アプリ版:「スタンプのみでお礼する」機能のリリースについて

現在、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
----------

A 回答 (6件)

凝った方法はあるのかもしれんけど, そんなことより「思考をそのままソースに書く」ことの方が一般には重要.


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

この回答への補足

ありがとうございます。

こちらの説明不足と当初の想定していた仕様範囲の想定及び説明の
間違いなどがありまして、皆様にご迷惑をおかけして申し訳ありません。

皆様の回答を見ながらなんとか想定していたものを実現できたようです。

実際には &{~}& の範囲内を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;

こんな感じになりましたがもしかすると間違いがあるかもしれません。

補足日時:2008/07/30 15:09
    • good
    • 0

よく考えたら, そもそも「一発で全部やりたい」とする意味がわからん.


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

この回答への補足

ありがとうございます。

何とかできたようです(No3)。

補足日時:2008/07/30 15:13
    • good
    • 0

仕様がよくわかりません。

。。
・$に続く変数名っぽい文字列があれば、変数として展開
・空白行は削除(連続する改行は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

この回答への補足

ありがとうございます。

何とかできたようです(No3)。

補足日時:2008/07/30 15:11
    • good
    • 0

あまり洗練されていませんが、一番簡単なのは 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/
}
}

この回答への補足

ありがとうございます。

何とかできたようです(No3)。

補足日時:2008/07/30 15:09
    • good
    • 0

s/// で置換ができたかどうかはその値でわかりますから, 「置換ができて空白だけになった」場合を除いて出力すればいいのでは? 例えば


unless($str =~ s/// and $str =~ /^\s*$/) {
print $str;
}
みたいな感じでいけると思うんだけど.

この回答への補足

ありがとうございます。

やはり、正規表現で一発というわけにはいかないでしょうかね。
前方一致やら後方一致なども考えたのですがなんか上手くでき
なかったりして。

基本的には一つの文字列内に複数の変数が含まれているとします。
あと、上記の例では簡単にするために1行単位にしていますが実際には
もっと処理が複雑で1行内に複数の変数が含まれていることもあります。
(gオプション付)

マッチした部分を置換した行が結果的に

^(\s*\n?)$

であればその部分(改行含)は出力せず、それ以外なら出力させたい
のです。
(因みに結果が 0 の場合は出力します)

連続の改行(及びマッチしていない行の空行)はそのまま出力します。

^ と $ は行レベルでマッチしない(?)ようですし...。

補足日時:2008/07/29 22:21
    • good
    • 0

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

この回答への補足

あ、まあ確かに結果的にはそうですね。

因みに、変数が書かれていないところは空白行でも正常に出力したいの
です。

上記のテンプレートの部分が

test

$test
$test2
test

となっていたら

test

test
test

と出力したい。

補足日時:2008/07/29 18:12
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!