아무것도 일치하지 않는 정규식


131

이것은 어리석은 질문처럼 들릴지 모르지만 동료 개발자들과 오랫동안 이야기를 나누었으며 재미있는 생각처럼 들렸습니다.

그래서; 당신의 생각은 무엇입니까-Regex는 어떻게 생겼으며, 어떤 문자열과도 일치하지 않습니다!

편집 : 왜 내가 이것을 원합니까? 글쎄, 첫 번째는 그런 표현을 생각하는 것이 흥미롭고 두 번째는 스크립트에 필요하기 때문입니다.

그 스크립트에서 나는 사전을 다음과 같이 정의합니다. Dictionary<string, Regex> . 여기에는 문자열과 표현식이 포함되어 있습니다.

해당 사전을 기반으로 모든 사람이 작업을 수행하는 방법에 대한 참조로만이 사전을 사용하는 메소드를 작성합니다.이 중 하나는 구문 분석 된 로그 파일에 대한 정규식과 일치합니다.

식이 일치하면 다른 식 Dictionary<string, long> 하면 식에 의해 반환되는 값이 추가됩니다. 따라서 사전의 식과 일치하지 않는 로그 메시지를 포착하기 위해 "unknown"이라는 새 그룹을 만들었습니다.

이 그룹에는 다른 것과 일치하지 않는 모든 것이 추가됩니다. 그러나 "알 수없는"식이 실수로 로그 메시지와 일치하지 않도록하려면 문자열에 관계없이 가장 확실하게 일치하지 않는 식을 만들어야했습니다.

따라서, 당신은이 "진짜 질문이 아닙니다"에 대한 나의 이유가 있습니다 ...


1
부정적인 것을 증명하는 것은 매우 어렵다는 점에 유의하십시오.
Lasse V. Karlsen

5
흥미 롭군 그런 정규식을 어디에서 사용 하시겠습니까?
Charlie Salts

1
위에서 언급 한 많은 의견들과이 질문에 대한 답변은 원래 stackoverflow.com/questions/1845078/… 에서 온 것이라는 기록에 주목할 것입니다 . Marc Gravell은 이들 의견을 합병했는데,이 답변 중 많은 부분이 정확한 원래의 맥락없이 기괴한 것으로 생각하기 때문에 일부 의견은 의미가없는 것으로 보입니다. (아마도 미래의 잠재적 인 담당자를 훔칠 수도 있습니다.) 그런 상세한 배경을 가진 질문은 결코 "정확한 복제본"이 될 수 없습니다. 무엇이든 ...
Peter Hansen

2
이 질문은 "Advanced Regex-Fu"아래 의 Stack Overflow Regular Expressions FAQ 에 추가되었습니다 .
aliteralmind

3
"음성을 증명하는 것은 매우 어렵다는 점에 유의하십시오."-유클리드가 가장 큰 소수가 없다는 것을 증명 한 이래로 우리가 알고 있듯이 이것은 광범위하게 믿어 지지만 완전히 거짓입니다. 그리고 P의 증거는 (P가 아닌) 부정의 증거입니다. 사실은 경험적으로 보편적이고 긍정적이거나 부정적인 것으로 증명하기가 어렵다는 것입니다. 예를 들어 "모든 까마귀는 검은 색입니다"또는 "까마귀는 흰색이 없습니다". 알고리즘은 경험적이 아닌 분석적이므로, 이는 가짜 규칙의 잘못된 적용입니다. 예를 들어, 패턴 'a'가 'b'로 시작하는 문자열과 일치하지 않는다는 증거는 "매우 어렵지 않습니다".
Jim Balter

답변:


66

구현 / 플래그 * 에 따라 다르지만 실제로는 매우 간단합니다 .

$a

a문자열 끝 이후의 문자와 일치 합니다. 행운을 빕니다.

경고 :
이 표현식은 비용이 많이 듭니다. 전체 행을 스캔하고 행 끝 앵커를 찾은 다음에 만 a일치하는 값을 찾지 못하고 리턴합니다. (자세한 내용은 아래 주석을 참조하십시오.)


* 원래 나는 줄 $의 끝과도 일치하는 멀티 라인 모드 정규 표현식에 대해 많이 생각하지 않았습니다 . 실제로, 그것은 개행 직전 의 빈 문자열과 일치 하므로 일반 문자는 a뒤에 나타날 수 없습니다 $.


50
이 표현식은 비용이 많이 듭니다. 전체 라인을 스캔하고 라인 끝 앵커를 찾은 다음 "a"를 찾지 않고 음의 일치를 반환합니다. ~ 275k 라인 파일을 스캔하는 데 ~ 480ms가 걸립니다. 대화식 "a ^"는 더 효율적으로 보일지라도 거의 같은 시간이 걸립니다. 반면, 부정적 예측은 "(?! x) x"(x 다음에 x와 뒤에 x가없는 것)가 아무것도 스캔하지 않아도됩니다. 약 30ms 또는 7 % 미만이 소요됩니다. (gnu 시간과 egrep.로 측정)
arantius

1
Perl에서 현재 값과 일치합니다 $a. 펄에 상응 $(?:a)하는 것도 매우 느립니다 perl -Mre=debug -e'$_=a x 50; /$(?:a)/'.
Brad Gilbert

@arantius 참조하십시오 타이밍에 대한 내 대답을 내가 측정 정반대 발견, timeitpython3.
nivk

6 년이 걸리고 주요 버전의 파이썬이 상황을 바꿀 수 있다는 것은 놀라운 일이 아닙니다.
arantius

1
POSIX BRE 구문에서는 해당 패턴의 앵커로 유효하지 않기 때문에 $a리터럴 텍스트와 일치합니다 . $a$
Phils

76

활용 negative lookahead:

>>> import re
>>> x=r'(?!x)x'
>>> r=re.compile(x)
>>> r.match('')
>>> r.match('x')
>>> r.match('y')

이 RE는 용어의 모순이므로 절대로 일치하지 않습니다.

참고 :
Python에서 re.match ()\A 는 정규 표현식의 시작 부분에 문자열 시작 앵커 ( )를 암시 적으로 추가합니다 . 이 앵커는 성능에 중요합니다.이 앵커가 없으면 전체 문자열이 스캔됩니다. 파이썬을 사용하지 않는 사람들은 앵커를 명시 적으로 추가하려고합니다.

\A(?!x)x

@Chris, yep 등- (?=x)(?!x)(모순 된 예측의 연결 및 lookbehinds의 경우도 마찬가지 임) 많은 x것들도 임의의 값으로 작동합니다 (lookbehinds x는 고정 길이의 문자열과 일치하는 s가 필요합니다 ).
Alex Martelli

1
잘 작동하는 것 같습니다. 그러나 대신 (?!)는 어떻습니까? ()가 항상 일치하므로 (?!)가 일치하지 않을 것이라고 보장하지 않습니까?
Peter Hansen

2
@Peter, 그렇습니다. 파이썬이 그 구문을 받아들이고 (최근 릴리스가 나타나는 것처럼 보인다면), 그것은 또한 모순 될 것입니다. 또 다른 아이디어 (매우 우아하지는 않지만 더 많은 아이디어를 얻을수록 관심있는 모든 RE 엔진에서 작동하는 아이디어를 찾을 수 있습니다) :r'a\bc' , 즉시 양쪽에 문자로 둘러싸인 단어 경계를 찾습니다 (변형 : 비 단어 양쪽).
Alex Martelli

1
흥미롭게도, 내가 알고있는 간단한 리터럴을 가진 나의 원본은 파이썬에서 가장 빠르다. 5MB 입력 문자열을 사용하고이를 sub () 연산에서 사용하면 (?! x) x는 21 % 더 오래 걸리고 (?! ())는 16 %, ($ ^) 6 % 더 깁니다. 내 경우는 아니지만 경우에 따라 중요 할 수 있습니다.
Peter Hansen

2
꽤 느려질 수 있습니다 perl -Mre=debug -e'$_=x x 8; /(?!x)x/'. 처음 \A(?!x)x또는 끝에 고정하여 더 빠르게 만들 수 있습니다 (?!x)x\z. perl -Mre=debug -e'$_=x x 8; /(?!x)x\z/; /\A(?!x)x/'
Brad Gilbert

43

놓친 것 :

^\b$

빈 문자열에 단어 경계가 없기 때문에 일치하지 않습니다. 파이썬 2.5에서 테스트되었습니다.


7
이것이 가장 좋은 대답입니다. lookaheads를 사용하지 않고 일부 정규식 구현에서 깨지거나 특정 문자 (예 : 'a')를 사용하지 않으며 전체를 스캔하지 않고 최대 3 개의 처리 단계 (regex101.com에 따라)에서 실패합니다 입력 문자열. 이것도 한눈에 이해하기 쉽습니다.
CubicleSoft

1
버퍼의 시작 또는 끝에 빈 줄이있는 경우 Emacs에서 실제로 실패하지만 \`\b\'"시작 / 종료"와 반대로 "텍스트의 시작 / 종료"를 Emacs 구문으로 대체합니다. 줄) ").
Phils

35

둘러보세요 :

(?=a)b

정규 표현식 초보자의 경우 : 긍정적 인 모습 (?=a)은 다음 문자가 a이지만 검색 위치를 변경하지는 않습니다 (또는 일치하는 문자열에 'a'포함). 이제 다음 문자가 확인 a되었으므로 b다음 문자가있는 경우에만 정규식 ( ) 의 나머지 부분이 일치합니다 b. 따라서이 정규 표현식은 문자가 모두있는 경우에만 일치 ab동시에.


30

a\bc여기서 \b단어 경계와 일치하는 너비가 0 인 표현식입니다.

그것은 단어의 한가운데서 나타날 수 없으며, 우리는 그것을 강요합니다.


유스 케이스를 사용하여 패턴을 문자열의 시작 부분에 고정시킬 수 있으면 정규 표현식 엔진 a이 텍스트 의 모든 인스턴스를 검색하고 테스트하지 못하게 됩니다.
Phils

20

$.

.^

$.^

(?!)


1
귀엽다! 내 잠재 의식은 처음 세 가지와 같은 아이디어에서 멀어지게했다. 왜냐하면 개념적으로는 "정규적"이기 때문이다. 나는 (!) 것을 인식하지 못합니다 ... 그것을 찾아야합니다.
Peter Hansen

1
좋아, 나는 (?!) 답변을 좋아한다 ... Alex가 제안한 것을 효과적으로. stackoverflow.com/questions/1723182 (위의 Amarghosh 에 의해 지적 됨)에서 누군가는 정규식의 "일부 맛"이 구문 오류를 고려할 것이라고 주장합니다. 파이썬은 그것을 좋아합니다. 파이썬의 re.DOTALL | re.MULTILINE 모드에서는 다른 제안이 모두 실패합니다.
Peter Hansen

1
이것이 테스트 되었습니까? 정규 표현식이 여러 줄 표현식이 아닌 한 정규 표현식 ^의 첫 번째 문자로 $특별한 의미 만 있고 정규 표현식의 끝에 특별한 의미 가 있다고 가정했습니다 .
PP.

실제로 Perl에서는 /$./완전히 다른 것을 의미합니다. $.(입력 라인 번호) 의 현재 값과 일치 함을 의미합니다 . 비록 /$(.)/당신이 쓴 경우 뭔가를 일치 수 use re '/s';그것을하기 전에. ( perl -E'say "\n" =~ /$(.)/s || 0')
브래드 길버트

POSIX BRE 구문에서, ^그리고 $, 패턴의 시작과 (각각) 끝에 만 특별 아무도 그렇게 $.하거나 .^또는 $.^작동합니다. (?!)펄 / PCRE 기능이라고 생각합니다.
Phils

13

최대 매칭

a++a

역 추적없이 최소 하나 a뒤에 임의의 숫자가옵니다 a. 그런 다음 하나 더 일치 시키십시오 a.

또는 독립적 하위 표현

이것은 a+독립적 인 하위 표현식을 입력 한 다음 다른 하위 표현식을 입력하는 것과 같습니다 a.

(?>a+)a

10

Perl 5.10은 "동사"라는 특수 제어 단어를 지원하며 (*...)순서대로 묶습니다 . ( (?...)특수 순서 와 비교하십시오 .) 그중에 는 정규 표현식에서 즉시 리턴 하는 (*FAIL)동사 가 포함되어 있습니다.

동사는 PCRE에서도 곧 구현되므로 PCRE 라이브러리를 사용하여 PHP 또는 다른 언어로도 사용할 수 있습니다. (그러나 파이썬이나 루비에서는 사용할 수 없습니다. 그들은 자체 엔진을 사용합니다.)


perldoc.perl.org/perlre.html#%28%2AFAIL%29-%28%2AF%29 의 문서는 "이 패턴은 아무 것도 일치하지 않으며 항상 실패합니다. (?!)와 동일하지만 더 쉽습니다. 실제로, (?!)는 내부적으로 (* FAIL)로 최적화됩니다. " 흥미로운 점은 (?!)가 지금까지 내가 가장 좋아하는 "순수한"대답입니다 (Javascript에서는 작동하지 않더라도). 감사.
Peter Hansen

10
\B\b

\b단어 경계-문자 사이의 위치와 문자가 아닌 문자 (또는 문자열 경계)와 일치합니다.
\B그것의 보완-그것은 두 글자 사이 또는 비 문자 사이의 위치와 일치합니다.

함께 그들은 어떤 위치와도 일치 할 수 없습니다.

또한보십시오:


이것은 훌륭한 솔루션처럼 보인다 제공 이 특정 지점 (텍스트의 시작 합리적인 것 같다)에 고정합니다. 그렇게하지 않으면 텍스트의 모든 단어 경계가 단어 경계를 따르는 지 테스트하기 때문에 끔찍한 해결책입니다 ! 따라서 합리적인 버전은 다음과 같습니다 . "텍스트의 시작"과 "라인의 시작"이 다른 구문을 갖는 언어에서는 "텍스트의 시작"구문을 사용하려고합니다. 그렇지 않으면 모든 행을 테스트합니다. (예 : Emacs에서는 또는) .^\B\b\`\B\b"\\`\\B\\b"
Phils

즉,이 질문의 명시된 목적은 그룹에서 사용할 정규 표현식을 얻는 것입니다.이 경우 첫 번째 문자 일 때 앵커 만있는 ^특정 정규 표현식 구문 (예 : POSIX BRE)에서 문제 ^가됩니다. 패턴과 일치하지 않으면 리터럴 ^문자 와 일치합니다 .
Phils

@phils-나는 당신이 그것을 과잉 생각하고 있다고 생각합니다 :)-이것은 실제적인 질문이 아니며, 목표는 재미있는 답변을 찾는 것이 었습니다-효율적인 답변은 아닙니다. 즉, 패턴은 라이너 시간 (대상 문자열의 크기와 함께)에서 거부 될 수 있으므로 정규 표현식에는 나쁘지 않습니다. 여기서 대부분의 패턴은 동일하며 ^최적화되지 않으면 선형 일 수도 있습니다.
Kobi

다시 : 최적화, 나는 다른 위치에서 "텍스트의 시작"을 찾을 희망 정규식 엔진을 무시하고 기꺼이 :)
phils

또한 그렇게 비현실적인 Q & A는 아닙니다. 여기서 내가 마무리 한 유일한 이유는 누군가 정규 표현식 값 을 필요 로 하는 특정 Emacs 변수를 구성하는 실용적인 목적으로 내 자신에게보다 효율적인 솔루션을 제안 할 수 있는지 확인하는 것이 었습니다. 효과적으로 비활성화하고 싶었습니다.
Phils

8

이것은 작동하는 것 같습니다 :

$.

2
Ferdinand Beyer의 예와 비슷합니다.
Gumbo

9
그리고 도트 일치 줄 바꿈 모드에서 일치합니다.
Tim Pietzcker 2009

Perl에서는 현재 입력 라인 번호와 실제로 일치합니다 $.. 이 경우에는 $(.)동등 하게 또는 그 이상 으로 의지해야 합니다 $(?:.).
Brad Gilbert

POSIX BRE 구문에서는 해당 패턴의 앵커로 유효하지 않기 때문에 $.리터럴과 문자가 일치합니다 . $$
Phils

8

어때 $^아니면 (?!)


3
줄 바꿈은 줄 ^의 시작과 $끝이 일치하는 모드에서이 표현식 과 일치합니다 .
Gumbo

4
아마도 그는 (?!)빈 문자열에 대한 부정적인 전망 을 의미했을 것 입니다. 그러나 일부 정규 표현식은 구문 오류로 취급합니다.
Alan Moore

1
빈 문자열은 적어도 JavaScript에서 첫 번째 문자열과 일치합니다.
Roland Pihlakas

POSIX BRE 구문에서는 $^문자가 앵커로 유효하지 않기 때문에 해당 리터럴 문자와 일치합니다 (즉, 패턴을 사용한 이유 때문에 원하는 것을 수행하지 못합니다)
phils

5

가장 빠른 방법은 다음과 같습니다.

r = re.compile(r'a^')
r.match('whatever')

'a'는 특수 문자가 아닌 문자 ( 'x', 'y') 일 수 있습니다. Knio의 구현은 조금 더 순수 할 수 있지만 'a'대신 선택한 문자로 시작하지 않는 모든 문자열에 대해 더 빠를 것입니다.이 경우 첫 번째 문자 이후가 아니라 첫 번째 문자 이후에 일치하지 않기 때문입니다.


실제로 내 경우에는 (. ^)가 (\ x00 ^)보다 대략 10 % 느려질 것입니다.
Peter Hansen

1
문자가 일치하지 않는다는 보장으로 \ n 이외의 값을 사용하고 (?! x) x 옵션보다 약간 더 읽기 쉬운 것으로 간주합니다 (상대적으로 소수의 정규 표현식 전문가 임) , 나는 그것도 투표했다. 제 경우에는 두 옵션 중 하나에 대해 설명이 필요하므로 원래 시도를 '\ x00NEVERMATCHES ^'로 조정하면됩니다. 원래의 자체 문서화 기능을 통해이 답변에 대해 불일치가 보장됩니다. 답변 주셔서 감사합니다!
Peter Hansen

3
이것이 실제로 작동합니까? 그렇다면 누가 유닉스와 침입하기로 결정 했습니까? 유닉스 정규 표현식 ^에서 첫 번째 문자로만 특별하고와 유사합니다 $. 유닉스 도구를 사용하면 정규 표현식이 리터럴 문자열을 포함하는 모든 항목과 일치합니다 a^.
JaakkoK 2009

이건 좋은 공격이다. 나는 그 리터럴 문자열에 대해 테스트하지 않았습니다.
Adam Nelson

아, 이것이 유닉스 정규 표현식을 어기면 좋아할 것 >^입니다.
CubicleSoft

4

파이썬은 그것을 받아들이지 않을 것이지만 Perl은 :

perl -ne 'print if /(w\1w)/'

이 정규식은 (이론적으로) 무한한 (짝수)의 수와 일치해야 w합니다. 첫 번째 그룹 ( ()들)은 그 자체로 되풀이되기 때문입니다. Perl은 아래에서도 경고를 발행하지 않는 것 같습니다 use strict; use warnings;. 최소한 유효하다고 가정하고 내 (최소) 테스트가 일치하지 않으므로 비평을 위해 제출하십시오.


1
이론은 항상 좋지만 실제로는 "무한"이라는 단어가 포함 된 정규식에 대해 걱정할 것입니다!
Peter Hansen

perl -Mre=debug -e'"www wwww wwwww wwwwww" =~ /(w\1w)/'
Brad Gilbert

@BradGilbert-운영 체제에서 요청한대로 여기에서 (5.10, 약간 오래된 버전) "regex failed"를 생성합니다. 시스템과 일치합니까?
Chris Lutz


4

이것은 파이썬 및 다른 많은 언어에서는 작동하지 않지만 Javascript 정규식에서는 []일치 할 수없는 유효한 문자 클래스입니다. 따라서 입력 내용에 관계없이 다음이 즉시 실패합니다.

var noMatch = /^[]/;

나보다 그것을 더 좋아합니다. 그것은 /$a/의도를 분명히 전달합니다. 그리고 필요할 때마다 사용자 입력을 기반으로 동적으로 컴파일 된 패턴에 대한 폴 백이 필요했기 때문에 필요했습니다. 패턴이 유효하지 않으면 패턴과 일치하지 않는 패턴으로 교체해야합니다. 단순화하면 다음과 같습니다.

try {
    var matchPattern = new RegExp(someUserInput);
}
catch (e) {
    matchPattern = noMatch;
}

4

경계 매처와 관련된 모든 예제는 동일한 레시피를 따릅니다. 레시피:

  1. 경계 매처를 가져옵니다. ^, $, \ b, \ A, \ Z, \ z

  2. 그들이 의도 한 것과 반대로 행동하십시오

예 :

^ 및 \ A는 처음부터 사용되므로 처음에는 사용하지 마십시오.

^ --> .^
\A --> .\A

\ b는 단어 경계와 일치하므로 그 사이에 사용하십시오.

\b --> .\b.

$, \ Z 및 \ z는 끝을 의미하기 때문에 끝에서 사용하지 마십시오.

$ --> $.
\Z --> \Z.
\z --> \z.

다른 사람들은 lookahead와 lookbehind를 사용하여 동일한 비유로도 작동합니다.

(?=x)[^x]
(?!x)x

당신이 반대 무언가를 따라 긍정적 또는 부정적 외모를 주면

[^x](?<=x)
x(?<!x)

그것들은 더 많은 패턴과 더 많은 유사점이 될 수 있습니다.


3

많은 좋은 답변!

@nivk의 답변과 유사하게 절대 일치하지 않는 정규 표현식의 다른 변형에 대해 Perl의 성능 비교를 공유하고 싶습니다.

  1. 입력 : 의사 랜덤 아스키 문자열 (25,000 개의 다른 라인, 길이 8-16) :

정규식 속도 :

Total for   \A(?!x)x: 69.675450 s, 1435225 lines/s
Total for       a\bc: 71.164469 s, 1405195 lines/s
Total for    (?>a+)a: 71.218324 s, 1404133 lines/s
Total for       a++a: 71.331362 s, 1401907 lines/s
Total for         $a: 72.567302 s, 1378031 lines/s
Total for     (?=a)b: 72.842308 s, 1372828 lines/s
Total for     (?!x)x: 72.948911 s, 1370822 lines/s
Total for       ^\b$: 79.417197 s, 1259173 lines/s
Total for         $.: 88.727839 s, 1127041 lines/s
Total for       (?!): 111.272815 s, 898692 lines/s
Total for         .^: 115.298849 s, 867311 lines/s
Total for    (*FAIL): 350.409864 s, 285380 lines/s
  1. 입력 : / usr / share / dict / words (100,000 영어 단어).

정규식 속도 :

Total for   \A(?!x)x: 128.336729 s, 1564805 lines/s
Total for     (?!x)x: 132.138544 s, 1519783 lines/s
Total for       a++a: 133.144501 s, 1508301 lines/s
Total for    (?>a+)a: 133.394062 s, 1505479 lines/s
Total for       a\bc: 134.643127 s, 1491513 lines/s
Total for     (?=a)b: 137.877110 s, 1456528 lines/s
Total for         $a: 152.215523 s, 1319326 lines/s
Total for       ^\b$: 153.727954 s, 1306346 lines/s
Total for         $.: 170.780654 s, 1175906 lines/s
Total for       (?!): 209.800379 s, 957205 lines/s
Total for         .^: 217.943800 s, 921439 lines/s
Total for    (*FAIL): 661.598302 s, 303540 lines/s

(인텔 i5-3320M의 우분투, Linux 커널 4.13, Perl 5.26)


다음은 몇 가지 방법의 자바 스크립트 비교 여기에 덮여 jsperf.com/regex-that-never-matches을
thdoan

2

나는 그것을 믿는다

\Z RE FAILS! \A

정규 표현식에 MULTILINE, DOTALL 등과 같은 플래그가 포함 된 경우도 포함합니다.

>>> import re
>>> x=re.compile(r"\Z RE FAILS! \A")
>>> x.match('')
>>> x.match(' RE FAILS! ')
>>>

\Zand 사이에 문자열의 길이 (> 0)가 무엇이든, \A실패 시간은 일정해야 한다고 생각합니다 (그러나 벤치 마크하지는 않았습니다) .


2
(*FAIL)

또는

(*F)

PCRE 및 PERL을 사용하면 패턴을 즉시 실패하게하는이 역 추적 제어 동사를 사용할 수 있습니다.


2

이 위대한 답변 중 일부를 본 후 현재 승인 된 답변에 대한 @arantius의 의견 (timing $xvs x^vs (?!x)x)은 지금까지 주어진 솔루션 중 일부를 시간을 내고 싶습니다.

@arantius의 275k 라인 표준을 사용하여 Python (v3.5.2, IPython 6.2.1)에서 다음 테스트를 실행했습니다.

TL; DR : 'x^''x\by' @ arantius의 발견에 적어도 ~ 16의 요소, 그리고 반대하여 가장 빠르다, (?!x)x중 하나였습니다 느린 (느린 ~ 37 회). 따라서 속도 문제는 확실히 구현에 달려 있습니다. 속도가 중요한지 커밋하기 전에 원하는 시스템에서 직접 테스트하십시오.

업데이트 : 타이밍 'x^'과 사이에 큰 불일치가 'a^'있습니다. 자세한 내용은 이 질문 을 참조하십시오.a 대신x .

In [1]: import re

In [2]: with open('/tmp/longfile.txt') as f:
   ...:     longfile = f.read()
   ...:     

In [3]: len(re.findall('\n',longfile))
Out[3]: 275000

In [4]: len(longfile)
Out[4]: 24733175

In [5]: for regex in ('x^','.^','$x','$.','$x^','$.^','$^','(?!x)x','(?!)','(?=x)y','(?=x)(?!x)',r'x\by',r'x\bx',r'^\b$'
    ...: ,r'\B\b',r'\ZNEVERMATCH\A',r'\Z\A'):
    ...:     print('-'*72)
    ...:     print(regex)
    ...:     %timeit re.search(regex,longfile)
    ...:     
------------------------------------------------------------------------
x^
6.98 ms ± 58.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
------------------------------------------------------------------------
.^
155 ms ± 960 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$x
111 ms ± 2.12 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$.
111 ms ± 1.76 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$x^
112 ms ± 1.14 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$.^
113 ms ± 1.44 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$^
111 ms ± 839 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
(?!x)x
257 ms ± 5.03 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
(?!)
203 ms ± 1.56 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
(?=x)y
204 ms ± 4.84 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
(?=x)(?!x)
210 ms ± 1.66 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
x\by
7.41 ms ± 122 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
------------------------------------------------------------------------
x\bx
7.42 ms ± 110 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
------------------------------------------------------------------------
^\b$
108 ms ± 1.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
\B\b
387 ms ± 5.77 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
\ZNEVERMATCH\A
112 ms ± 1.52 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
\Z\A
112 ms ± 1.38 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

처음으로 이것을 실행했을 때, 나는 r마지막 3 개의 표현을 잊어 버렸습니다 . 그래서 백 스페이스 문자 '\b'로 해석되었습니다 '\x08'. 그러나 놀랍게도'a\x08c' 이전의 가장 빠른 결과보다 빠릅니다! 공평하게 말하면, 그것은 여전히 ​​그 텍스트와 일치하지만, 왜 그것이 더 빠른지 확실하지 않기 때문에 여전히 주목할 가치가 있다고 생각했습니다.

In [6]: for regex in ('x\by','x\bx','^\b$','\B\b'):
    ...:     print('-'*72)
    ...:     print(regex, repr(regex))
    ...:     %timeit re.search(regex,longfile)
    ...:     print(re.search(regex,longfile))
    ...:     
------------------------------------------------------------------------
y 'x\x08y'
5.32 ms ± 46.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
None
------------------------------------------------------------------------
x 'x\x08x'
5.34 ms ± 66.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
None
------------------------------------------------------------------------
$ '^\x08$'
122 ms ± 1.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
None
------------------------------------------------------------------------
\ '\\B\x08'
300 ms ± 4.11 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
None

내 테스트 파일은 "... 읽기 쉬운 내용과 중복 된 줄 없음" (우분투 16.04) 의 공식을 사용하여 작성되었습니다 .

$ ruby -e 'a=STDIN.readlines;275000.times do;b=[];rand(20).times do; b << a[rand(a.size)].chomp end; puts b.join(" "); end' < /usr/share/dict/words > /tmp/longfile.txt

$ head -n5 /tmp/longfile.txt 
unavailable speedometer's garbling Zambia subcontracted fullbacks Belmont mantra's
pizzicatos carotids bitch Hernandez renovate leopard Knuth coarsen
Ramada flu occupies drippings peaces siroccos Bartók upside twiggier configurable perpetuates tapering pint paralyzed
vibraphone stoppered weirdest dispute clergy's getup perusal fork
nighties resurgence chafe

\B\b위치에 고정되지 않은 모든 패턴과 마찬가지로 성능 측면에서 끔찍하게 결함이 있지만이 패턴은 특히 나쁩니다. ^\B\b대신 벤치마킹 을 시도하십시오 .
Phils

2

빈 정규식

아무것도 일치하지 않는 가장 좋은 정규식은 빈 정규식입니다. 그러나 모든 정규식 엔진이 그것을 받아 들일지 확신하지 못합니다.

불가능한 정규식

다른 해결책은 불가능한 정규식을 만드는 것입니다. 나는 것을 발견 $-^단지 텍스트의 크기 (에 관계없이 계산하는 두 단계를 수행 https://regex101.com/r/yjcs1Z/1 ).

참고로 :

  • $^$.(1)> O를 - 계산하는 단계 (36)를 가지고
  • \b\B 내 샘플에서 1507 단계를 거치고 문자열의 문자 수에 따라 증가합니다-> O (n)

이 질문에 대한 더 인기있는 스레드 :


1

어쩌면?

/$.+^/

파이썬에서,이 방법은 사용자가 제어 할 경우에만 작동 플래그 : re.compile('$.+^', re.MULTILINE|re.DOTALL).search('a\nb\nc\n')리턴 매치 b와 c에 해당하는 개체 (모든 인접 줄 바꿈의 사이를). 내가 추천하는 부정적 접근법은 컴파일 할 수있는 플래그 조합에 대해 작동합니다 (즉, 일치하지 않습니다).
Alex Martelli

내 나쁜 혼합 $^.
Chris Lutz

1
이것은 시작 하기 전에 문자열의 끝을 찾으려고 시도 할 수도 있지만 정규 표현식의 마지막 문자가 아니라면 $가 '문자열의 끝'을 의미하지 않는다는 것을 알았습니다. 따라서 ^는 리터럴 $로 시작하고 리터럴로 끝나는 하위 문자열과 일치 할 수 있습니다.
pavium

@ pavium, 그것은 확실히 파이썬이나 자바 스크립트에서 그런 식으로 행동하지 않습니다. \로 이스케이프하거나 []로 문자 세트에 포함시키지 않는 한 $ 및 ^와 같은 특수 문자는 리터럴로 취급되지 않아야합니다. 어떤 언어로 이것을 관찰 했습니까?
Peter Hansen

Perl에서는 최소한 작성해야합니다 /\z.+\A/( perldoc perlre 참조 ). 이는 다중 회선 및 단일 회선 모드 ( use re '/ms')가 영향을 미치지 않도록합니다.
Brad Gilbert

0
'[^0-9a-zA-Z...]*'

...을 모든 인쇄 가능한 기호로 대체하십시오.). 그것은 텍스트 파일입니다.


나는 그것을위한 더 짧은 방법이 있어야한다고 생각하지만, 그것은 나의 첫 생각이기도했다 ^^
FP

4
이것은 빈 문자열과 일치합니다. 가능한 모든 문자를 잡으려면 [^\x00-\xFF]+(바이트 기반 구현에)를 사용하십시오.
페르디난트 베이어

6
더 나은 표현은입니다 [^\s\S]. 그러나 Ferdinand Beyer가 이미 말했듯이 빈 문자열과 일치합니다.
Gumbo

3
Drakosha의 정규식은 *; 그것을 그대로 두거나 +로 바꾸면 적어도 하나의 문자와 일치해야합니다. 클래스가 가능한 모든 문자를 제외하면 아무것도 일치하지 않습니다.
Alan Moore

0

정규 표현식 대신 항상 false if 문을 사용하면 어떻습니까? 자바 스크립트에서 :

var willAlwaysFalse=false;
if(willAlwaysFalse)
{
}
else
{
}

Charlie의 질문에 대한 답변으로 이러한 종류의 접근 방식이 바람직하지 않은 이유를 설명하는 주석을 추가했습니다. 요컨대, 나는 항상 사용될 정규 표현식 안에 그룹이 필요하지만 어떤 경우에는 절대 일치하지 않도록 그룹을 만들어야합니다.
Peter Hansen

-2

정규 표현식 구현에 의존하지 않는 휴대용 솔루션은 로그 메시지에 절대 나타나지 않는 상수 문자열을 사용하는 것입니다. 예를 들어 다음을 기반으로 문자열을 만듭니다.

cat /dev/urandom | hexdump | head -20
0000000 5d5d 3607 40d8 d7ab ce72 aae1 4eb3 ae47
0000010 c5e2 b9e8 910d a2d9 2eb3 fdff 6301 c85f
0000020 35d4 c282 e439 33d8 1c73 ca78 1e4d a569
0000030 8aca eb3c cbe4 aff7 d079 ca38 8831 15a5
0000040 818b 323f 0b02 caec f17f 387b 3995 88da
0000050 7b02 c80b 2d42 8087 9758 f56f b71f 0053
0000060 1501 35c9 0965 2c6e 03fe 7c6d f0ca e547
0000070 aba0 d5b6 c1d9 9bb2 fcd1 5ec7 ee9d 9963
0000080 6f0a 2c91 39c2 3587 c060 faa7 4ea4 1efd
0000090 6738 1a4c 3037 ed28 f62f 20fa 3d57 3cc0
00000a0 34f0 4bc2 3067 a1f7 9a87 086b 2876 1072
00000b0 d9e1 6b8f 5432 a60e f0f5 00b5 d9ef ed6f
00000c0 4a85 70ee 5ec4 a378 7786 927f f126 2ec2
00000d0 18c5 46fe b167 1ae6 c87c 1497 48c9 3c09
00000e0 8d09 e945 13ce 7da2 08af 1a96 c24c c022
00000f0 b051 98b3 2bf5 4d7d 5ec4 e016 a50d 355b
0000100 0e89 d9dd b153 9f0e 9a42 a51f 2d46 2435
0000110 ef35 17c2 d2aa 3cc7 e2c3 e711 d229 f108
0000120 324e 5d6a 650a d151 bc55 963f 41d3 66ee
0000130 1d8c 1fb1 1137 29b2 abf7 3af7 51fe 3cf4

물론 이것은 지적 과제는 아니지만 덕트 테이프 프로그래밍 과 유사 합니다 .


-6
new Regex(Guid.NewGuid().ToString())

영숫자 및 ' -'(둘 중 정규 표현식 특수 문자는 아님) 만 포함하는 패턴을 작성 하지만 GUID의 요점이므로 동일한 문자열이 이전 어느 곳에 나 나타나는 것은 통계적으로 불가능합니다.


2
"통계 불가능"? 응? GUID가 계산되는 방식에 따라 다음 GUID를 예측하는 것이 가능하고 종종 매우 간단합니다 (컴퓨터가 GUID를 계산하는 시간과 시간에 따라 달라짐). "아마도", "매우 작은 확률로"를 의미하지만 완벽하게 임의의 문자열에도 "불가능"이라고 말할 수는 없습니다. 정규식은 무한한 문자열과 일치합니다.이 질문은 일치하지 않는 문자열을 찾고 있습니다. 이제까지.
페르디난트 바이어
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.