Frage Der schnellste Weg, um viele Strings durchzuführen, ersetzt in Java


Ich muss einen Parser schreiben, der einen String erhält und bestimmte Zeichensätze durch andere ersetzt. Der Code sieht so aus:

noHTMLString = noHTMLString.replaceAll("</p>", "\n");
noHTMLString = noHTMLString.replaceAll("<br/>", "\n\n");
noHTMLString = noHTMLString.replaceAll("<br />", "\n\n");
//here goes A LOT of lines like these ones

Die Funktion ist sehr lang und führt eine Vielzahl von Strings durch. Das Problem hier ist, dass es viel Zeit braucht, da die Methode oft aufgerufen wird und die Anwendungsleistung verlangsamt.

Ich habe einige Threads hier über die Verwendung von StringBuilder als eine Alternative gelesen, aber es fehlt die ReplaceAll-Methode und wie hier angegeben Unterliegt die String.ReplaceAll () - Performance der String-Unveränderlichkeit? Die Methode replaceAll in der String-Klasse arbeitet mit

Match Pattern & Matcher und Matcher.replaceAll () verwenden einen StringBuilder, um den eventuell zurückgegebenen Wert zu speichern   Ich weiß also nicht, ob der Wechsel zu StringBuilder die Zeit für die Ersetzungen wirklich verkürzt.

Kennst du einen schnellen Weg, um eine Menge von String schnell zu ersetzen? Hast du einen Rat für dieses Problem?

Vielen Dank.

BEARBEITEN: Ich muss einen Bericht erstellen, der ein paar Felder mit HTML-Text enthält. Für jede Zeile rufe ich die Methode auf, die alle HTML-Tags und Sonderzeichen in diesen Strings ersetzt. Mit einem vollständigen Bericht dauert es mehr als 3 Minuten, um den gesamten Text zu parsen. Das Problem ist, dass ich die Methode sehr oft aufrufen muss


11
2017-11-26 11:56


Ursprung


Antworten:


Ich fand, dass org.apache.commons.lang.StringUtils am schnellsten ist, wenn Sie sich nicht mit dem StringBuffer beschäftigen wollen.

Du kannst es so benutzen:
noHTMLString = StringUtils.replace(noHTMLString, "</p>", "\n");

Ich habe Leistungstests durchgeführt, es war fussiger als meine eigene StrinBuffer-Lösung, die der von @extraneon vorgeschlagenen ähnlich ist.


12
2017-11-27 00:13



Es sieht so aus, als ob du HTML dort parsierst Bibliothek von Drittanbietern anstatt das Rad neu zu erfinden?


6
2017-11-26 12:00



Ich stimme Martijn darin zu, eine vorgefertigte Lösung zu verwenden, anstatt sie selbst zu analysieren - im javax.xml-Paket sind viele Dinge in Java integriert. Eine saubere Lösung wäre, XSLT-Transformation zu ersetzen, das sieht nach einem idealen Anwendungsfall dafür aus. Es ist jedoch kompliziert.

Um die Frage zu beantworten, haben Sie in Betracht gezogen, die Bibliotheken für reguläre Ausdrücke? Es sieht so aus, als hätten Sie viele verschiedene Dinge, die Sie abgleichen möchten, und ersetzen Sie sie durch dasselbe (\ n oder eine leere Zeichenfolge). Mit regulären Ausdrücken können Sie ein Ausdruck wie sein "<br>|<br/>|<br />" oder noch schlauer <br.*?>" um ein Matcher-Objekt zu erstellen, auf dem Sie replaceAll aufrufen können.


4
2017-11-26 12:25



Ich stimme Martijn hier voll und ganz zu. Wählen Sie das richtige Werkzeug für den Job.

Wenn Ihre Datei jedoch nicht HTML ist, sondern nur einige HTML-Token enthält, gibt es einige Möglichkeiten, wie Sie die Dinge beschleunigen können.

Wenn ein Teil der Eingabe keine ersetzbaren Elemente enthält, sollten Sie zunächst mit etwas beginnen, das wie folgt aussieht:

if (!input.contains('<')) {
    return input;
}

Zweitens, betrachte eine Regex:

Pattern p = Pattern.compile( your_regex );

Erstellen Sie kein Muster für jede einzelne replaceAll-Zeile, sondern versuchen Sie, sie zu kombinieren (Regex hat einen OR-Operator) und lassen Sie Pattern die Regex optimieren. Benutze die kompiliert Muster und kompilieren Sie es nicht bei jedem Anruf, es ist ziemlich teuer.

Wenn Regexes etwas zu komplex sind, können Sie auch eine schnellere (aber möglicherweise weniger lesbare) Ersatz-Engine implementieren:

StringBuilder result = new StringBuilder(input.length();
for (int i=0; i < input.length(); i++) {
  char c = input.charAt(i);

  if ( c != '<' ) {
    continue;
  }

  int closePos = input.indexOf( '>', i);
  if (closePos == -1) {// not found
    result.append( input.substring(i, input.length());
    return result.toString();
  }
  i = closePos;
  String token = input.substring(i, closePos);
  if ( token.equals( "p/" ) {
    result.append("\\n");
  } else if (token.equals(...)) {
  } else if (...) {
  } 
}
return result.toString();

Dies kann einige Fehler haben :)

Der Vorteil ist, dass Sie die Eingabe nur einmal durchlaufen müssen. Der große Nachteil ist, dass es nicht so einfach zu verstehen ist. Sie könnten auch eine Zustandsmaschine schreiben, die pro Charakter analysiert, was der neue Zustand sein sollte, und das wäre wahrscheinlich schneller und noch mehr Arbeit.


3
2017-11-26 12:26