sedでダブルクォートで括られてる("ABC")ような文字列の置換をしようとしていたんだけど、うまくいかなかった。
これだと、ダブルクォートの中が以外の任意の1文字と"+"の場合しかマッチない。
ダブルクォートの中には必ず1文字以上ある事を意図して"+"記号を使っていたんだけど、どうもsedではこれを特殊記号として扱ってくれないらしい。
なので、以下だとうまくいく。
どうしてこんなことになるかというと。。。
一般に使われている正規表現を大きく分けると以下の3つになる。
※他にも正規表現の方言はたくさんあるのであくまで、大きく分けるとという話。
BRE - Basic Regular Expressions
ERE - Extended Regular Expressions
PCRE - Perl Compatible Regular Expressions
それぞれの規格の参照先は以下。
The Open Group Base Specifications Issue 7
IEEE Std 1003.1-2008, 2016 Edition
9.3 Basic Regular Expressions
9.4 Extended Regular Expressions
Perl regular expressions man page.
PCRE - Perl Compatible Regular Expressions
この中で標準的なUnixコマンドでEREが使えるのはgrepで"-e"オプションを指定した場合で、他はほとんどBREしか使えない。
じゃあ、後方参照と選択演算子を1回の検索で使いたかったら、どうしようか。
※BREは後方参照をサポートしているのに、EREは後方参照をサポートしていないというヘンな規格だ。 つまり、EREはBREの上位互換ではないということになる。
そんな場合はPCREを使えばいいってことになるし、その場合は素直にPerlを使おう。
Perlでは"-n"や"-p"オプションを使えば、標準入力もしくは指定されたファイルの1行毎に対して、作用するプログラムを記述することができる。
例えば、catと同じ事をしたければ、以下のようになる。
なんでこれがcat相当になるかは、"-MO=Deparse"オプションをつけると確認できる。
ワンライナーが実際にどのようなスクリプトになるかを確認したいときは"-MO=Deparse"を使うといいだろう。
"-n"オプションだと"-p"と違い、自動で毎行printがない。
これを使えば、PCREでgrep,sed,awk相当のことができる。
まず、sedライクな置換がしたければ、以下のようになる。
grepのように該当行のみの抽出がしたければ、こうしよう。
awkのように分割されたフィールドを扱いたければ、"-a"オプションを使う。
そうすると、分割されたフィールドが @F 配列に格納される。
"-F"オプションを使えば、フィールドセパレータの文字を変えることもできる。
$ sed -e 's/"[^"]+"/"xxx"/g' "foo" "foo" "f+" "xxx"
これだと、ダブルクォートの中が以外の任意の1文字と"+"の場合しかマッチない。
ダブルクォートの中には必ず1文字以上ある事を意図して"+"記号を使っていたんだけど、どうもsedではこれを特殊記号として扱ってくれないらしい。
なので、以下だとうまくいく。
$ sed -e 's/"[^"][^"]*"/"xxx"/g' "" "" "foo" "xxx"
どうしてこんなことになるかというと。。。
一般に使われている正規表現を大きく分けると以下の3つになる。
※他にも正規表現の方言はたくさんあるのであくまで、大きく分けるとという話。
BRE - Basic Regular Expressions
ERE - Extended Regular Expressions
PCRE - Perl Compatible Regular Expressions
それぞれの規格の参照先は以下。
The Open Group Base Specifications Issue 7
IEEE Std 1003.1-2008, 2016 Edition
9.3 Basic Regular Expressions
9.4 Extended Regular Expressions
Perl regular expressions man page.
PCRE - Perl Compatible Regular Expressions
この中で標準的なUnixコマンドでEREが使えるのはgrepで"-e"オプションを指定した場合で、他はほとんどBREしか使えない。
じゃあ、後方参照と選択演算子を1回の検索で使いたかったら、どうしようか。
※BREは後方参照をサポートしているのに、EREは後方参照をサポートしていないというヘンな規格だ。 つまり、EREはBREの上位互換ではないということになる。
そんな場合はPCREを使えばいいってことになるし、その場合は素直にPerlを使おう。
Perlでは"-n"や"-p"オプションを使えば、標準入力もしくは指定されたファイルの1行毎に対して、作用するプログラムを記述することができる。
例えば、catと同じ事をしたければ、以下のようになる。
$ perl -lpe '' filename
なんでこれがcat相当になるかは、"-MO=Deparse"オプションをつけると確認できる。
$ perl -MO=Deparse -lpe '' BEGIN { $/ = "\n"; $\ = "\n"; } LINE: while (defined($_ =)) { chomp $_; } continue { die "-p destination: $!\n" unless print $_; } -e syntax OK
ワンライナーが実際にどのようなスクリプトになるかを確認したいときは"-MO=Deparse"を使うといいだろう。
"-n"オプションだと"-p"と違い、自動で毎行printがない。
$ perl -MO=Deparse -lne '' BEGIN { $/ = "\n"; $\ = "\n"; } LINE: while (defined($_ = <ARGV>)) { chomp $_; } -e syntax OK
これを使えば、PCREでgrep,sed,awk相当のことができる。
まず、sedライクな置換がしたければ、以下のようになる。
$ perl -lpe 's/foo/FOO/g' foobarfoo FOObarFOO
grepのように該当行のみの抽出がしたければ、こうしよう。
$ perl -lne 'print $_ if $_ =~ /bar/' foo bar bar $ #マッチしない行のみ抽出するバージョン $ perl -lne 'print $_ if $_ !~ /bar/'
awkのように分割されたフィールドを扱いたければ、"-a"オプションを使う。
そうすると、分割されたフィールドが @F 配列に格納される。
$ perl -alne 'print $F[0]' ABC DEF ABC
"-F"オプションを使えば、フィールドセパレータの文字を変えることもできる。
$ perl -alne 'print $F[0]' -F, ABC,DEF ABC
0 件のコメント:
コメントを投稿