2010-10-08 4 views
15

die folgende Zeichenfolge mit dem angegebenen "Hi ~+ and ^*. Is ^* still flying around ~+?"C++ mehrere Strings in einem String in einem einzigen Durchgang ersetzen

Ich möchte alle Vorkommen von "~+" und "^*" mit "Bobby" ersetzen und "Danny", so die Zeichenfolge wird:

"Hi Bobby and Danny. Is Danny still flying around Bobby?"

Ich möchte nicht Boost Replace-Funktion zweimal aufrufen, um das Auftreten der zwei verschiedenen Werte zu ersetzen.

+0

Woher kommt die Zeichenfolge? – JoshD

+0

Wie wir wissen, ist 'O (n) + O (n)' immer noch 'O (n)', was ist die * echte * Motivation hier? – Arun

+1

Die tatsächliche Zeichenfolge/Daten ist möglicherweise 100s von Gigabyte in der Größe, inkrementell verarbeitet, und während der Aufruf zweimal ersetzen ist immer noch O (n), das n ist ziemlich groß. –

Antwort

0

Boost string_algo hat eine replace_all-Funktion. Du könntest das benutzen.

+0

Danke Matthew, aber das braucht nur einen Wert um konvertiert zu werden und ich müsste es zweimal aufrufen. Ich versuche herauszufinden, es gibt eine Möglichkeit, im Wesentlichen eine Karte zu geben, wenn Sie x1 mit y1 und x2 mit y2 usw. ersetzen und der Scan über die Zeichenfolge nur einmal passiert. –

0

Ich empfehle die Verwendung der Boost Format Bibliothek. Anstatt ~+ und ^* verwenden Sie dann %1% und %2% und so weiter, ein bisschen systematischer.

Beispiel aus der Dokumentation.

cout << boost::format("writing %1%, x=%2% : %3%-th try") % "toto" % 40.23 % 50; 
    // prints "writing toto, x=40.230 : 50-th try" 

Prost & hth,

- Alf

+0

Danke für den Vorschlag Alf, aber ich habe keine Kontrolle über die Eingabedaten, so dass Ihr Vorschlag nicht funktioniert. Ich muss den Inhalt verarbeiten und die Werte ändern, wie vom Benutzer angegeben, der den Code aufruft. –

5

ich es geschafft, die benötigten Ersatzfunktion Boost.Iostreams zu implementieren. Bei der Methode, die ich verwendet habe, handelte es sich um einen Filterstrom, der reguläre Ausdrücke verwendet, um die zu ersetzenden Elemente abzugleichen. Ich bin mir nicht sicher über die Leistung von Gigabyte-Dateien. Sie müssen es natürlich testen. Wie auch immer, hier ist der Code:

#include <boost/regex.hpp> 
#include <boost/iostreams/filter/regex.hpp> 
#include <boost/iostreams/filtering_stream.hpp> 
#include <iostream> 

int main() 
{ 
    using namespace boost::iostreams; 

    regex_filter filter1(boost::regex("~\\+"), "Bobby"); 
    regex_filter filter2(boost::regex("\\^\\*"), "Danny"); 

    filtering_ostream out; 
    out.push(filter1); 
    out.push(filter2); 
    out.push(std::cout); 

    out << "Hi ~+ and ^*. Is ^* still flying around ~+?" << std::endl; 

    // for file conversion, use this line instead: 
    //out << std::cin.rdbuf(); 
} 

Die obige drucken "Hi Bobby and Danny. Is Danny still flying around Bobby?" wenn laufen, genau wie erwartet.

Es wäre interessant, die Leistungsergebnisse zu sehen, wenn Sie sich entscheiden, es zu messen.

Daniel

Edit: Ich habe erkannt, dass regex_filter Bedürfnisse den gesamten Zeichenfolge in den Speicher zu lesen, ist es ziemlich nutzlos für Gigabyte-Größe Eingaben zu machen. Oh well ...

0

Ich würde vorschlagen, mit std :: map. So haben Sie eine Reihe von Ersatz, so tun:

std::map<std::string,std::string> replace; 
replace["~+"]=Bobby; 
replace["^*"]=Danny; 

Dann Sie die Zeichenfolge in einen Vektor von Strings setzen könnten und prüfen, ob jede Zeichenfolge in der Karte auftritt, und wenn sie es nicht ersetzen, würden Sie müssen auch irgendwelche Interpunktionszeichen vom Ende entfernen. Oder füge diese zu den Ersatzteilen hinzu. Sie könnten es dann in einer Schleife tun. Ich bin mir nicht sicher, ob das wirklich effizienter oder nützlicher ist als Boost.

3

Ich habe bemerkt, dass es ein Jahr war, seit das aktiv war, aber für das, was es wert ist. I came across an article on CodeProject heute behauptet, dieses Problem zu lösen - vielleicht können Sie Ideen von dort verwenden:

Ich kann nicht für seine Richtigkeit bürgen, aber könnte einen Blick wert sein.:)

Die Implementierung erfordert sicherlich die gesamte Zeichenfolge im Speicher zu halten, aber Sie können problemlos umgehen (wie bei jeder anderen Implementierung, die die Ersetzungen durchführt), solange Sie die Eingabe in Blöcke teilen und garantieren können, dass Sie nie Split an einer Position, die innerhalb ein Symbol ist, das ersetzt werden soll. (Eine einfache Möglichkeit, dass in Ihrem Fall zu tun ist, in einer Position zu spalten, wo das nächste Zeichen ist keine der in einem Symbol verwendet Zeichen.)

-

Es gibt einen Grund, über die Leistung (obwohl das ein ausreichender Grund in meinem Buch ist), eine "ReplaceMultiple" -Methode zu seiner String-Bibliothek hinzuzufügen: Einfach die Ersetzungsoperation N mal zu tun, ist im Allgemeinen NICHT korrekt.

Wenn die Werte, die für die Symbole, substituiert sind, sind nicht eingeschränkt, Werte können als Symbole behandelt in nachfolgenden Operationen ersetzen, am Ende wird. (Es könnte Situationen geben, in denen Sie das wirklich wollen, aber es gibt definitiv Fälle, in denen Sie das nicht tun. Das Verwenden seltsam aussehender Symbole reduziert die Schwere des Problems, löst es aber nicht und "ist hässlich" weil die zu formatierenden Zeichenketten benutzerdefinierbar sein können - und daher keine exotischen Zeichen erfordern sollten.)

Ich vermute jedoch, dass es einen guten Grund gibt, warum ich eine allgemeine Multi-Replace-Implementierung nicht leicht finden kann. Eine Operation "ReplaceMultiple" ist im Allgemeinen nicht (offensichtlich) gut definiert.

Um dies zu sehen, überlegen, was es könnte bedeuten zu "ersetzen" aa 'mit'! ' und 'baa' mit '?' in der Zeichenfolge 'abaa' "? Ist das Ergebnis 'ab!' oder ein?' - Oder ist ein solcher Ersatz illegal?

Man könnte verlangen, dass Symbole "Präfix-frei" sind, aber in vielen Fällen wäre das inakzeptabel. Angenommen, ich möchte damit einen Vorlagentext formatieren. Und sagen meine Vorlage ist für Code. Ich möchte "§table" durch einen Datenbanktabellennamen ersetzen, der nur zur Laufzeit bekannt ist. Es wäre ärgerlich, wenn ich jetzt "§t" nicht in der gleichen Vorlage verwenden könnte. Das Vorlagen-Skript könnte etwas völlig Generisches sein, und siehe da, eines Tages begegne ich dem Client, der tatsächlich "§" in seinen Tabellennamen verwendet hat ... was meine Vorlagen-Bibliothek möglicherweise weniger nützlich macht.

Eine vielleicht bessere Lösung wäre die Verwendung eines Recursive-Descent-Parser anstelle von Literalen. :)

Verwandte Themen