Regex vom Teilstring bis zum ersten Auftreten eines anderen Teilstrings

801
Robert Koszegi

Ich muss die textClipping-Dateien aus einer Liste entfernen. Leider wurden einige Dateien furchtbar benannt und enthalten einen Wagenrücklauf. Ich brauche den Perl-Regex, damit jeder Pfad von /Volumes/bis .textClippingeinschließlich Newline passt.

/Volumes/.*\.textClippingerfasst die ersten beiden .textClippingDateien, nicht jedoch die dritte mit dem Zeilenumbruch. Alternativ konnte ich alles vom ersten /Volumes/bis zum letzten Moment erfassen, was .textClippingaber auch nicht hilfreich ist.

Irgendwelche Ideen? Vielen Dank.

/Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/fi   le.textClipping /Volumes/folder/folder/file.doc 
0

3 Antworten auf die Frage

0
FosseWay

Ich konnte Ihrer Frage nicht sagen, wo in den Dateinamen die Zeilenumbrüche stehen könnten, also gehe ich davon aus, dass sie irgendwo sein könnten. Dies macht das Matching schwieriger.

Die einfachste Lösung besteht darin, alle Zeilenumbrüche aus der Eingabe zu entfernen, bevor unerwünschte Dateinamen entfernt werden.

Ich habe dieses Skript gemacht:

#!/usr/bin/perl  $filename = "filelist.txt";  open(FILE, $filename) or die "Cant open $filename\n";   # Undefine the record separator, so that the entire file will be read into a single string # instead of an array with records separated by newlines local $/ = undef;  $lines = <FILE>;  close(FILE);  print "Before\n------\n";  print $lines;   # Remove all newlines  $lines =~ s/\n+//g;  # Remove all "textClipping" files $lines =~ s/\/Volumes\/[^ ]*.textClipping//g;  # Turn multiple consecutive spaces into single spaces $lines =~ s/ +/ /g;   print "After\n-----\n";  print "$lines\n";  

und fütterte es als filelist.txt:

/Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/fi le.textClipping /Volumes/folder/folder/file.doc 

was gab diese Ausgabe:

Before ------ /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/fi le.textClipping /Volumes/folder/folder/file.doc After ----- /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.doc 

Zum Schluss denke ich, dass Sie mit dem Muster, das Sie in Ihrer Frage vorschlagen, sehr vorsichtig sein sollten:

/Volumes/.*.textClipping 

schon seit . erfasst jedes Zeichen außer einem Zeilenumbruch, jedoch auch ein Leerzeichen. Ich habe dieses Muster mit dieser Eingabe ausgeführt, wie von Ihrer Frage vorgeschlagen:

/Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/fi le.textClipping /Volumes/folder/folder/file.doc 

und bekam diese Ausgabe, von der ich glaube, dass sie nicht das ist, was Sie wollen:

/Volumes/folder/folder/fi le.textClipping /Volumes/folder/folder/file.doc 

Bearbeiten : Sie haben kürzlich eine Antwort auf Ihre eigene Frage gepostet, in der Sie erneut in diese Falle geraten, aber ich habe nicht genug Ansehen, um einen Kommentar dazu zu posten. Anstelle von /Volumes/.*\n*.textClipping/g(die mit Leerzeichen übereinstimmt und daher möglicherweise mehr als ein Dateiname gleichzeitig entfernt wird), empfehle ich dringend, Folgendes zu berücksichtigen /Volumes/[^ ]*\n*.textClipping/g: das [^ ]*wird alles außer Leerzeichen entsprechen.

0
Toto

Du könntest es tun:

perl -0777 -ae '@files = m~(/Volumes/(?:[^/\r\n]+/)+?[^/]+?\.textClipping\R)~g;print scalar(@files)," files found:\n",@files' file.txt 

Woher:

  • -0777 Lesen Sie die Datei im "slurp" -Modus
  • -a Autosplit-Modus

Regex:

 ~ : regex delimiter ( : start group 1 /Volumes/ : literally  (?: : start non capture group [^/\r\n]+ : 1 or more any character that is not a slash or line break / : slash )+? : group repeated 1 or more times, not greedy (ie. the path) [^/]+? : not a slash, 1 or more times, not greedy (ie. the filename) \.textClipping : a dot with the extension \R : any kind of linebreak ) : end group 1 ~g : regex delimiter, global flag 

Ausgabe:

3 files found: /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/fi  le.textClipping 

Wenn Sie alle Dateien behalten möchten, die nicht mit enden .textClipping

perl -0777 -i.orig -ape 's~(/Volumes/(?:[^/\r\n]+/)+?[^/]+?\.textClipping\R)~~g' file.txt 

Die Eingabedatei -iwird direkt geändert (Option ), die Originaldatei wird mit der Erweiterung gesichert.orig

cat file.txt /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.doc 
0
Robert Koszegi

Ich schätze die Antworten sehr. Vielen Dank für Ihre Zeit. Ich entschuldige mich, wenn meine Frage nicht klar war. Die Antwort stellte sich als einfacher heraus, als ich zunächst dachte.

Der Wagenrücklauf oder die neue Zeile im Dateinamen lautet wie folgt: "file (CR) name.textClipping". Textclipping-Dateien geben einfach den darin enthaltenen Text als Namen der Datei an, was in meinem Fall ein paar Zeilenumbrüche ist. Schmerz in den Arsch!

Das funktioniert trotzdem : /Volumes/.*\n*.textClipping/g

Dies entspricht Vorkommensfolgen, die mit "/ Volumes /" beginnen und mit ".textClipping" enden, wobei alles dazwischen steht.

Nochmals vielen Dank für Ihre Vorschläge.

Bist du sicher, dass das funktioniert, wie du willst? Auf gegebene Beispieldatei anwenden, gibt es für die zweite Übereinstimmung 2 Dateien (Zeile 3 mit Zeile 4 verketten). Toto vor 7 Jahren 0