---------- SED 教室 第五回 「文字列の置換」 ---------- 前回は正規表現について説明しました。実は SED では実行条件以外にも正規 表現を使うところがもう一つあります。SED の命令には文字列の置換を行う命令 がありまして、どの文字列を置換の対象にするかを指定するために正規表現が使 われるのです。まず置換命令の書き方から説明しましょう。 s/正規表現/文字列/ パターンスペースの中で、「正規表現」にマッチする 文字列を「文字列」と置き換えます。例えばパターンス ペースが「abcdefg」の時「s/def/XYZ/」を実行すると、 「abcXYZg」に変わります。 では実際に使ってみましょう。 <<< TITLE.SED >>> ---------------------------------------- /^[0-5][0-9][0-9]\/[0-5][0-9][0-9]/{ s/\/[0-9 ]*/:/ p } d ---------------------------------------- スクリプトの一行目は、前回の講義でやったのと同じですね。会議室の発言の タイトルの行で条件が成立します。ん? 最後にある「{」は何でしょう。条件の 次は命令では? というわけで新しい命令の紹介です。 { 次に「}」が現れる行までの命令を実行する。つまり、「実行条件」が成 立したとき複数の命令を実行する事が出来るのです。当然、「実行条件」 が成立しないときは「{」と「}」で囲まれた命令は実行されません。 この場合でしたら、タイトル行で命令「s」(置換)と「p」(出力)を実行するわ けです。 では二行目はどのような動きをするでしょうか。正規表現「\/[0-9 ]*」とマ ッチする文字列が「:」に置換されるのですね。ふむふむ、そして三行目でパタ ーンスペースが標準出力に吐き出されるのか。五行目は現在のパターンスペース の内容を削除し、標準入力から次の行を読み込み、スクリプトの一行目へジャン プします。 さて、ではここで問題です。命令「s/\/[0-9 ]*/:/」によってどんな文字列が 「:」で置き換えられるのでしょう。まず「/」で始まって、数字か空白が何個か つながったものですか。例えば、パターンスペースが 「003/009 GCD03723 最大公約数 SED 教室その 1」 だと、「/009 」(空白が 3 個) ですね。でもよく考えると「/009 」(空白 が 2 個) だってマッチしそうです。え?「/」はどうなんだって? 「[0-9 ]*」 は数字か空白の*0 個*以上の繰り返しですから、これも実は正しいのです。し かし SED の動作が何通りもあっては混乱を招くだけですから、置換される文字 列がただ一通りに決まるように規則が決めてあります。スポーツで延々と試合が 同点のまま続いたときは最後はじゃんけんで決める、という規則が決められてい るのと同じです (違うって? :-)。その規則とは マッチする文字列の中で、文字列の左端が一番左にあるもの。 もし左端が一致する文字列が複数個ある時は、その中で一番長いもの。 を置換する文字列に選ぶのです。この場合でしたら、どの候補も左端は「/」 で同じ位置ですから、長さで勝負が決まります。 一番長いのは「/009 」(空白が 3 個) ですね。結局置換が行われるとパタ ーンスペースの内容は 「003:GCD03723 最大公約数 SED 教室その 1」 になります。これで正規表現にマッチする文字列がたくさんあっても、どの文 字列が選ばれるかすぐわかりますね。では次の例はどうでしょうか。 パターンスペース : 「bbbaaccaaa」 命令 : 「s/a*/A/」 「a*」にマッチする文字列はどれでしょう。4 文字目の「a」, 4 ~ 5 文字目 の「aa」, 8 文字目の「a」, 8 ~ 9 文字目の「aa」, 8 ~ 10 文字目の「aaa」 ですか。するとその中で左端が一番左にあるのは 4 文字目から a が始まってい る文字列です。その中で長さが一番長いのは 4 ~ 5 文字目の「aa」。だから置 換後はパターンスペースは「bbbAccaaa」になっているはずです。では実験して みましょう。この命令は短いのでコマンドラインに書いてみます。 まず、コマンドラインから | |A>sed -e s/a*/A/ と入力して改行。標準入力はキーボードになります。次に |bbbaaccaaa と入力して改行。 |^Z 標準入力の終わりを示すために control-Z。 SED はスクリプトの一行目「s/a*/A/」を読んで命令を実行した後二行目を読 もうとすると、もうスクリプトはありません。困ったなと思うのではなくて命令 「p」と「d」を実行するのでした (第三回 SED 教室でやりましたね)。まず、 「p」パターンスペースを標準出力に吐き出す。次に「d」パターンスペースを削 除して標準入力から次の行を読み込む。と思ったらもう標準入力はおしまいです。 標準入力がなくなってしまうと SED は何もすることがなくなってしまうので実 行を終了します。というわけで置換後のパターンスペースが画面 (標準出力) に 現れるわけです。では画面を見てみましょう。 |Abbbaaccaaa |A> おやおや? なにか予想したものと違うものが出てきてしまいました。4 文字 目からの「aa」は置換されず、一番前に「A」が挿入されています。一体どうし たというのでしょうか。実はもとの文字列の「bbbaaccaaa」の先頭の長さ 0 の 文字列 (ヌルストリングと言います) が正規表現「a*」とマッチしてしまったの です。このように長さ 0 の文字列とマッチする正規表現には注意する必要があ ります。 さてみなさんはエディタで、ファイルの中の特定の文字列を全部ほかの文字列 で置き換えた事はありませんでしょうか。例えば句読点を「、」「。」で全部書 いた後で「, 」「. 」に全部直すという事は時々必要になります。エディタを起 動して書き換えても良いのですが、単なる置換ですから上で説明した命令を使え ば SED でも出来そうです。でもちょっと待って下さい。例えばパターンスペー スが「本日は晴天なり。今日は良い天気です。」だったとします。このとき 「s/。/. /」を実行すると、「晴天なり。」の句点は置換されるのですが、二番 目の「天気です。」の句点は変換されずに残ってしまいます。もう一度置換を実 行すれば良いって? でも句点が一行に 3 個以上あるとやっぱり困ってしまいま す。そこで命令「s」のバリエーションとして次のものがあります。 s/正規表現/文字列/g パターンスペースの中で、「正規表現」にマッチする 文字列を全て「文字列」と置き換えます。 これを使えばうまく行きそうです。 | |A>sed -e "s/、/, /g" -e "s/。/. /g" < input.txt などとすれば良いでしょう。パターンスペースの読点を変換し、次に句点を変 換するわけです。(その次はもちろん「p」と「d」の実行です。) 以上で SED の最低限 :-) の使い方は全て説明した事になります。色々なスク リプトを書いて実験してみて下さい。 今までは一行づつ読み込み、置換し、出力していました。次回からはちょっと 高度な使い方として、複数行をまとめて編集する方法を紹介する予定です。複数 行をまとめて扱う事によって、例えば複数行にわたるヘッダ (Nifty の会議室の 発言のヘッダも実は 2 行ですね) が編集できるようになります。 --- GCD03723 (Greatest Common Divisor:最大公約数)