Perlの正規表現で繰り返し置換する方法

Perlの正規表現で繰り返し置換する方法

Posted at July 30,2013 12:55 AM
Tag:[Perl]

Perlの正規表現を使って文字列を繰り返し置換する方法を紹介します。

テキストの中のある文字列を一律変換するのではなく、マッチする文字列の一部を除外しなければいけないという条件つきです。

ネットで色々調べてみましたが、同じ解決策がみつけられなかったので自力で作ってみました。

1.問題点

次のように、右辺に含まれる「0」だけを「A」に変換する必要が生じました。

変更前

102030=012301230123

変更後

102030=A123A123A123

「=」以外の、左辺および右辺の文字数や「0」の出現位置は不定とします。

実際には1行ではなく、このような行が数十行にわたって記述されていますが、1行単位で処理すればいいのでここでは省略しています。

ちなみにネットで調べたところ、次のようなサンプルは数多くヒットしました。

例:テキストに含まれる「0」をすべて「A」に変更

変更前

012301230123

変更後

A123A123A123

この例であれば、次のような一括置換を行えば一撃です。

my $content = '012301230123';
$content =~ s/0/A/g;

が、この方法を使って

my $content = '102030=012301230123';
$content =~ s/0/A/g;

とすると、左辺も含めてすべての「0」が「A」に変換されてしまいます。

変更前

102030=012301230123

変更後

1A2A3A=A123A123A123

2.特定の文字列を複数回置換する

追記:@usualomaさんから回答いただきました。ありがとうございました!

「(?!式)」は、後続の文字列が式に一致しなければマッチする拡張構文です。

この場合、後続の文字列が「=」に一致しない「0」に(複数回)マッチするということになります。勉強になりました。

以降は元エントリーの内容ですがそのまま残しておきます。

「=」で文字列を分割して右辺を一括置換した後結合するという方法もありますが、ここではwhileと組み合わせて実現してみました。

my $content = '102030=012301230123';
while ( $content=~ s/(.*=)(.*)0(.*)/$1$2A$3/ ) {}

これで変換後の値は、右辺のすべての「0」が「A」に変換されて、

102030=A123A123A123

となります。

このコードではまず最後尾の「0」を「A」に変換し、while文を使って左方向に向かって右辺のすべての「0」を「A」に変換していきます。

3.その他

ちなみにg修飾子を使って、

$content =~ s/(.*=)(.*)0(.*)/$1$2A$3/g;

でよいのでは?と思った方もいるかもしれませんが、上のコードでは最後に出現した「0」だけが「A」に置換されて、

102030=01230123A123

となってしまいます。

また、最短マッチを意味する「量指定子+?」を使った、

$content =~ s/(.*=)(.*?)0(.*)/$1$2A$3/g;

の場合は、最初に出現した「0」しか「A」に置換されません。

102030=A12301230123

ということで2項のようなコードにしています。

よりエレガントな解があると思いますので、質問の意味も含めてエントリーしてみました。

関連記事
トラックバックURL


コメントする
greeting

*必須

*必須(非表示)


ご質問のコメントの回答については、内容あるいは多忙の場合、1週間以上かかる場合があります。また、すべてのご質問にはお答えできない可能性があります。予めご了承ください。

太字イタリックアンダーラインハイパーリンク引用
[サインインしない場合はここにCAPTCHAを表示します]

コメント投稿後にScript Errorや500エラーが表示された場合は、すぐに再送信せず、ブラウザの「戻る」ボタンで一旦エントリーのページに戻り(プレビュー画面で投稿した場合は、投稿内容をマウスコピーしてからエントリーのページに戻り)、ブラウザをリロードして投稿コメントが反映されていることを確認してください。

コメント欄に(X)HTMLタグやMTタグを記述される場合、「<」は「&lt;」、「>」は「&gt;」と入力してください。例えば「<$MTBlogURL$>」は「&lt;$MTBlogURL$&gt;」となります(全て半角文字)