web-dev-qa-db-ja.com

複数行にわたる正規表現

私はこれで数時間こだわっていて、仕事を完了するためにさまざまなツールを繰り返し使用しました。成功なし。誰かがこれを手伝ってくれるとしたら、それは素晴らしいことです。

ここに問題があります:

正しくフォーマットされていない非常に大きなCSVファイル(400mb +)があります。現時点では、次のようになっています。

これは何かを説明する長い要約です。次に続くのは、この文のタイルです。 "
、Title1 
これは、1行で実行されている別の文です。次の行にタイトルがあります。
、Title2

タイトル「、Title1」と「、Title2」は、実際には前述の文と同じ行にあるはずです。その後、次のようになります。

これは何かを説明する長い要約です。この文のタイルは次のとおりです。 "、Title1 
これは1行で実行されている別の文です。次の行にタイトルが表示されます。、Title2

文の終わりに引用符が含まれる場合と含まれない場合があることに注意してください。最終的には、それらも交換する必要があります。

これが私がこれまでに思いついたものです:

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

これにより、実際には複数行にわたる式のマッチングが行われます。残念ながらそれはしません:)

式は、文の終わりにあるドットと、オプションの引用符、および。*と一致させようとしている改行文字を探しています。

どうぞよろしくお願いいたします。また、どのツール(awk、Perl、sed、trなど)を実行するかは問題ではありません。

16
herrherr

sed内の複数行は、それ自体が必ずしもトリッキーであるとは限りません。それは、ほとんどの人が慣れていないコマンドを使用し、現在の行を「\ n」で次の行から区切るなどの特定の副作用があるというだけです。 「N」を使用してパターンスペースに次の行を追加する場合。

とにかく、コンマで始まる行で一致させて改行を削除するかどうかを決定する方がはるかに簡単なので、それをここで行いました。

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

入力

$ 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

出力

$ 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
18
SiegeX

あなたはいくつかの小さな変更で動作します:

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

?はエスケープする必要があり、.は改行に一致しません。

ホールドスペースを使用する必要のない別の方法を次に示します。

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

コメント付きのバージョンは次のとおりです。

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
13