私はこの正規表現を持っています:
if($string =~ m/^(Clinton|[^Bush]|Reagan)/i)
{print "$string\n"};
私はクリントンとレーガンにマッチしたいが、ブッシュにはマッチしたくない。
動いていない。
サンプルテキスト:
クリントンは言った
ブッシュはクレヨンを使用しました
レーガンは忘れました
ブッシュマッチを省略するだけです:
$ Perl -ne 'print if /^(Clinton|Reagan)/' textfile
Clinton said
Reagan forgot
または、本当に指定したい場合:
$ Perl -ne 'print if /^(?!Bush)(Clinton|Reagan)/' textfile
Clinton said
Reagan forgot
[]は文字クラスを定義しているため正規表現は機能しませんが、必要なのは先読みです:
(?=) - Positive look ahead assertion foo(?=bar) matches foo when followed by bar
(?!) - Negative look ahead assertion foo(?!bar) matches foo when not followed by bar
(?<=) - Positive look behind assertion (?<=foo)bar matches bar when preceded by foo
(?<!) - Negative look behind assertion (?<!foo)bar matches bar when NOT preceded by foo
(?>) - Once-only subpatterns (?>\d+)bar Performance enhancing when bar not present
(?(x)) - Conditional subpatterns
(?(3)foo|fu)bar - Matches foo if 3rd subpattern has matched, fu if not
(?#) - Comment (?# Pattern does x y or z)
だから試してください:(?!bush)
あなたの正規表現は次のように言っています:
/^ - if the line starts with
( - start a capture group
Clinton| - "Clinton"
| - or
[^Bush] - Any single character except "B", "u", "s" or "h"
| - or
Reagan) - "Reagan". End capture group.
/i - Make matches case-insensitive
つまり、言い換えれば、正規表現の中間部分はあなたを台無しにしています。これは「キャッチオール」グループの一種であるため、「ブッシュ」の大文字または小文字のいずれでも始まらない行を許可します。たとえば、次の行は正規表現に一致します。
Our president, George Bush
In the news today, pigs can fly
012-3123 33
前述のように、ネガティブな先読みを行うか、単に2つの正規表現を作成します。
if( ($string =~ m/^(Clinton|Reagan)/i) and
($string !~ m/^Bush/i) ) {
print "$string\n";
}
mirod がコメントで指摘しているように、キャレット(^
)「クリントン」または「レーガン」で始まる行が「ブッシュ」で始まることはないため、行の先頭のみに一致します。
ただし、キャレットがなくても有効です。
2つの正規表現(または3つ)の使用の何が問題になっていますか?これにより、意図がより明確になり、パフォーマンスが向上する場合があります。
if ($string =~ /^(Clinton|Reagan)/i && $string !~ /Bush/i) { ... }
if (($string =~ /^Clinton/i || $string =~ /^Reagan/i)
&& $string !~ /Bush/i) {
print "$string\n"
}
私の理解が正しければ、クリントンとレーガンを含む任意の行に一致しますが、ブッシュには一致しません。 Stuckが提案したように、先読みアサーション付きのバージョンは次のとおりです。
#!/usr/bin/Perl
use strict;
use warnings;
my $regex = qr/
(?=.*clinton)
(?!.*bush)
.*reagan
/ix;
while (<DATA>) {
chomp;
next unless (/$regex/);
print $_, "\n";
}
__DATA__
shouldn't match - reagan came first, then clinton, finally bush
first match - first two: reagan and clinton
second match - first two reverse: clinton and reagan
shouldn't match - last two: clinton and bush
shouldn't match - reverse: bush and clinton
shouldn't match - and then came obama, along comes mary
shouldn't match - to clinton with Perl
結果
first match - first two: reagan and clinton
second match - first two reverse: clinton and reagan
必要に応じて、レーガンとクリントンを任意の順序で含む任意の行に一致します。
http://www252.pair.com/comdog/mastering_Perl/Chapters/02.advanced_regular_expressions.html の例で先読みアサーションがどのように機能するかを読んでみてください。
彼らはとてもおいしいです:)