Finde Ziffern in Dateinamen und referenziere sie mit anderen

9

Zunächst werde ich kurz meine Motivation für dieses und das eigentliche Problem beschreiben:
Ich beschäftige mich ständig mit großen Stapeln von Dateien, und ich finde, dass ich sie nach der folgenden Regel umbenennen muss:
Sie können alle Wörter und Ziffern enthalten, aber nur eine Zifferngruppe wird erhöht und nicht "konstant". Ich muss diese und nur diese Ziffern extrahieren und die Dateien entsprechend umbenennen. Zum Beispiel:

%Vor%

Wird umbenannt:

%Vor%

Wir beginnen also mit einem Vektor mit std::wstring -Objekten für alle Dateinamen im angegebenen Verzeichnis. Ich fordere Sie auf, 3 Minuten lang mit dem Lesen aufzuhören und darüber nachzudenken, wie Sie das angehen können, bevor ich mit meinen Versuchen und Fragen fortfahre. Ich möchte nicht, dass meine Ideen dich in die eine oder andere Richtung schubsen und ich habe immer neue Ideen für die besten gefunden.

Nun, hier sind zwei Möglichkeiten, die ich mir vorstellen kann:

1) C-String-Manipulation und Vergleiche im alten Stil:
In meinen Augen bedeutet dies, jeden Dateinamen zu analysieren und sich die Position und Länge jeder Ziffernfolge zu merken. Dies wird leicht in einem Vektor oder was nicht für jede Datei gespeichert. Dies funktioniert gut (verwendet im Prinzip String-Suchen mit zunehmenden Offsets):

%Vor%

Was ich danach habe, ist ein Vektor aus (Location, Size) -Paaren für alle Ziffern im Dateinamen, Konstante (unter Verwendung der Definition in der Motivation) oder nicht.
Danach folgt Chaos, da Sie die Zeichenfolgen durch Querverweise vergleichen müssen, um herauszufinden, welche Ziffern zu extrahieren sind. Dies wird exponentiell mit der Anzahl der Dateien (die tendenziell sehr groß ist) wachsen, die nicht erwähnt werden, multipliziert mit der Anzahl der Ziffernfolgen in jeder Zeichenkette. Auch nicht sehr lesbar, wartbar oder elegant. Nicht gehen.

2) Reguläre Ausdrücke

Wenn es jemals einen Regex gab, ist es das. Erstellen Sie ein Regex-Objekt aus dem ersten Dateinamen und versuchen Sie, es mit dem, was als nächstes kommt, zu vergleichen. Erfolg? Sofortige Fähigkeit, die erforderliche Anzahl zu extrahieren. Fehler? Fügen Sie den fehlerhaften Dateinamen als neues Regex-Objekt hinzu und versuchen Sie, die Übereinstimmung mit den beiden vorhandenen regulären Ausdrücken herzustellen. Spülen und wiederholen. Die Regex würden in etwa so aussehen:

%Vor%

oder erstellen Sie eine Regex für jede Ziffernfolge separat:

%Vor%

Der Rest ist Kuchen. Pass einfach weiter auf, und im besten Fall braucht es vielleicht nur einen Pass! Frage ist ...

Was ich wissen muss:

1) Können Sie sich einen anderen überlegenen Weg vorstellen, dies zu erreichen? Ich habe meinen Kopf seit Tagen gegen die Wand geschlagen 2) Obwohl die Kosten der Zeichenfolgenmanipulation und des Konstruierens / Zerstörens von Vektoren bei der ersten Methode erheblich sein können, verblasst sie vielleicht im Vergleich zu den Kosten von Regex-Objekten. Zweite Methode, Worst Case: So viele Regex-Objekte wie Dateien. Wäre das mit möglicherweise Tausenden Akten katastrophal? 3) Die zweite Methode kann für eine von zwei Möglichkeiten angepasst werden: Wenige std::regex Objektkonstruktionen, viele regex_match Aufrufe oder umgekehrt. Was ist teurer, die Konstruktion des Regex-Objekts oder versuchen, einen String damit zu vergleichen?

    
Mark 05.06.2015, 17:36
quelle

2 Antworten

2

Für mich (Gcc4.6.2 32-Bit-Optimierungen O3) war die manuelle String-Manipulation etwa 2x schneller als reguläre Ausdrücke. Nicht die Kosten wert.

Beispiel runnable complete code (Verknüpfung mit boost_system und boost_regex, oder include include, wenn Sie bereits im Compiler regex haben):

%Vor%

Es produziert Ausgabe für mich:

%Vor%

Ich denke auch, dass es völlig sinnlos ist, weil der tatsächliche I / O (Dateiname, Umbenennungsdatei) in Ihrem Beispiel viel langsamer ist als jede CPU-String-Manipulation. Also, um deine Fragen zu beantworten:

  1. Ich sehe keinen besseren Weg, I / O ist was langsam ist, nicht mit Überlegenheit belästigen
  2. Regex-Objekt war meiner Erfahrung nach nicht teuer, im Vergleich zu manueller Methode mit zweifacher Verlangsamung ist das eine konstante Verlangsamung und vernachlässigbar, verglichen mit der Menge an Arbeit, die es speichert
  3. Wie viele std :: regex-Objekte für wie viele Regex_match-Aufrufe? Hängt von der Anzahl der regex_match-Aufrufe ab: Je mehr Übereinstimmungen es gibt, desto mehr lohnt es sich, ein bestimmtes std :: regex-Objekt zu erstellen. Dies wird jedoch sehr Bibliothek-abhängig sein. Wenn es viele Match-Aufrufe gibt, erstellen Sie getrennt, wenn Sie nicht sicher sind, nicht stören.
peenut 05.06.2015, 19:57
quelle
1

Warum verwenden Sie nicht die Teilung, um die Zeichenfolge zwischen Buchstaben und Zahlen aufzuteilen:

%Vor%

dann erhalten Sie den Index, den Sie für die Zahlen benötigen, vielleicht mit einer Where-Klausel, um diejenigen zu finden, die an Wert zunehmen, während die anderen Indizes übereinstimmen, dann können Sie .Last () verwenden, um die Erweiterung zu erhalten.

    
maksymiuk 07.06.2015 15:11
quelle

Tags und Links