web-dev-qa-db-ja.com

「実装されていない可変長ルックバック」は可変長ではありません

診断しようとしている非常にクレイジーな正規表現があります。また、非常に長いですが、次のスクリプトだけに短縮しました。 Strawberry Perl v5.26.2を使用して実行します。

use strict;
use warnings;

my $text = "M Y H A P P Y T E X T";
my $regex = '(?i)(?<!(Mon|Fri|Sun)day |August )abcd(?-i)';

if ($text =~ m/$regex/){
    print "true\n";
}
else {
    print "false\n";
}

これにより、「可変長の後読みが正規表現に実装されていません」というエラーが発生します。

いくつかの問題を解決できることを願っています。

  1. 可能性のある後読み値はすべて「Monday」、「Friday」、「Sunday」、「August」の7文字であるため、このエラーが発生する理由はわかりません。
  2. 私はこの正規表現を自分で書いたわけではなく、構文(?i)(?-i)の解釈方法がわかりません。 (?i)を取り除くと、実際にエラーはなくなります。 Perlは正規表現のこの部分をどのように解釈しますか?最初の2文字は「オプションのリテラル括弧」と評価されますが、括弧はエスケープされず、その場合は閉じ括弧が一致しないため、別の構文エラーが発生します。
  3. この動作は、少なくともStrawberry Perlでは、Perl 5.16.3_64と5.26.1_64の間のどこかで始まります。前者のバージョンはコードには問題ありませんが、後者はそうではありません。なぜ始まったのですか?
56
Stephen

私はあなたの問題をこれに減らしました:

my $text = 'M Y H A P P Y T E X T';
my $regex = '(?<!st)A';
print ($text =~ m/$regex/i ? "true\n" : "false\n");

/i(大文字と小文字を区別しない)修飾子の存在と、 Typographic_ligature で置き換えることができる"ss""st"などの特定の文字の組み合わせの存在により可変長である(/August/iは、たとえばAUGUST(6文字)とaugust(5文字、最後はU + FB06)の両方に一致します)。

ただし、/i(大文字と小文字を区別しない)修飾子を削除すると、活版印刷の合字が一致しないため機能します。

解決策:aa修飾子を使用します。つまり:

/(?<!st)A/iaa

または正規表現で:

my $text = 'M Y H A P P Y T E X T';
my $regex = '(?<!(Mon|Fri|Sun)day |August )abcd';
print ($text =~ m/$regex/iaa ? "true\n" : "false\n");

perlre から:

ASCIIと非ASCIIの一致(「\ N {KELVIN SIGN}」と「k」など)を禁止するには、「a」を2回指定します(例:/aaiまたは/aia)。 (最初の「a」の出現は\dなどを制限し、2番目の出現は「/ i」の制限を追加します。)ただし、ASCIIの範囲外のコードポイントは/iマッチングのUnicodeルール。したがって、修飾子は実際にはASCIIだけに制限しません。 ASCIIと非ASCIIの混合を禁止します。

ここで密接に関連する議論を参照してください

76
anubhava

stが合字になる可能性があるためです。同じことがfiffにも起こります:

#!/usr/bin/Perl
use warnings;
use strict;

use utf8;

my $fi = 'fi';
print $fi =~ /fi/i;

fi|fiのようなものを想像してください。実際、代替の長さは同じではありません。

21
choroba

(?i)後読み後:

(?<!(Mon|Fri|Sun)day |August )(?i)abcd(?-i)

または

(?<!(Mon|Fri|Sun)day |August )(?i:abcd)

私にはそれはバグのようです。

0
Hegel F.