17 Stimmen

Regulärer Ausdruck über mehrere Zeilen

Ich stecke nun schon seit mehreren Stunden damit fest und habe eine Fülle von verschiedenen Tools ausprobiert, um die Aufgabe zu erledigen. Ohne Erfolg. Es wäre fantastisch, wenn mir jemand bei diesem Problem helfen könnte.

Hier liegt das Problem:

Ich habe eine sehr große CSV-Datei (400 MB+), die nicht korrekt formatiert ist. Im Moment sieht sie etwa so aus:

This is a long abstract describing something. What follows is the tile for this sentence."   
,Title1  
This is another sentence that is running on one line. On the next line you can find the title.   
,Title2

Wie Sie wahrscheinlich sehen können, müssten die Titel ",Titel1" und ",Titel2" eigentlich in der gleichen Zeile wie der vorstehende Satz stehen. Dann würde es etwa so aussehen:

This is a long abstract describing something. What follows is the tile for this sentence.",Title1  
This is another sentence that is running on one line. On the next line you can find the title.,Title2

Bitte beachten Sie, dass das Ende des Satzes Anführungszeichen enthalten kann oder nicht. Am Ende sollten auch sie ersetzt werden.

Hier ist, was ich bis jetzt gefunden habe:

sed -n '1h;1!H;${;g;s/\."?.*,//g;p;}' out.csv > out1.csv

Dies sollte eigentlich die Aufgabe erfüllen, den Ausdruck über mehrere Zeilen hinweg abzugleichen. Leider tut es das nicht :)

Der Ausdruck sucht nach dem Punkt am Ende des Satzes und den optionalen Anführungszeichen plus einem Zeilenumbruchzeichen, das ich mit .* abzugleichen versuche.

Hilfe sehr erwünscht. Dabei spielt es keine Rolle, mit welchem Tool die Aufgabe erledigt wird (awk, perl, sed, tr, etc.).

20voto

SiegeX Punkte 127640

Mehrzeilig in sed ist an sich nicht unbedingt kompliziert, es verwendet nur Befehle, mit denen die meisten Leute nicht vertraut sind, und hat bestimmte Nebeneffekte, wie z. B. die Abtrennung der aktuellen Zeile von der nächsten Zeile durch ein ' \n ', wenn Sie 'N' verwenden, um die nächste Zeile an den Musterbereich anzuhängen.

Wie auch immer, es ist viel einfacher, wenn Sie eine Zeile finden, die mit einem Komma beginnt, um zu entscheiden, ob der Zeilenumbruch entfernt werden soll oder nicht, also habe ich das hier getan:

sed 'N;/\n,/s/"\? *\n//;P;D' title_csv

Eingabe

$ cat title_csv
don't touch this line
don't touch this line either
This is a long abstract describing something. What follows is the tile for this sentence."
,Title1
seriously, don't touch this line
This is another sentence that is running on one line. On the next line you can find the title.
,Title2
also, don't touch this line

Ausgabe

$ sed 'N;/\n,/s/"\? *\n//;P;D' title_csv
don't touch this line
don't touch this line either
This is a long abstract describing something. What follows is the tile for this sentence.,Title1
seriously, don't touch this line
This is another sentence that is running on one line. On the next line you can find the title.,Title2
also, don't touch this line

14voto

Dennis Williamson Punkte 322329

Ihre funktioniert mit ein paar kleinen Änderungen:

sed -n '1h;1!H;${;g;s/\."\?\n,//g;p;}' inputfile

El ? muss entkommen werden und . passt nicht zu Zeilenumbrüchen.

Es gibt noch eine andere Möglichkeit, bei der der Laderaum nicht benutzt werden muss:

sed -n '${p;q};N;/\n,/{s/"\?\n//p;b};P;D' inputfile

Hier ist eine kommentierte Version:

sed -n '
$          # for the last input line
{
  p;             # print
  q              # and quit
};
N;         # otherwise, append the next line
/\n,/      # if it starts with a comma
{
  s/"\?\n//p;    # delete an optional comma and the newline and print the result
  b              # branch to the end to read the next line
};
P;         # it doesn't start with a comma so print it
D          # delete the first line of the pair (it's just been printed) and loop to the top
' inputfile

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X