• ベストアンサー

正規表現で置換した後に前後も含めて空白(改行)のみの場合は削除する

現在、Perlでテンプレート処理みたなものを自作しています。 例えば my $str = <<'TEST'; test $test $test2 test TEST my $test = 'test'; $str =~ s/(\$\w+)/eval($1)/eg; print $str; exit; のような感じの時に(実際には特定の記号の範囲内にてサブルーチンや Perl構文なども処理できるようにしていますがこの際には例外処理や 複雑な処理などは一切考慮しないものとします)置換結果が空白で 前後が改行などのみになった場合にその行を削除したいのですが どうしたらよいのでしょうか。 >>例(上記の場合の実行結果) ---------- test test test ---------- ↓(理想) ---------- test test test ----------

質問者が選んだベストアンサー

  • ベストアンサー
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

凝った方法はあるのかもしれんけど, そんなことより「思考をそのままソースに書く」ことの方が一般には重要. でもって状況を確認したいんですけど, ・「あと、上記の例では簡単にするために1行単位にしていますが実際には もっと処理が複雑で1行内に複数の変数が含まれていることもあります。 (gオプション付)」というのはどういうことでしょうか? 文章の前半と後半がかみあっていないんですけど. ・「マッチした部分を置換した行が結果的に ^(\s*\n?)$ であればその部分(改行含)は出力せず、それ以外なら出力させたい」というのは, 「置換した部分を含めた全体が」という解釈でいいですか? あと, 文字列の先頭と末尾は \A, \Z でマッチしませんでしたっけ?

pick52
質問者

補足

ありがとうございます。 こちらの説明不足と当初の想定していた仕様範囲の想定及び説明の 間違いなどがありまして、皆様にご迷惑をおかけして申し訳ありません。 皆様の回答を見ながらなんとか想定していたものを実現できたようです。 実際には &{~}& の範囲内をPerl構文として実行したかったのです。 因みにこの間は改行を含めることができたり、1行内(この1行とは &{~}& の範囲は無視)に複数入れたりできるというようにしたかった のですがこの説明をするとややこしくなるかなと思った上で省略したら 余計にややこしくなってしまいました。 結果的に # 対象文字列 my $str = <<'TEST'; test &{ return $test; }& &{ return $test2; }& test TEST #my $test = '$test'; #my $test2 = '$test2'; # 変換用のサブルーチン my $func = sub { my $str = shift; $str =~ s/&{(.+?)}&/eval($1)/egs; if($str =~ /^\s*\n?$/s) { return; } return $str; }; # 変換 $str =~ s/((([^\n]*?)&{(.+?)}&(?=[^\s]*))+(\n?))/&$func($1)/egs; # 表示 print $str; exit; こんな感じになりましたがもしかすると間違いがあるかもしれません。

その他の回答 (5)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.6

よく考えたら, そもそも「一発で全部やりたい」とする意味がわからん. たいていの場合で「短いけど凝った記述」よりも「長いけど素直な記述」の方が安全. 今の場合だと「\n で split して各行を処理したあとまとめる」ということになるのかなぁ? ど~しても「一発」にしたいならサブルーチン使えばいいだけ.

pick52
質問者

補足

ありがとうございます。 何とかできたようです(No3)。

回答No.5

仕様がよくわかりません。。。 ・$に続く変数名っぽい文字列があれば、変数として展開 ・空白行は削除(連続する改行は1つに詰める) って言うことでいいでしょうか? 2行になりますけど。 $str=~s/(\$\w+)/eval($1)/ge; $str=~s/\n{2,}/\n/g; # $str=~s/\s{2,}/\n/g; # スペースのみの行も消すなら 検証 my $aaa='hoge'; my $bbb='page'; my $str=<<'END'; test $aaa $bbb $ccc test END $str=~s/(\$\w+)/eval($1)/ge; $str=~s/\n{2,}/\n/g; print $str; -- 結果 -- test hoge page test

pick52
質問者

補足

ありがとうございます。 何とかできたようです(No3)。

  • kumoz
  • ベストアンサー率64% (120/185)
回答No.4

あまり洗練されていませんが、一番簡単なのは while ループで1行ずつ処理することだと思います。 use strict; my $str = <<'TEST'; test $test $test2 test TEST my $test = 'test'; my $test2 = ''; while ($str =~ /(.*\n)/g) { my $line = $1; if ($line =~ /^\s*\n/) { print $line; } else { $line =~ s/(\$\w+)/$1/eeg; print $line if $line !~ /^\s*\n/ } }

pick52
質問者

補足

ありがとうございます。 何とかできたようです(No3)。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

s/// で置換ができたかどうかはその値でわかりますから, 「置換ができて空白だけになった」場合を除いて出力すればいいのでは? 例えば unless($str =~ s/// and $str =~ /^\s*$/) { print $str; } みたいな感じでいけると思うんだけど.

pick52
質問者

補足

ありがとうございます。 やはり、正規表現で一発というわけにはいかないでしょうかね。 前方一致やら後方一致なども考えたのですがなんか上手くでき なかったりして。 基本的には一つの文字列内に複数の変数が含まれているとします。 あと、上記の例では簡単にするために1行単位にしていますが実際には もっと処理が複雑で1行内に複数の変数が含まれていることもあります。 (gオプション付) マッチした部分を置換した行が結果的に ^(\s*\n?)$ であればその部分(改行含)は出力せず、それ以外なら出力させたい のです。 (因みに結果が 0 の場合は出力します) 連続の改行(及びマッチしていない行の空行)はそのまま出力します。 ^ と $ は行レベルでマッチしない(?)ようですし...。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

「削除する」というか, 「(置換した結果) 空白だけの行は出力しない」と書けばいいのでは?

pick52
質問者

補足

あ、まあ確かに結果的にはそうですね。 因みに、変数が書かれていないところは空白行でも正常に出力したいの です。 上記のテンプレートの部分が test $test $test2 test となっていたら test test test と出力したい。

関連するQ&A