Sedでキャプチャグループを繰り返す

Sedでキャプチャグループを繰り返す

次のスキーマがあります。

#ABC: (0),(0-11,22),(A7E2BB0F38DF),(42),(1A0290800D7),(7042),(81A0290800D7),(7442)

sedを使って次の結果を得たいと思います。

0 0-11,22 A7E2BB0F38DF 42 1A0290800D7 7042 81A0290800D7 7442

以下はbashで動作します:

result="#ABC: (0),(0-11,22),(A7E2BB0F38DF),(42),(1A0290800D7),(7042),(81A0290800D7),(7442)"
sed -n 's/.*(\(.*\)),(\(.*\)),(\(.*\)),(\(.*\)),(\(.*\)),(\(.*\)),(\(.*\)),(\(.*\))/\1 \2 \3 \4 \5 \6 \7 \8/p' <<< "$result"
0 0-11,22 A7E2BB0F38DF 42 1A0290800D7 7042 81A0290800D7 7442

今、このsed式をどのように最適化しますか?重複キャプチャグループを削除する方法は?

答え1

大丈夫ですか?

% sed -Ee 's/[^(]*\(([^)]*)\)/\1 /g' < input.txt
0 0-11,22 A7E2BB0F38DF 42 1A0290800D7 7042 81A0290800D7 7442 

つまり、最初の開かれた括弧()[^(]*\(の前のすべての項目と一致([^)]*)し、閉じる括弧()以外のすべての項目をキャプチャし、閉じる括弧と一致し、バッチをキャプチャされた部分()に置き換え、残りの\1文字列(/g)。

またはPerlでは:

% perl -ne 'print "$1 " while(/\((.*?)\)/g); print "\n"' < input.txt
0 0-11,22 A7E2BB0F38DF 42 1A0290800D7 7042 81A0290800D7 7442 

答え2

質問に示されている元の入力が、一部の構造化文書形式(YAMLやJSONなど)の大きな文書の一部ではないとします。もしそうなら、ここや他の答えに示されているものよりもこれを達成するより良い方法があるかもしれません。


これにより、指定した方法と反対の方法で目的のタスクが達成されます。角かっこ内の内容を一致させて保持するのではなく、最初の項目(とその前のすべての項目、最後の項目)とその後のすべての項目を削除してから、部分文字列),(の各インスタンスを空白に置き換えます。

$ sed -e 's/[^(]*(//' -e 's/)[^)]*$//' -e 's/),(/ /g' file
0 0-11,22 A7E2BB0F38DF 42 1A0290800D7 7042 81A0290800D7 7442

または、スペースを最初に使用して、大括弧と),(括弧をあまり使用せずに他の代替項目を書き換えることができます(入力の外部括弧に括弧で囲まれた部分文字列が含まれていないと仮定)。

$ sed -e 's/),(/ /g' -e 's/.*(//' -e 's/).*//' file
0 0-11,22 A7E2BB0F38DF 42 1A0290800D7 7042 81A0290800D7 7442

残りは角かっこしかない部分文字列です(スペースで区切られています)。


まったく異なるアプローチは、最初の前のテキストを削除し(てから、(各合計を二重引用符に変換して、)入力を適切に引用されたCSVに変換することです。それから私達はcsvformat次に利用できるcsvkitデフォルトのフィールド区切り文字を空白に変更します。

$ sed -e 's/[^(]*(/(/' -e 'y/()/""/' file | csvformat -D ' '
0 0-11,22 A7E2BB0F38DF 42 1A0290800D7 7042 81A0290800D7 7442

関連情報