login.txtファイルには次のエントリが含まれています
abc def
abc 123
def abc
abc de
tha ewe
perlを使用して前向きな先読みを行うと、次の結果が得られます
cat login.txt | Perl -ne 'print if /(?)abc\s(?=def)/'
abc def
grepを使用すると、次の結果が得られます
cat login.txt | grep -P '(?<=abc)\s(?=def)'
abc def
perlとgrepから次のような否定的なlookahedの結果。
cat login | Perl -ne 'print if /(?)abc\s(?!def)/'
abc 123
def abc
abc de
grepの結果
cat login.txt | grep -P '(?<=abc)\s(?!def)'
abc 123
abc de
Perlは、ネガティブルックアヘッドのdefabcと一致しました。しかし、abcをチェックしてからdefパターンをチェックしているので、defabcと一致するべきではありません。 grepは正しい結果を返します。
私のPerlパターンに何か欠けているものはありますか?
grepは、正規表現に対してチェックする文字列に改行を含めないため、abcが行の終わりにある場合、abc\s
は一致しません。 Perlでchompするか、-lコマンドラインオプションを使用すると、同様の結果が表示されます。
Perlとgrepの正規表現の間で他の変更を行った理由がわかりません。 (?)
は何を達成することになっていたのですか?
私はあなたの正規表現を次のように固定してみます:
/(^abc\s+(?!def).+)/
これはキャプチャします:
abc 123
abc de
(?)
ネガティブな先読み正規表現の最初は冗長です
Perl -ne 'print if /(?)abc\s(?!def)/'
で、Perlにabc
、次にスペース、次に文字列をdef
で検索するように要求します。ここではdef
の後にabc
がなく、def abc
が改行と一致するため、これは\s
と正常に一致します。
Perl -ne 'print if /(?)abc\s(?!def)/'
まず、fugiが述べたように、(?)
は空の非キャプチャグループであり、何にでも一致するため、何もしません。
したがって、記述されているように、この正規表現は、リテラル文字列abc
の後に単一の[:space:OR:tab:OR:newline]
、 not の後にリテラル文字列def
が続くものと一致します。
\s
は改行文字と一致し、各行の処理時に末尾の改行文字を切り詰めなかったため、正規表現のdef abc
は(?)abc\s
と一致し、その後にabc[:newline:]
(行末アンカーが続く)と一致するため、$
は一致します。 not def
)。
修正された正規表現(冗長な(?)
を考慮)は次のようになります。
Perl -ne 'print if /(?<=abc)\s(?!def)/'
...これは、前にabc
と not の後にdef
が続く単一の[:space:OR:tab:OR:newline]
に一致します。
この still はdef abc
と一致します。これも、\s
が[:newline:]
と一致し、その前にabc
が続き、その後に$
(行末アンカーではなくdef
)。
Perlで正規表現を評価する前に[:newline:]
を選択するか、\s
の代わりに文字クラス[\ t](タブ文字を考慮する必要がある場合)を使用します。
Perl -ne 'print if /(?<=abc)[ \t](?!def)/'
または単に
Perl -ne 'print if /(?<=abc) (?!def)/'