"Variable length lookbehind가 구현되지 않았지만"가변 길이가 아닙니다.
진단하려는 매우 미친 정규식이 있습니다. 또한 매우 길지만 다음 스크립트로 줄였습니다. 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";
}
이로 인해 "정규식에서 구현되지 않은 가변 길이 lookbehind"오류가 발생합니다.
몇 가지 문제에 대해 도움을 주시면 감사하겠습니다.
- 가능한 모든 lookbehind 값이 "Monday", "Friday", "Sunday", "August"의 7 자이기 때문에이 오류가 발생하는 이유를 알 수 없습니다.
- 이 정규식을 직접 작성하지 않았으며 구문
(?i)
및(?-i)
. 내가 제거(?i)
하면 오류가 실제로 사라집니다. Perl은 정규식의이 부분을 어떻게 해석할까요? 괄호가 이스케이프되지 않고 닫는 괄호가 일치하지 않기 때문에 다른 구문 오류가 발생한다는 점을 제외하면 처음 두 문자는 "선택적 리터럴 괄호"로 평가됩니다. - 이 동작은 Perl 5.16.3_64와 5.26.1_64 사이, 적어도 Strawberry Perl에서 시작됩니다. 전자 버전은 코드에 문제가없고 후자는 그렇지 않습니다. 왜 시작 되었나요?
나는 당신의 문제를 이것으로 줄였습니다.
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
(케이스 둔감)과 같은 특정 문자 조합 개질제의 존재 "ss"
또는 "st"
하는 교체 할 수 Typographic_ligature 가 (가변 길이되게 /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"를 두 번 지정하십시오 (예 :
/aai
또는)/aia
. ( "a"의 첫 번째 발생은\d
, 등을 제한하고 두 번째 발생은 "/ i"제한을 추가합니다.) 그러나 ASCII 범위 밖의 코드 포인트는/i
일치에 유니 코드 규칙을 사용 하므로 수정자는 그렇지 않습니다. 정말 ASCII로만 제한합니다. 그것은 단지 ASCII와 non-ASCII의 혼합을 금지합니다 .
st
합자가 될 수 있기 때문 입니다. 동일은 어떻게됩니까 fi
과 ff
:
#!/usr/bin/perl
use warnings;
use strict;
use utf8;
my $fi = 'fi';
print $fi =~ /fi/i;
따라서 fi|fi
실제로 대안의 길이가 동일하지 않은 경우를 상상해보십시오 .
st
1 자 스타일 합자 로 st
또는로 표시 ſt
될 수 있으므로 길이는 2 또는 1이 될 수 있습니다.
bash 명령을 사용하여 perl의 2 → 1 자 합자 전체 목록을 빠르게 찾습니다.
$ perl -e 'print $^V'
v5.26.2
$ for lig in {a..z}{a..z}; do \
perl -e 'print if /(?<!'$lig')x/i' 2>/dev/null || echo $lig; done
ff fi fl ss st
이들은 각각 대표 ff
, fi
, fl
, ß
, 및 st
/ ſt
합자.
( ſt
대표 ſt
오래된 사용, 긴의 문자를 , 그것은 일치 st
하고 않습니다 하지 일치 ft
.)
펄은 또한 남아있는 문체 합자를 지원 ffi
하고 ffl
대한 ffi
및 ffl
lookbehinds 이미 문제를 갖고 있기 때문에 문제는이 맥락에서 주목할만한 것은 아니지만, ff
및 fi
/ fl
별도.
Future releases of perl may include more stylistic ligatures, though all that remain are font-specific (e.g. Linux Libertine has stylistic ligatures for ct
and ch
) or debatably stylistic (such as the Dutch ij
for ij
or the obsolete Spanish ꝇ
for ll
). It doesn't seem appropriate to have this treatment for ligatures that are not entirely interchangeable (nobody would accept dœs
for does
), though there are other scenarios, such as including ß
thanks to its uppercase form being SS
.
Perl 5.16.3 (and similarly old versions) only stumble on ss
(for ß
) and fail to expand the other ligatures in lookbehinds (they have fixed width and will not match). I didn't seek out the bugfix to itemize exactly which versions are affected.
Perl 5.14 introduced ligature support, so earlier versions don't have this problem.
Workarounds
Workarounds for /(?<!August)x/i
(only the first will properly avoid August
):
/(?<!Augus[t])(?<!Augu(?=st).)x/i
(absolutely comprehensive)/(?<!Augu(?aa:st))x/i
(just thest
in the lookbehind is "ASCII-safe" ²)/(?<!(?aa)August)x/i
(the whole the lookbehind is "ASCII-safe" ²)/(?<!August)x/iaa
(the whole regex is "ASCII-safe" ²)/(?<!Augus[t])x/i
(breaks ligature seeking ¹)/(?<!Augus.)x/i
(slightly different, matches more)/(?<!Augu(?-i:st))x/i
(case-sensitivest
in lookbehind, won't matchAugusTx
)
These toy with removing the case-insensitive modifier¹ or adding the ASCII-safe modifier² in various places, often requiring the regex writer to specifically know of the variable-width ligature.
The first variation (which is the only comprehensive one) matches the variable widths with two lookbehinds: first for the six character version (no ligatures as noted in the first quote below) and second for any ligatures, employing a forward lookahead (which has zero width!) for st
(including the ligatures) and then accounting for its single character width with a .
Two segments of the perlre
man page:
¹ Case-insensitive modifier /i
& ligatures
There are a number of Unicode characters that match a sequence of multiple characters under
/i
. For example, "LATIN SMALL LIGATURE FI" should match the sequencefi
. Perl is not currently able to do this when the multiple characters are in the pattern and are split between groupings, or when one or more are quantified. Thus"\N{LATIN SMALL LIGATURE FI}" =~ /fi/i; # Matches [in perl 5.14+] "\N{LATIN SMALL LIGATURE FI}" =~ /[fi][fi]/i; # Doesn't match! "\N{LATIN SMALL LIGATURE FI}" =~ /fi*/i; # Doesn't match! "\N{LATIN SMALL LIGATURE FI}" =~ /(f)(i)/i; # Doesn't match!
² ASCII-safe modifier /aa
(perl 5.14+)
To forbid ASCII/non-ASCII matches (like
k
with\N{KELVIN SIGN}
), specify thea
twice, for example/aai
or/aia
. (The first occurrence ofa
restricts the\d
, etc., and the second occurrence adds the/i
restrictions.) But, note that code points outside the ASCII range will use Unicode rules for/i
matching, so the modifier doesn't really restrict things to just ASCII; it just forbids the intermixing of ASCII and non-ASCII.To summarize, this modifier provides protection for applications that don't wish to be exposed to all of Unicode. Specifying it twice gives added protection.
Put (?i)
after lookbehind:
(?<!(Mon|Fri|Sun)day |August )(?i)abcd(?-i)
or
(?<!(Mon|Fri|Sun)day |August )(?i:abcd)
To me it seems to be a bug.
'programing' 카테고리의 다른 글
Python 3의 zip () 함수 (0) | 2020.12.30 |
---|---|
Kotlin에서 동시에 확장 및 구현 (0) | 2020.12.30 |
++ * ptr ++는 C ++에서 정의되지 않은 동작입니까? (0) | 2020.12.30 |
http 요청을 기반으로 웹 애플리케이션에서 모바일 브라우저를 감지하는 표준 방법 (0) | 2020.12.30 |
객체와 해시의 차이점은 무엇입니까? (0) | 2020.12.30 |