貪欲な量指定子とあまり一致しないように正規表現を修正するにはどうすればよいですか? [複製]
-
05-07-2019 - |
質問
この質問にはすでに回答があります:
次の行があります:
"14:48 say;0ed673079715c343281355c2a1fde843;2;laka;hello ;)"
単純な正規表現を使用してこれを解析します:
if($line =~ /(\d+:\d+)\ssay;(.*);(.*);(.*);(.*)/) {
my($ts, $hash, $pid, $handle, $quote) = ($1, $2, $3, $4, $5);
}
しかし;最後に物事を台無しにし、私は理由がわかりません。貪欲なオペレーターは「すべて」を処理すべきではありませんか?
解決
貪欲な演算子は、可能な限り多くのものを取得しようとし、それでも文字列と一致します。何が起こっているのは、最初の(「say」の後)グラブ「0ed673079715c343281355c2a1fde843; 2」で、2番目は「laka」、3番目は「hello」を見つけます。 4番目は括弧に一致します。
あなたがする必要があるのは、最後の1つを除いてすべてを貪欲ではないようにすることです。
(\d+:\d+)\ssay;(.*?);(.*?);(.*?);(.*)
他のヒント
(\d+:\d+)\ssay;([^;]*);([^;]*);([^;]*);(.*)
より良く動作するはず
正規表現はこれを簡単に行うことができますが、それが最も簡単なアプローチであるかどうかはわかりません。おそらく最短ですが、実際には最もメンテナンスしやすいものにはなりません。
代わりに、次のようなものを提案します:
$x="14:48 say;0ed673079715c343281355c2a1fde843;2;laka;hello ;)";
if (($ts,$rest) = $x =~ /(\d+:\d+)\s+(.*)/)
{
my($command,$hash,$pid,$handle,$quote) = split /;/, $rest, 5;
print join ",", map { "[正規表現はこれを簡単に行うことができますが、それが最も簡単なアプローチであるかどうかはわかりません。おそらく最短ですが、実際には最もメンテナンスしやすいものにはなりません。
代わりに、次のようなものを提案します:
[14:48],[say],[0ed673079715c343281355c2a1fde843],[2],[laka],[hello ;)]
結果:
<*>
これはもう少し読みやすいと思います。それだけでなく、人間がペンと紙を使って同じことをしようとした場合の方法に近いため、デバッグと保守も簡単だと思います。文字列をチャンクに分割すると、簡単に解析できるようになります。コンピューターに正確に実行してもらいます。修正するときが来たら、これはもっとうまくいくと思います。 YMMV。
]" } $ts,$command,$hash,$pid,$handle,$quote
}
結果:
<*>これはもう少し読みやすいと思います。それだけでなく、人間がペンと紙を使って同じことをしようとした場合の方法に近いため、デバッグと保守も簡単だと思います。文字列をチャンクに分割すると、簡単に解析できるようになります。コンピューターに正確に実行してもらいます。修正するときが来たら、これはもっとうまくいくと思います。 YMMV。
最初の3つの(。*)
を欲張らない(。*?)
セミコロンで区切られたリストの値にセミコロン自体を含めることができない場合、それをつづるだけで最も効率的で簡単な正規表現が得られます。特定の値が16進文字列などにしかなれない場合、それを綴ります。遅延ドットまたは貪欲なドットを使用するソリューションでは、正規表現が件名文字列と一致しない場合、常に多くの無駄なバックトラックが発生します。
(\d+:\d+)\ssay;([a-f0-9]+);(\d+);(\w+);([^;\r\n]+)
疑問符を追加することで*貪欲でないようにすることができます:
$line =~ /(\d+:\d+)\ssay;(.*?);(.*?);(.*?);(.*)/
または最後の部分を除く各部分のセミコロンを除くすべてに一致させることができます:
$line =~ /(\d+:\d+)\ssay;([^;]*);([^;]*);([^;]*);(.*)/