web-dev-qa-db-ja.com

grepとperlによるポジティブ/ネガティブな先読み

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パターンに何か欠けているものはありますか?

13

grepは、正規表現に対してチェックする文字列に改行を含めないため、abcが行の終わりにある場合、abc\sは一致しません。 Perlでchompするか、-lコマンドラインオプションを使用すると、同様の結果が表示されます。

Perlとgrepの正規表現の間で他の変更を行った理由がわかりません。 (?)は何を達成することになっていたのですか?

6
ysth

私はあなたの正規表現を次のように固定してみます:

/(^abc\s+(?!def).+)/

これはキャプチャします:

abc 123
abc de

(?)ネガティブな先読み正規表現の最初は冗長です

3
fugu

Perl -ne 'print if /(?)abc\s(?!def)/'で、Perlにabc、次にスペース、次に文字列をdefで検索するように要求します。ここではdefの後にabcがなく、def abcが改行と一致するため、これは\sと正常に一致します。

2
Oleg G
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)/'
0
Vinny