th0x0472.log

アクセスカウンタ

zoom RSS awkのsub()関数について調べてみました。正規表現とか。

<<   作成日時 : 2012/03/09 00:25   >>

なるほど(納得、参考になった、ヘー) ブログ気持玉 1 / トラックバック 3 / コメント 1

大部分の人には何の脈絡もない突発的な記事に思えるでしょうが、ちゃんと理由があるのです。
なんてことを言う前に、そもそもこのブログをどれだけの方が読んでくれているのか自覚すべきです>自分。

一昨日の #bookathon でごくごく一部でちょっとだけ話題になったので、調べてみました。

awk はOSX Lionのデフォルトのヤツです。Cygwinは・・・気が向いたら試してみます。

awkには文字列を置換するsub()関数があります。


sub(r,s,t)


文字列t の中で最初にrにマッチしたものを文字列sに置き換えます。
たとえばこんな感じです。


bash-3.2$ echo "Hello world."
Hello world.
bash-3.2$ echo "Hello world." | awk '{sub("world","heaven",$0); print $0}'
Hello heaven.


"world" が "heaven" に置き換えられました。


sub(r,s,t)


t が指定されないと、$0 が使われます。だから上の例は、次のようにも書けます。


bash-3.2$ echo "Hello world."
Hello world.
bash-3.2$ echo "Hello world." | awk '{sub("world","heaven"); print}'
Hello heaven.
bash-3.2$



そして、rには正規表現が使えます。本題です、たぶん。


bash-3.2$ echo "Hello Tokyo. Hello Kyoto."
Hello Tokyo. Hello Kyoto.
bash-3.2$ echo "Hello Tokyo. Hello Kyoto." | awk '{sub(/Tokyo|Kyoto/,"Osaka"); print}'
Hello Osaka. Hello Kyoto.


Tokyo が Osakaに置き換えられてしまいました。しかし、Kyoto はそのままです。


bash-3.2$ echo "Hello Kyoto. Hello Tokyo." | awk '{sub(/Tokyo|Kyoto/,"Osaka"); print}'
Hello Osaka. Hello Tokyo.


今度はKyotoがOsakaに置き換えられました。Tokyoはそのままです。

これ、出現順と置換回数の問題なんです。
sub()関数は、文字列tの中で最初に正規表現r にマッチした部分を置き換えます。それ以降は見ません。
だから、Kyotoの後に出てきたTokyoはそのままでした。

最初の説明で「文字列t の中で最初にrにマッチしたもの」と書いてましたが、つまりそういうことです。

文字列tの中で正規表現rにマッチするすべての部分を文字列sに置き換えたい場合は、sub()関数ではなくてgsub()関数を使います。


bash-3.2$ echo "Hello Kyoto. Hello Tokyo." | awk '{gsub(/Tokyo|Kyoto/,"Osaka"); print}'
Hello Osaka. Hello Osaka.
bash-3.2$


こんどは、TokyoもKyotoもOsakaに置き換えられました。

ついでにパイプ自身にヒットさせる場合です。


bash-3.2$ echo '|'
|
bash-3.2$ echo '|' | awk '{sub(/|/,"pipe"); print}'
awk: illegal primary in regular expression | at
source line number 1
context is
         >>> {sub(/|/,"pipe") <<<


当然怒られます。エスケープしてやればOKです。


bash-3.2$ echo '|' | awk '{sub(/\|/,"pipe"); print}'
pipe


つぎはこれ。"大文字K または 小文字k につづいて yo" を "京" に置き換えてます。


bash-3.2$ echo "Hello Kyoto. Hello Tokyo." | awk '{gsub(/[Kk]yo/,"京"); print}'
Hello 京to. Hello To京.
bash-3.2$


京to とか気持ち悪い・・・。(だったらやめておけ・・・)

文字列中の [ または ] をなかったことにするには、こんな感じです。


bash-3.2$ echo "[H[]][[][e[]][]][l]][[l[o][ [[[[[w][][][]o[]]][][[r]][[][][][[][][[[][][l[]]]d][.[][][[[][]]][][" | awk '{gsub(/[\[\]]/,"");print}'
Hello world.
bash-3.2$


やりすぎです、すみません・・・・。

もうちょっと素直な例を。


bash-3.2$ echo "[ABC]"
[ABC]
bash-3.2$ echo "[ABC]" | awk '{gsub(/[\[\]]/,""); print}'
ABC


[ ] でくくられた中にエスケープされた [ と ] があり、それが空(から)の文字列"" に置き換えられます。
コレでもいけました。


bash-3.2$ echo "[ABC]" | awk '{gsub(/\[|\]/,""); print}'
ABC


sub()関数も gsub()関数も、文字列t を書き換えてます。関数が返す値が文字列ではありません。
つまりこういうことです。


bash-3.2$ echo "Hello Kyoto." | awk '{sub("Kyoto","Osaka"); print; sub("Osaka","Tokyo"); print}'
Hello Osaka.
Hello Tokyo.
bash-3.2$


1回目のsub()関数で $0 が "Hello Osaka." に書き換えられ、2回目のsub()関数で $0 が "Hello Tokyo" に書き換えられてます。もし2回目のsub()関数の置換の条件が "Kyoto" だったら、$0 は書き換えられません。こんな感じになります。


bash-3.2$ echo "Hello Kyoto." | awk '{sub("Kyoto","Osaka"); print; sub("Kyoto","Tokyo"); print}'
Hello Osaka.
Hello Osaka.


関数が返す値は、置換した回数です。


bash-3.2$ echo "[H[]][[][e[]][]][l]][[l[o][ [[[[[w][][][]o[]]][][[r]][[][][][[][][[[][][l[]]]d][.[][][[[][]]][][" | awk '{N=gsub(/[\[\]]/,"");print N}'
84


置換が発生しないと当然0です。


bash-3.2$ echo "Hello Kyoto." | awk '{N1=sub("Kyoto","Osaka"); print; print N1; N2=sub("Kyoto","Tokyo"); print; print N2}'
Hello Osaka.
1
Hello Osaka.
0
bash-3.2$


if文の条件式にも使えました。


bash-3.2$ echo "Hello Kyoto." | awk '{if(sub("Kyoto","Osaka")) print; if(sub("Kyoto","Osaka"))print}'
Hello Osaka.
bash-3.2$


正規表現は / / でくくらないといけないのかな?と思って試してみたら・・・何とも微妙な結果に。


bash-3.2$ echo "[AABBC]" | awk '{gsub("[AB]","C");print}'
[CCCCC]
bash-3.2$ echo "[AABBC]" | awk '{gsub("[\[\]]","\"");print}'
[AABBC]
bash-3.2$ echo "[AABBC]" | awk '{gsub(/[\[\]]/,"\"");print}'
"AABBC"


とりあえず、/ / でくくるのが安心なようです。

ちなみに、今回の記事は「sed & awkプログラミング 改訂版」を参考にしました。今回の内容を5ページ位で説明してて、450ページくらいあるんだから、恐るべし・・・。

詳説 正規表現 第3版
オライリージャパン
Jeffrey E.F. Friedl

amazon.co.jpで買う
Amazonアソシエイト by 詳説 正規表現 第3版 の詳しい情報を見る / ウェブリブログ商品ポータル



sed & awkプログラミング 改訂版
オライリー・ジャパン
Dale Dougherty

amazon.co.jpで買う
Amazonアソシエイト by sed & awkプログラミング 改訂版 の詳しい情報を見る / ウェブリブログ商品ポータル

テーマ

関連テーマ 一覧


月別リンク

ブログ気持玉

クリックして気持ちを伝えよう!
ログインしてクリックすれば、自分のブログへのリンクが付きます。
→ログインへ
気持玉数 : 1
なるほど(納得、参考になった、ヘー)

トラックバック(3件)

タイトル (本文) ブログ名/日時
オークリー
awkのsub()関数について調べてみました。正規表現とか。 th0x0472.log/ウェブリブログ ...続きを見る
オークリー
2013/07/06 01:47
プラダ バッグ
awkのsub()関数について調べてみました。正規表現とか。 th0x0472.log/ウェブリブログ ...続きを見る
プラダ バッグ
2013/07/07 06:57
プラダ 財布
awkのsub()関数について調べてみました。正規表現とか。 th0x0472.log/ウェブリブログ ...続きを見る
プラダ 財布
2013/07/08 02:38

トラックバック用URL help


自分のブログにトラックバック記事作成(会員用) help

タイトル
本 文

コメント(1件)

内 容 ニックネーム/日時
sub,gsubのrは//で囲ってやったほうが良かったんですね〜。知らなかった・・・。

ちなみに私の場合、置換をかける時は$0にかけるケースがまず無く、大抵フィールド指定で初めにヒットした物のみ置換=sub関数を使ってます。
でも、パイプ使ってあれもこれも、とやりたい場合はやっぱりgsubが必要になるんですね。盲点でした(^-^;

パイプ自体をヒットさせる方法、わかって勉強になりました><
sed&awkは1年くらい前の現場に置きっぱなしで、戻ってくるかどうかわからない状態で泣きたい(笑)

usaturn
2012/03/09 01:30

コメントする help

ニックネーム
本 文
awkのsub()関数について調べてみました。正規表現とか。 th0x0472.log/BIGLOBEウェブリブログ
文字サイズ:       閉じる