Javascript - Entfernen von wiederholenden Phrasen in String?

3 Antworten

Was ist, wenn es keine Leerzeichen oder andere Trennzeichen gibt. Performance ist zweitrangig

Ich würde das mit filter() lösen:

const result = str.split(" ")
  .filter((word, i, arr) => arr[i-1] !== word)
  .join(" ");

Neue Lösung, da Wörter nicht unbedingt durch Leerzeichen getrennt sein müssen:

let str = `Emojibombe PogchampPogchampPogchampPogchamp LiEmoji LiEmoji LiEmoji Eine Nachricht dazwischen Pogchamp Pogchamp Pogchamp Pogcham LiEmoji LiEmoji LiEmoji`;

str =  str.split(/\s+/g).filter((word, i, words) => words[i-1] !== word).join(" ");

for (let wl = Math.min(20, Math.floor(str.length/2)); wl > 1; wl--) { // word length
  let wordFoundAt = [];
  for (let i = wl; i <= str.length - wl; i++) {
    const word = str.substring(i,i+wl);
    if (word.includes(" ")) continue;
    const lastWord = str.substring(i-wl, i);
    if (lastWord === word) {
      for(let j = i; j < i+wl; j++) {
        wordFoundAt.push(j);
      }
    }
  }
  str = str.split("").filter((_,i) => !wordFoundAt.includes(i)).join("");
}

console.log(str);
Woher ich das weiß:Hobby – Programmieren ist mein Hobby & Beruf
EvilMind 
Fragesteller
 15.11.2022, 21:20

Idee gut. Nutzen leider ... weniger :/

Grund: Es können auch solche Abfolgen auftauchen:

var str = `Emojibombe PogchampPogchampPogchampPogcham LiEmoji LiEmoji LiEmoji Eine Nachricht dazwischen Pogchamp Pogchamp Pogchamp Pogcham LiEmoji LiEmoji LiEmoji`;

Wie würde ich daraus am effektivsten die Dinge erkennen, welche sich mindestens 2 mal in folge wiederholen. Also (Beispiel) ProPro oder KartKartKartKart oder Tom Tom Tom ... usw.

Vorzugsweise mit einer Referenz auf das Wort, welches sich da wiederholt, damit man es halt kürzen bzw. ersezten könnte.

0
MrAmazing2  15.11.2022, 21:41
@EvilMind

Und die "Wörter" welche sich wiederholen beginnen wirklich immer mit nem Großbuchstaben?

Oder hast du das nur groß geschrieben damit man's besser erkennt und es könnte auch "Emojibombe pogchamppogchamppogchamppogchamp LiEmoji" sein?

Falls letzteres, Stammen die Wörter wenigstens aus einem Wort-Pool (also sind das bestimmte Wörter, von denen du am besten auch eine Liste hast) oder soll das für alle Wörter gelten? Aber ein normales Wort wie "Benennen" würde dann zu "Benen" geküzt werden...

0
MrAmazing2  15.11.2022, 22:20
@EvilMind

Erstmal alle doppelten Wörter mit Leerzeichen dazwischen entfernen, die Leerzeichen machen sonst später Probleme. Dafür habe ich ja bereits eine Lösung genannt.

Und dann alle Wörter entfernen die direkt nacheinander stehen sind. Ich bin davon ausgegangen dass so ein Wort maximal 20 Zeichen lang ist, kann man aber beliebig höher machen die word length:

str =  str.split(/\s+/g).filter((word, i, words) => words[i-1] !== word).join(" ");

for (let wl = 20; wl > 1; wl--) { // word length
  let wordFoundAt = [];
  for (let i = wl; i <= str.length - wl; i++) {
    const word = str.substring(i,i+wl);
    if (word.includes(" ")) continue;
    const lastWord = str.substring(i-wl, i);
    if (str.substring(i-wl, i) === str.substring(i,i+wl)) {
      console.log(str.substring(i-wl, i), str.substring(i,i+wl));
      for(let j = i; j < i+wl; j++) {
        wordFoundAt.push(j);
      }
    }
  }
  str = str.split("").filter((_,i) => !wordFoundAt.includes(i)).join("");
}

console.log(str);
0
MrAmazing2  15.11.2022, 22:23
@MrAmazing2

Ups der console.log in der Mitte kann natürlich raus, war nur fürs Debuggen.

Hier nochmal verbessert:

let str = `Emojibombe PogchampPogchampPogchampPogchamp LiEmoji LiEmoji LiEmoji Eine Nachricht dazwischen Pogchamp Pogchamp Pogchamp Pogcham LiEmoji LiEmoji LiEmoji`;

str =  str.split(/\s+/g).filter((word, i, words) => words[i-1] !== word).join(" ");

for (let wl = Math.min(20, str.length/2); wl > 1; wl--) { // word length
  let wordFoundAt = [];
  for (let i = wl; i <= str.length - wl; i++) {
    const word = str.substring(i,i+wl);
    if (word.includes(" ")) continue;
    const lastWord = str.substring(i-wl, i);
    if (lastWord === word) {
      for(let j = i; j < i+wl; j++) {
        wordFoundAt.push(j);
      }
    }
  }
  str = str.split("").filter((_,i) => !wordFoundAt.includes(i)).join("");
}

console.log(str);
1
EvilMind 
Fragesteller
 15.11.2022, 23:26
@MrAmazing2

Die wörter entsprechen nicht den regulären wörtern. Ich möchte wiederholende Phrasen innerhalb eines Textes ermitteln. Dabei wär eine Abtrennung von Wörtern mit MINDESTENS 4 zeichen bis maximal 15 ideal. Dazu wäre es nicht schlimm, wenn der entstehende Text "zusammenklebende" wörter erzeugt. Ich habe hier mal einen Test geschrieben:

function parseInput(t)
{
  var r = t;
  var beginPos = 0;
  var minLength = 4;
  var maxLength = 15;
  while(beginPos < r.length - minLength)
  {
    var searchFor = [];
    var currentMaxLength = Math.min(maxLength, r.length - beginPos - minLength);
    for(var offsetLength = minLength; offsetLength <= currentMaxLength;offsetLength++)
    {
      var preText = r.substr(0, beginPos + offsetLength);
      var phrs = r.substr(beginPos, offsetLength);
      var parts = [];
      for(var tmpOffset = phrs.length + beginPos;tmpOffset < r.length;tmpOffset += phrs.length)
      {
        var off = r.substr(tmpOffset, phrs.length);
        if(off == "") break;
        parts.push(off);
      }
      if(parts.indexOf(phrs, 1) == 1)
      {
        var outp = "";
        for(var n = 1;n < parts.length;n++)
        {
          if(parts[n] != phrs)
          {
            outp += parts[n];
          }
        }
        r = preText + outp;
      }
    }
    beginPos += 1;
  }
  if(t == r)
  {
    return(r);
  }
  else
  {
    return(parseInput(r));
  }
}

Testergebnisse:

var currentPhrase = `Ich glaube, damit habe ich das Problem ja gelöst. Rekursiv ist die ganze Sache sache sache sache sache auch noch PogoChampPogoChampPogoChampPogoChamp Und Und Und und und und UndUndUnd Es kommt auch mit komplexen Dingern klar`;

var result = parseInput(currentPhrase);
// Ich glaube, damit habe ich das Problem ja gelöst. Rekursiv ist die ganze Sache sache auch noch PogoChamp Und undUndUnd Es kommt auch mit komplexen Dingern klar

Hierbei sucht er alles, was mindestens 3 mal in Folge auftaucht und enfernt es dann daraus.

Und ja. Das ganze kann mit 100%iger Wahrscheinlichkeit noch stark optimiert werden.

0
EvilMind 
Fragesteller
 15.11.2022, 23:31
@MrAmazing2

Spitzenklasse. O_O Ist definitiv effektiver und besser als mein Ansatz. Hab auch meinen Text mal durchgejagt und er macht exakt das, was er soll. VIELEN dank. :)

1
MrAmazing2  16.11.2022, 00:07
@EvilMind

Gerne, war ein schönes Rätsel wie man das am besten löst! ^^

Die for-Schleife kannst übrigens du zu

for (let wl = Math.min(15, str.length/2); wl > 3; wl--) { // word length

ändern, dann geht es alle Wortlängen von 4-15 durch.

Um nur Wörter zu entfernen die dreimal in Folge sind muss man es noch etwas abändern, aber das schaffst du :D

Aber das hast du wahrscheinlich eh bereits rausgefunden. :D

0
Von Experte MrAmazing2 bestätigt

Den String kannst du zunächst anhand des Leerzeichens aufsplitten. Dann iterierst du über das resultierende Array und kopierst dabei jeden Eintrag hinüber in ein anderes Array. Wenn dabei das aktuelle Element dem letzten Element des neuen Arrays entspricht (sofern dieses überhaupt schon einen Eintrag hat), überspringst du dieses.

EvilMind 
Fragesteller
 15.11.2022, 21:20

Leerzeichen sind nicht immer dabei

0