1

不要な一致を消費/スキップする方法は?

次のテキストがあるとします。

my $t ='good good *bad !bad -bad "alwaysbad alwaysbad alwaysbad" good';

good単語のみに一致する単一の正規表現が必要です。もちろん、記号語goodbad、およびの実際の内容は(この質問では問題ありません) です。単語と単語を区別するには、単語の先頭のようなもので十分です。プレフィックスがなくても、二重引用符で囲まれたものは常に悪い言葉です。alwaysbad[0-9A-Za-z_@]+\w+badgood(\s|^)\b\w

これは私が持っているものです:

my $r = qr/
           (?: " [^"]+ " )     # skip quoted part altogether, don't capture
            |                  # OR
           (?<!\S) \b ([\w@]+) # find words without 'bad' prefix and capture
          /x;

この式は引用部分をキャプチャしませんが、それでも一致します。したがって、undefined一致リストには空のエントリがあります。

my @matches = $t =~ /$r/g;

print join "\n", @matches;

  good
  good
         <== (uninitialized value, this comes from the quoted part)
  good

今質問:

文字列の特定の部分を消費するが、それを単一の正規表現呼び出しと一致させない方法を現代のperl正規表現に適用できる手法を知っている人はいますか?

したがって、結果は次のようになります。

  good
  good
  good


補遺:

ボロディンの回答のおかげで、よりはっきりと見えるようになりました。(or) を削除して量指定子|を適用するだけor-zero-timesで機能します。

my $r = qr/
           (?: " [^"]+ ")? \s?  # skip quotes + space if any
           (?<!\S) \b ([\w@]+)  # find words without 'bad' prefix and capture
          /x;
4

2 に答える 2

2

あなたの正規表現は、それがあなたが望んでいたものだと言ったので、非キャプチャシーケンスにのみ一致しています。

次のように、引用符以外の文字を間に挟んで、任意の数の引用符で囲まれた文字列のオプションのプレフィックスを記述します。

my $r = qr/
  (?: " [^"]* " [^"]*?)*    # skip quoted part altogether, don't capture
  (?<!\S) \b (\w+)          # find words without 'bad' prefix and capture
/x;

しかし、明確にするために、ターゲットに一致させる前に、引用符で囲まれたすべての文字列をターゲットから削除します。@部分文字列でも許可したい場合は、 が必要であることを忘れないでください[\w@]。また、先頭のに無効な文字がないことを確認するために、末尾のチェックも必要です。

$t =~ s/"[^"]*"//g;
my @matches = $t =~ /(?:\s|^)[\w\@]+(?=\s|\z)/g;
于 2012-07-31T12:23:45.460 に答える
1

それらを除外することができます:

my @matches = grep { m/\S/ } $t =~ /$r/g;
于 2012-07-31T12:24:49.407 に答える