---------- SED 教室 第十三回 「~から~まで、応用編」 ---------- 前回紹介したように、「/これ/,/そして/」などの実行条件を用いると、現在 条件が成立しているか否かを SED が覚えてくれます。したがってフラグの代わ りに用いる事が出来ます。 例えば、特定の漢字が、最初に現れた時だけ振り仮名をつけるスクリプトは次 のように書けます。 <<< YOMI.SED >>> --------------------------------------- 1,/条件/s//&(じょうけん)/ 1,/教室/s//&(きょうしつ)/ 1,/最初/s//&(さいしょ)/ --------------------------------------- 命令「s」の正規表現 (どの文字列を置換の対象にするか指定する表現でした ね) がヌルストリング (長さ 0 の文字列) であることに注意して下さい。正規 表現が省略されると、直前の正規表現と同じであると解釈されます。つまり、 「1,/条件/s//&(じょうけん)/」は、 「1,/条件/s/条件/&(じょうけん)/」 と全く同じ意味です。長い正規表現を何回も書くのは面倒ですから、同じ正規表 現が続く時は省略した方が楽ですよね。でも楽なだけではありません、少しだけ 実行速度が速くなります。というのも、sed は実行時にまずスクリプトを全部読 み込んでから作業を開始するのですが、スクリプトに正規表現があると、それを 内部表現に変換します。正規表現が省略されていると、変換作業も省略できる (直前に作った内部表現をそのまま使えますからね) のでちょっぴり効率が良い というわけです。 さて、「1,/条件/」という実行条件は、標準入力の 1 行目から「条件」とい う文字が現れる行まで成立します。つまり一度「条件」という文字列を含む行が 現れたが最後、この実行条件は以後二度と成立することはありません。従って置 換は最初の「条件」という文字列にたいしてのみ行なわれるわけです。 文字列「教室」,「最初」についても同様です。この「SED 教室」のファイル を <<< YOMI.SED >>> で処理して、どのように動作するか確かめて下さい。 うまくいきましたでしょうか ? おや ? 2 つ目の「教室」にも振り仮名がついてる ? (注意) 「---------- SED 教室 第十三回 ... 」のタイトルが 1 行目に来るよ うなファイルで実験して下さいね。(^^) ^^^^^^^ 「1,/教室/」という実行条件は、1 行目から「教室」を含む行まで成立するわ けですが、1 行目では「/教室/」という条件が成立するか否かは sed は関知し ないのです。つまり最初の条件が成立した行以降で、2 番目の条件が成立する行 まで「~から~まで」の実行条件が成立する、というわけです。 これを回避するには、1 行目を 2 回 sed に読み込ませれば OK です。すなわ ち 1 回目は条件「1」を成立させるために、2 回目は条件「/教室/」が成り立つ か調べるために。1 回目の読み込みでは「1 行目」でさえあれば何でもいいので、 パターンスペースをヌルストリングにすることにします。スクリプトは次のよう に書けます。 <<< YOMI2.SED >>> --------------------------------------- 1 1!b top 2 h 3 s/.*// 4 :top 5 1,/教室/s//&(きょうしつ)/ 6 1,/条件/s//&(じょうけん)/ 7 1,/最初/s//&(さいしょ)/ 8 1!b 9 G 10 /^\n./{ 11 g 12 b top 13 } 14 s/\n.*// --------------------------------------- スクリプトの三行目でパターンスペースをヌルストリングにして 1 回目の読 み込みを行ないます。標準入力の「本当の」 1 行目は、スクリプトの二行目の 「x」でホールドスペースに保存されています。そして十一行目で保存していた 1 行目を元に戻して 2 回目の読み込みを行なうわけです。 2 回目の読み込みでは、パターンスペースの内容とホールドスペースの内容は 同じです。従ってスクリプト十行目の実行条件は成立しないので、3 回目の読み 込みは行なわれず、標準入力の 2 行目の読み込みが行なわれますね。 <<< YOMI2.SED >>> では、最初に現れた文字列だけの置換でしたが、2 番目、 3 番目に現れた文字列を置換することも出来ます。 <<< YOMI3.SED >>> --------------------------------------- 1 1!b top 2 h 3 s/.*// 4 :top 5 1,/\(条件\)\([^(]\)/s//\1(じょうけん)<1st>\2/ 6 1,//s//\1(じょうけん)<2nd>\2/ 7 1,//s//\1(じょうけん)<3rd>\2/ 8 1,//s//\1(じょうけん)<4th>\2/ 9 1,/\(最初\)\([^(]\)/s//\1(さいしょ)<1st>\2/ 10 1,//s//\1(さいしょ)<2nd>\2/ 11 1,//s//\1(さいしょ)<3rd>\2/ 12 1,//s//\1(さいしょ)<4th>\2/ 13 1!b 14 G 15 /^\n./{ 16 g 17 b top 18 } 19 s/\n.*// --------------------------------------- 正規表現の省略が多用されていることに注意して下さい。<<< YOMI2.SED >>> では一度「条件」という文字列が現れた後は、「条件」という文字列は置換され ませんが、<<< YOMI3.SED >>> だと、スクリプト六~八行目があるので、2 番め 以降の「条件」という文字列も置換されます。文字列「条件」が現れるたびにス クリプト六~八行目の実行条件が順に不成立になっていくわけです。 あと注意すべき点は、置換後の文字列「条件(じょうけん)<1st>」の中に置換 対象の文字列「条件」が含まれてしまっている点です。 # 読み仮名をつけるという目的上、やむを得ませんね。 <<< YOMI2.SED >>> と同じように「s/条件/&(じょうけん)/」で置換すると、 最初の文字列「条件」が何回も置換されて、 条件(じょうけん)<1st> ↓ 条件(じょうけん)<2nd>(じょうけん)<1st> ↓ 条件(じょうけん)<3rd>(じょうけん)<2nd>(じょうけん)<1st> などとなってしまいます。<<< YOMI3.SED >>> の様に、正規表現に「[^(]」を 付けて、文字列「条件」の後に「(」が続かないもののみを置換対象にすれば、 一応 (^^;) 防ぐことが出来ます。 --- GCD03723 (Greatest Common Divisor:最大公約数)