11

たとえば、次の文字列を含む行があるとします。

「$トム」は何とか何とか言った。「$dick」は「何とか何とか」と言った。「$ハリー」は何とか何とか言った。

そして抽出したい

「$dick」は「何とか何とか」と言った

次のコードがあります。

my ($term) = /(".+?" said ".+?")/g;
print $term;

しかし、それは私が必要とする以上のものを私に与えてくれます:

「$トム」は何とか何とか言った。「$dick」は「何とか何とか」と言った

非キャプチャ括弧を使用して、パターン全体をグループ化してみました。

my ($term) = /((?:".+?" said ".+?"))/g;

しかし、問題は解決しません。

Learning Perl の Nongreedy Quantifiers セクションを読み直しましたが、今のところ何もわかりません。

寛大に提供できるガイダンスをありがとう:)

4

4 に答える 4

19

問題は、貪欲ではありませんが、それでも挑戦し続けることです。正規表現は表示されません

"$tom" said blah blah blash.

「ああ、「言った」に続くものは引用されていないので、それをスキップします」と考えます。それは、「まあ、"said" の後の部分は引用されていないので、引用の一部であるに違いない」と考えます。だから".+?"マッチ

"$tom" said blah blah blash.  "$dick"

あなたが欲しいのはです"[^"]+"。これは、引用符以外のものを囲む 2 つの引用符に一致します。したがって、最終的な解決策:

("[^"]+" said "[^"]+")
于 2009-10-21T05:57:21.320 に答える
3

残念ながら"、慎重に扱う必要があるほど独特なキャラクターです。使用する:

my ($term) = /("[^"]+?" said "[^"]+?")/g;

そして、それはうまくいくはずです(私にとってはそうです...!)。つまり、任意の文字のシーケンスではなく、「非二重引用符」のシーケンスに明示的に一致します。

于 2009-10-21T06:00:16.950 に答える
3

他の人はこれを修正する方法について言及しています。

これをデバッグする方法についてお答えします。さらにキャプチャを使用すると、何が起こっているかを確認できます。

 bash$ cat story | perl -nle 'my ($term1, $term2, $term3) = /(".+?") (said) (".+?")/g ; 
      print "term1 = \"$term1\" term2 = \"$term2\" term3 = \"$term3\" \n"; '
 term1 = ""$tom" said blah blah blash.  "$dick"" term2 = "said" term3 = ""blah blah blah""
于 2009-10-21T06:01:04.153 に答える
2

ここでの問題は、正規表現に一致する可能性のあるものが2つあることです。1つは必要なもの(短いもの)で、もう1つは正規表現エンジンが選択するものです。エンジンは、文字列の早い段階で開始され、後で開始されて短い一致よりも長い一致を優先するため、その特定の一致を選択します。言い換えれば、早い試合は短い試合に勝ちます。

これを解決するには、正規表現をより具体的にする必要があります($ termに引用符を含めないようにエンジンに指示する場合など。とにかく、正規表現をできるだけ具体的にすることをお勧めします。

正規表現に関する詳細と落とし穴については、JeffreyFriedlの優れた本「MasteringRegularExpressions 」をお勧めします。

于 2009-10-25T21:27:27.063 に答える