4 列の CSV ファイルがあります。例:
0001 @ fish @ animal @ eats worms
以前はファイルに対して検索と置換を行っていsed
ましたが、この検索と置換を列 3 内にあるテキストのみに制限する必要があります。
この 1 つの列でのみ検索と置換を行うにはどうすればよいですか?
本当に を使用しsed
ますか? どうcsvfix
ですか?あなたのCSVは、引用符や埋め込まれたコンマ、または正規表現を作成するその他の厄介なものがなく、素晴らしくシンプルですか...一般的なCSVファイルを処理する方法として満足のいくものではありませんか? @
は、フォーマットの「コンマ」であると想定しています。
awk
の代わりに使用することを検討してくださいsed
:
awk -F@ '$3 ~ /pattern/ { OFS= "@"; $3 = "replace"; }'
おそらく、OFS を 1 回設定する BEGIN ブロックが必要です。1 行の入力では、何のオッズもありませんでした (そして、100 万行の入力の違いを測定するのもおそらく難しいでしょう):
$ echo "pattern @ pattern @ pattern @ pattern" |
> awk -F@ '$3 ~ /pattern/ { OFS= "@"; $3 = "replace"; }'
pattern @ pattern @replace@ pattern
$
sed
それでも魅力的だと思われる場合は、次のようにします。
sed '/^\([^@]*@[^@]*\)@pattern@\(.*\)/ s//\1@replace@\2/'
例 (入力と出力がわずかに異なることに注意してください。必要に応じて、awk
非常に簡単に同じように処理するように修正できます):
$ echo "pattern@pattern@pattern@pattern" |
> sed '/^\([^@]*@[^@]*\)@pattern@\(.*\)/ s//\1@replace@\2/'
pattern@pattern@replace@pattern
$
最初の正規表現は、行頭、非アットマークのフィールド、アットマーク、非アットマークの別のフィールドを探し、ロットを記憶します。アットマーク、パターン (最初の 2 つのフィールドは既に一致しているため、パターンは 3 番目のフィールドにある必要があります)、別のアットマーク、そして行の残りを探します。行が一致すると、その行が最初の 2 つのフィールド (必要に応じて変更なし) に置き換えられ、次に、置換された 3 番目のフィールドと行の残り (必要に応じて変更されない) が追加されます。
3 番目のフィールドを単純に置き換えるのではなく、編集する必要がある場合は、awk
Perl または Python の使用を検討します。それでも に制約されている場合はsed
、ホールド スペースを使用してラインの一部を保持し、パターン スペースで他の部分を操作して、印刷前にホールド スペースとパターン スペースから目的の出力ラインを再統合することになります。この線。それは聞こえるほど厄介です。実際には、思ったよりも厄介かもしれません。私は Perl を使いますが (私はずっと前に Perl を学び、この種のことを非常に簡単に実行できるため)、sed
ツール以外の好きなものを使用できます。
3 番目のフィールドを編集する Perl。デフォルトの出力は$_
、配列内の自動分割フィールドから再構築する必要があることに注意してください@F
。
$ echo "pattern@pattern@pattern@pattern" | sh -x xxx.pl
> perl -pa -F@ -e '$F[2] =~ s/\s*pat(\w\w)rn\s*/ prefix-$1-suffix /; $_ = join "@", @F; ' "$@"
pattern@pattern@ prefix-te-suffix @pattern
$
説明。 これは、「ループし、各反復の最後に-p
行を読み込ん$_
で印刷する」ことを意味します。$_
これは、「配列に-a
自動分割」することを意味します。は、フィールド セパレータが であることを意味します。この後に Perl プログラムが続きます。Perl では配列は 0 からインデックス付けされるため、3 番目のフィールドは(シジル — or — は、配列の値を操作するか、配列全体の値を操作するかによって変化します。は一致演算子です。は、RHS の正規表現を LHS の値に適用します。置換パターンは、0 個以上のスペースとそれに続く2 つの「単語」文字を認識し、$_
@F
-F@
@
-e
$F[2]
@
$
=~
\s*
pat
$1
rn
そして再びゼロ以上のスペース。フィールドの開始と終了にバインドする^
andがそこにあるはずです。$
置換は、スペース、'prefix-'、記憶された文字のペア、および'-suffix' とスペースです。は、変更された可能性のある個別のフィールドから$_ = join "@", @F;
入力行を再構築し、それを出力します。私が望むほどきれいではありません(おそらくもっと良い方法があります)が、うまくいきます。また、Perl では、任意のフィールドに対して任意の変換を簡単に行うことができます。Perl には、非常に複雑な CSV ファイルを処理できるモジュール(および高速な C バージョン) もあります。$_
-p
Text::CSV
Text::CSV_XS
これはあなたのために働くかもしれません:
echo 0001 @ fish @ animal @ eats worms|
sed 's/@/&\n/2;s/@/\n&/3;h;s/\n@.*//;s/.*\n//;y/a/b/;G;s/\([^\n]*\)\n\([^\n]*\).*\n/\2\1/'
0001 @ fish @ bnimbl @ eats worms
説明:
\n
前と直後に改行()を挿入します。s/@/&\n/2;s/@/\n&/3
h
s/\n@.*//;s/.*\n//
a's
をに変更しb's
ます。y/a/b/
G
s/\([^\n]*\)\n\([^\n]*\).*\n/\2\1/
注意:ステップ4では、パターンスペースには定義されたフィールドのみが含まれているため、ここで任意の数のコマンドを実行でき、結果は行の残りの部分に影響しません。
基本的に、探しているパターンを真ん中にして、線を 3 つに分けます。次に、外側のピースを残し、中央を交換します。
/\([^@]*@[^@]*@\[^@]*\)pattern\([^@]*@.*\)/s//\1replacement\2/
\([^@]*@[^@]*@\[^@]*\)
- 3 番目の @ と数式の前のテキストを含む、パターンの前のすべてを収集します - これは \1 になります
pattern
- あなたが探しているもの
\([^@]*@.*\)
- パターンの後にすべてを集めます - これは \2 になります
\1
次に、その行を に変更しreplacement
、その後のすべてを変更しpattern
ます。\2