정규식 골프 팁


43

언어 별 골프 팁에 대한 스레드와 비슷합니다. 정규 표현식을 단축하는 일반적인 방법은 무엇입니까?

골프에 관해서는 정규식의 세 가지 용도를 볼 수 있습니다. 정규식 정규식 골프 ( "여기서 일치해야하는 목록이 있고 여기에 실패한 목록이 있습니다"), 정규식을 사용하여 계산 문제 와 정규 표현식을 일부로 사용합니다. 더 큰 골프 코드. 이들 중 일부 또는 전부를 다루는 팁을 자유롭게 게시하십시오. 팁이 하나 이상의 맛으로 제한되는 경우 이러한 맛을 맨 위에 표시하십시오.

평소와 같이, 답변 당 하나의 팁 (또는 매우 밀접한 관련 팁군)을 고수하여 가장 유용한 팁이 투표를 통해 맨 위로 올라갈 수 있습니다.


중요한 자기 진흥 : 어떤 종류의 정규식 사용에 해당합니까? codegolf.stackexchange.com/a/37685/8048
Kyle Strand

@KyleStrand "대규모 골프 코드의 일부로 사용되는 정규식"
Martin Ender

답변:


24

탈출하지 않을 때

이 규칙은 전부는 아니지만 대부분의 풍미에 적용됩니다.

  • ] 불일치 할 때 탈출 할 필요가 없습니다.

  • {그리고 }그들이 반복의 일부가 아닌 경우 예를 들면, 탈출하지 않아도 {a}일치하는 {a}문자. 와 같은 것을 일치 시키려고하더라도 {2}그 중 하나만 탈출하면됩니다 (예 :) {2\}.

캐릭터 클래스에서 :

  • ]그것은 예를 들면, 문자 세트의 첫 번째 문자 때 탈출이 필요하지 않습니다 []abc]중 하나와 일치 ]abc하거나,이 후 두 번째 문자가 때 ^, 예를 들어, [^]]아무것도하지만 일치합니다 ]. (특별한 예외 : ECMAScript 맛!)

  • [전혀 탈출 할 필요가 없습니다. 위의 팁과 함께 두 대괄호를 끔찍한 반 직관적 인 문자 클래스와 일치시킬 수 있습니다 [][].

  • ^이 때 탈출이 필요하지 않습니다 하지 예를 들어, 문자 세트의 첫 번째 문자 [ab^c].

  • -이 중 하나 (두 번째 후 첫번째 때 탈출이 필요하지 않습니다 ^문자 집합, 예에서) 또는 마지막 문자 [-abc], [^-abc]또는 [abc-].

  • 문자 클래스 외부의 메타 문자 인 경우에도 문자 클래스 내부에서 이스케이프 처리 할 필요가 없습니다 (백 슬래시 \자체 제외 ).

또한, 일부 맛 ^$그들이 각각 정규 표현식의 시작 또는 끝 부분에 없을 때 그대로 일치합니다.

(세부 사항을 작성해 주신 @ MartinBüttner에게 감사드립니다)


일부는 이스케이프가 필요없는 문자 클래스 (예 :)로 실제 점을 이스케이프 처리하는 것을 선호합니다 [.]. 이 경우에는 보통 1 바이트를 절약 할 수 있습니다\.
CSᵠ

참고 [자바로 이스케이프해야합니다. 그러나 ICU (Android 및 iOS에서 사용) 또는 .NET에 대해서는 확실하지 않습니다.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

18

ASCII 테이블 의 모든 인쇄 가능 문자와 일치하는 간단한 정규식 입니다.

[ -~]

1
순수한 굉장함, 표준 미국 키보드의 모든 문자! 참고 : 표준 ASCII 테이블 (확장 범위 127-255를 포함하지 않음
CSᵠ

자주 사용하지만 일반적인 "일반"문자 인 TAB이 누락되었습니다. 그리고 다른 로케일이 실패하므로 LC_ALL = "C"(또는 이와 유사한)를 사용한다고 가정합니다.
Olivier Dulac

ASCII 테이블에서 문자 범위를 지정하기 위해 하이픈을 사용할 수 있습니까? 모든 정규식에 적용됩니까?
Josh Withee

14

정규식 맛을 알고

정규 표현이 본질적으로 언어에 구애받지 않는다고 생각하는 사람들은 놀랍습니다. 그러나 실제로는 풍미 사이에 상당한 차이가 있으며 특히 코드 골프의 경우 몇 가지와 흥미로운 기능을 아는 것이 좋으므로 각 작업에 가장 적합한 것을 선택할 수 있습니다. 다음은 몇 가지 중요한 맛에 대한 개요와 다른 맛을 구별하는 것입니다. (이 목록은 완전하지는 않지만 정말 눈에 띄는 것을 놓친 경우 알려주십시오.)

펄과 PCRE

나는 Perl 풍미에 너무 익숙하지 않기 때문에 이것을 단일 냄비에 던지고 있으며 대부분 동등합니다 (PCRE는 결국 Perl 호환 정규 표현식 용입니다). Perl 플레이버의 주요 장점은 정규식과 대체 내부에서 실제로 Perl 코드를 호출 할 수 있다는 것입니다.

  • 재귀 / 서브 루틴 . 아마도 골프를위한 가장 중요한 특징 일 것입니다 (몇 가지 맛에만 존재 함).
  • 조건부 패턴 (?(group)yes|no).
  • 지원이와 대체 문자열에서 경우의 변경 \l, \u, \L\U.
  • PCRE는 각 대안이 길이는 다르지만 고정 된 길이를 가질 수있는 lookbehinds에서의 교체를 허용합니다. (Perl을 포함한 대부분의 맛은 전체 고정 길이를 갖도록 lookbehinds가 필요합니다.)
  • \G 이전 경기의 끝에 경기를 고정합니다.
  • \K 경기의 시작을 재설정
  • PCRE는 유니 코드 문자 속성과 스크립트를 모두 지원합니다 .
  • \Q...\E더 긴 문자를 피하기 위해. 많은 메타 문자가 포함 된 문자열을 일치 시키려고 할 때 유용합니다.

.그물

이것은 아마도 가장 약한 단점 일 것입니다.

골프와 관련하여 한 가지 중요한 단점은 다른 맛과 같은 소유 수량자를 지원하지 않는다는 것입니다. 대신 .?+을 작성해야합니다 (?>.?).

자바

  • 버그로 인해 자바 가변 길이 lookbehind의 제한된 유형을 지원 (부록 참조) : 당신이 문자열의 시작 부분에 모든 방법을 lookbehind 수 있습니다 .*당신이 지금처럼 내다을 시작할 수있는 곳에서 (?<=(?=lookahead).*).
  • 캐릭터 클래스의 결합 및 교차를 지원합니다.
  • "유니 코드 스크립트, 블록, 범주 및 이진 속성"에 대한 문자 클래스를 사용하여 유니 코드를 가장 광범위하게 지원합니다 .
  • \Q...\E Perl / PCRE에서와 같이.

루비

최신 버전에서이 특징은 서브 루틴 호출 지원을 포함하여 PCRE와 유사하게 강력합니다. Java와 마찬가지로 문자 클래스의 통합 및 교차를 지원합니다. 한 가지 특별한 기능은 16 진수를위한 내장 문자 클래스입니다 \h(및 부정 \H).

골프를 치는 데 가장 유용한 기능은 Ruby가 수량자를 처리하는 방법입니다. 특히 괄호없이 수량자를 중첩 할 수 있습니다. .{5,7}+작동합니다 .{3}?. 또한, 대부분의 다른 풍미와는 달리, 정량 자상의 하한 0이 생략되면, 예 .{,5}를 들어와 동일하다 .{0,5}.

서브 루틴으로서, PCRE의 서브 루틴 루비의 서브 루틴의 주요 차이점은, 루비 구문 바이트 이상이다 (?n)VS \g<n>하지만 PCRE 서브 루틴이 완료된 후 캡처를 리셋 반면 루비 루틴은 촬영에 사용될 수있다.

마지막으로, Ruby는 다른 맛과는 달리 라인 관련 수정 자에 대한 의미가 다릅니다. 일반적으로 m다른 맛에서 호출되는 수정자는 루비에서 항상 켜져 있습니다. 그래서 ^그리고 $항상의 시작과 끝과 일치 라인 뿐만 아니라 시작과 문자열의 끝을. 이 동작을해야하는 경우는 당신에게 바이트를 저장할 수 있지만, 그렇게하지 않으면 당신은 교체해야하기 때문에, 당신에게 추가 바이트를 비용 ^$함께 \A\z각각. 또한 일반적으로 호출되는 수정 자 s( .줄 바꿈 일치)는 mRuby에서 대신 호출 됩니다. 바이트 수에는 영향을 미치지 않지만 혼동을 피하기 위해 명심해야합니다.

파이썬

파이썬에는 단단한 맛이 있지만 다른 곳에서는 찾을 수없는 특히 유용한 기능을 알지 못합니다.

그러나 ,이 다른 맛을 바꾸기위한 것입니다 re어느 시점에서 모듈은 재미있는 기능이 많이 포함되어있다. 재귀, 가변 길이 lookbehinds 및 문자 클래스 조합 연산자에 대한 지원을 추가 할뿐만 아니라 퍼지 매칭 의 고유 한 기능도 있습니다 . 본질적으로 허용되는 많은 오류 (삽입, 삭제, 대체)를 지정할 수 있으며 엔진은 대략적인 일치도 제공합니다.

ECMAScript

ECMAScript의 풍미는 매우 제한적이므로 골프에 거의 유용하지 않습니다. 그것이 유일하게 진행 되는 것은 무조건 빈 캐릭터 클래스뿐만 아니라 (일반적인 것과는 달리) 모든 캐릭터와 일치 하는 부정 된 빈 캐릭터 클래스 입니다. 불행히도,이 풍미에는 후자의 정상적인 문제에 유용한 특징이 없습니다.[^][](?!)

루아

루아 (Lua)는 상당히 독특한 맛을 지니고 있습니다. 예를 들어 그룹을 정량화 할 수는 없지만 유용하고 흥미로운 기능이 몇 가지 있습니다.

  • 구두점, 대문자 / 소문자 및 16 진수를 포함하여 내장 문자 클래스를 위한 많은 속기가 있습니다.
  • 으로 %b는 매우 컴팩트 한 구문을 지원 균형 문자열하였습니다. 예를 들어 %b()a (와 일치하는 모든 항목을 일치 )시킵니다 (내부 일치하는 쌍을 올바르게 건너 뛰기). (그리고 )여기에 두 문자를 할 수 있습니다.

후원

Boost의 정규식 맛 은 본질적으로 Perl입니다. 그러나 대소 문자 변경 및 조건을 포함하여 정규식 대체를위한 몇 가지 새로운 기능이 있습니다 . 후자는 내가 아는 한 부스트 고유합니다.


look-behind의 look-ahead는 look-behind의 경계 한계를 뚫습니다. Java 및 PCRE에서 테스트되었습니다.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

하지인가 .?+에 해당 .*?
CalculatorFeline

@CalculatorFeline 전자는 소유 적 0 또는 1 수량 자 (소유 적 수량자를 지원하는 맛)이며 후자는 0 이상의 수량 자입니다.
Martin Ender

@CalculatorFeline 아 혼란을 이해합니다. 오타가있었습니다.
Martin Ender

13

당신의 캐릭터 클래스를 알고

대부분의 정규 표현식에는 사전 정의 된 문자 클래스가 있습니다. 예를 들어, \d3 바이트보다 짧은 10 진수를 찾습니다 [0-9]. 예, \d일부 맛에서 유니 코드 숫자와 일치 할 수 있으므로 약간 다를 수 있지만 대부분의 문제에서는 차이가 없습니다.

다음은 대부분의 정규 표현식에서 발견되는 문자 클래스입니다.

\d      Match a decimal digit character
\s      Match a whitespace character
\w      Match a word character (typically [a-zA-Z0-9_])

또한, 우리는 또한 :

\D \S \W

위의 버전을 무효화합니다.

추가 캐릭터 클래스가 있는지 맛을 확인하십시오. 예를 들어 PCRE에는 줄 \R바꿈이 있고 Lua 에는 소문자 및 대문자와 같은 클래스도 있습니다.

(이 점을 지적 해준 @HamZa 및 @ MartinBüttner에게 감사합니다)


3
\RPCRE의 개행.
HamZa

12

캡처하지 않은 그룹을 괴롭히지 마십시오 (...이 아닌 경우)

이 팁은 (적어도) 모든 인기있는 Perl 영감 풍미에 적용됩니다.

이것은 분명 할 수 있지만 (골프가 아닌 (?:...)경우) 가능하면 캡처하지 않는 그룹을 사용하는 것이 좋습니다. 이 두 캐릭터 ?:는 골프를 타는 데 낭비가되므로 역 참조를하지 않더라도 캡처 그룹을 사용하십시오.

하지만 하나 (희귀) 예외가 있습니다 : 당신은 역 참조 그룹에 일어나는 경우에 10적어도 3 번, 당신은 실제로 비 캡처 그룹으로 이전 그룹을 돌려 바이트 저장, 모든 같은 수 \10의가 될 \9의. (그룹 11을 5 회 이상 사용하는 경우 유사한 트릭이 적용됩니다 .)


10이 3을 요구할 때 11이 5 번 가치가있는 이유는 무엇입니까?
Nic Hartley

1
@QPaysTaxes 는 1 바이트 $9대신 $10또는 $111 회 사용할 수 있습니다 . 켜기 $10로하는 것은 $9하나가 필요합니다 ?:세 필요합니다, 그래서 두 바이트, $10뭔가를 저장할들. 켜기 $11로하는 것은 $9이 개 필요 ?:다섯 개해야합니다, 그래서 4 바이트입니다들 $11뭔가를 저장할들 (또는 오 $10$11결합).
Martin Ender

10

패턴 재사용을위한 재귀

소수의 풍미가 재귀를 지원합니다 ( 내 지식으로 는 Perl, PCRE 및 Ruby). 재귀 문제를 해결하지 않더라도이 기능은 더 복잡한 패턴 으로 많은 바이트를 절약 할 수 있습니다 . 해당 그룹 자체의 다른 (이름이 있거나 번호가 지정된) 그룹을 호출 할 필요가 없습니다. 정규식에 특정 패턴이 여러 번 나타나는 경우 그룹화하여 해당 그룹 외부에서 참조하십시오. 이것은 일반적인 프로그래밍 언어의 서브 루틴 호출과 다르지 않습니다. 그래서 대신

...someComplexPatternHere...someComplexPatternHere...someComplexPatternHere... 

Perl / PCRE에서 다음을 수행 할 수 있습니다.

...(someComplexPatternHere)...(?1)...(?1)...

또는 루비에서 :

...(someComplexPatternHere)...\g<1>...\g<1>...

이 그룹이 첫 번째 그룹 인 경우에는 물론 재귀 호출에 번호를 사용할 수 있습니다.

이것은 역 참조 ( ) 와 동일 하지 않습니다\1 . 역 참조는 그룹이 마지막으로 일치 한 것과 정확히 동일한 문자열과 일치합니다. 이 서브 루틴 호출은 실제로 패턴을 다시 평가합니다. someComplexPatternHere긴 문자 클래스를 예로들 수 있습니다.

a[0_B!$]b[0_B!$]c[0_B!$]d

이것은 다음과 일치합니다.

aBb0c!d

동작을 유지하는 동안 역 참조를 사용할 수 없습니다. 역 참조는 위의 문자열에 실패 때문에 것 B0!동일하지 않습니다. 그러나 서브 루틴 호출의 경우 패턴이 실제로 재평가됩니다. 위의 패턴은

a([0_B!$])b(?1)c(?1)d

서브 루틴 호출에서 캡처

Perl 및 PCRE에 대한주의 사항 : 1위 예의 그룹 에 추가 그룹이 포함 된 경우 서브 루틴 호출은 캡처를 기억하지 않습니다. 이 예제를 고려하십시오.

(\w(\d):)\2 (?1)\2 (?1)\2

이 것 없는 일치

x1:1 y2:2 z3:3

서브 루틴 호출이 리턴 된 후 새 그룹 캡처 2가 삭제됩니다. 대신이 패턴은이 문자열과 일치합니다.

x1:1 y2:1 z3:1

이는 서브 루틴 호출 캡처를 유지하는 Ruby와 다르므로 해당 Ruby 정규식 (\w(\d):)\2 \g<1>\2 \g<1>\2이 위의 첫 번째 예와 일치합니다.


\1자바 스크립트에 사용할 수 있습니다 . 그리고 PHP도 마찬가지입니다.
Ismael Miguel

5
@IsmaelMiguel 이것은 역 참조가 아닙니다. 실제로 패턴을 다시 평가합니다. 예를 들어 (..)\1일치합니다 abab하지만 실패 abba반면 (..)(?1)후자를 일치합니다. 실제로 마지막에 일치하는 것과 문자 그대로 일치하는 대신 표현식이 다시 적용된다는 점에서 실제로 서브 루틴 호출입니다.
Martin Ender

와, 나도 몰랐어! 매일 새로운 것을 배우십시오
Ismael Miguel

.NET (또는이 기능이없는 다른 특징)에서 :(?=a.b.c)(.[0_B!$]){3}d
jimmy23013

@ user23013 은이 특정 예에 매우 구체적으로 보입니다. 다양한 둘러보기에서 특정 하위 패턴을 재사용하면 적용 가능한지 확실하지 않습니다.
마틴 엔더

9

경기 실패 원인

정규식을 사용하여 계산 문제를 해결하거나 비정규 언어와 일치하는 경우 문자열의 위치에 관계없이 패턴 분기가 실패해야하는 경우가 있습니다. 순진한 접근 방식은 빈 부정적 예측을 사용하는 것입니다.

(?!)

내용 (빈 패턴)은 항상 일치하므로 부정적인 예측은 항상 실패합니다. 그러나 더 자주는 아니지만 훨씬 간단한 옵션이 있습니다. 입력에 절대 나타나지 않는 문자를 사용하십시오. 예를 들어 입력이 항상 숫자로만 구성된다는 것을 알고 있다면 간단히 사용할 수 있습니다.

!

또는 숫자가 아닌 비 메타 문자로 인해 오류가 발생할 수 있습니다.

입력에 잠재적으로 하위 문자열이 포함될 수 있더라도보다 짧은 방법이 (?!)있습니다. 앵커가 끝과 반대로 패턴 내에 나타날 수 있도록하는 다음과 같은 두 가지 솔루션 중 하나를 사용할 수 있습니다.

a^
$a

그러나 일부 맛을 취급합니다 ^그리고 $그들은 분명히 실제로 앵커로 이해가되지 않기 때문에,이 위치에서 리터럴 문자로.

ECMAScript의 풍미에는 다소 우아한 2 문자 솔루션도 있습니다

[]

이것은 빈 문자 클래스로, 다음 문자가 클래스의 문자 중 하나인지 확인하려고하지만 클래스에 문자가 없으므로 항상 실패합니다. 일반적으로 문자 클래스는 비워 둘 수 없으므로 다른 맛에서는 작동하지 않습니다.


8

OR 최적화

RegEx에 3 개 이상의 대안이있을 때마다 :

/aliceblue|antiquewhite|aquamarine|azure/

일반적인 시작이 있는지 확인하십시오.

/a(liceblue|ntiquewhite|quamarine|zure)/

그리고 아마도 일반적인 결말?

/a(liceblu|ntiquewhit|quamarin|zur)e/

참고 : 3은 시작일 뿐이며 같은 길이를 차지하며 4+는 차이를 만듭니다.


그러나 그들 모두가 공통 접두사를 가지고 있지 않다면 어떨까요? (명확성을 위해 공백 만 추가됨)

/aliceblue|antiquewhite|aqua|aquamarine|azure
|beige|bisque|black|blanchedalmond|blue|blueviolet|brown|burlywood
|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan/

3+ 규칙이 의미가있는 한 그룹화하십시오.

/a(liceblue|ntiquewhite|qua|quamarine|zure)
|b(eige|isque|lack|lanchedalmond|lue|lueviolet|rown|urlywood)
|c(adetblue|hartreuse|hocolate|oral|ornflowerblue|ornsilk|rimson|yan)/

또는 엔트로피가 사용 사례를 충족하는지 일반화 하십시오.

/\w(liceblue|ntiquewhite|qua|quamarine|zure
|eige|isque|lack|lanchedalmond|lue|lueviolet|rown|urlywood
|adetblue|hartreuse|hocolate|oral|ornflowerblue|ornsilk|rimson|yan)/

^이 경우 우리가 확신 우리가 어떤을하지 않습니다 clue또는crown slack Ryan

이것은 "일부 테스트에 따르면" 시작할 때 앵커 를 제공하므로 성능이 향상 됩니다.


1
공통 시작 또는 끝이 한 문자보다 긴 경우 두 그룹을 그룹화해도 차이가 생길 수 있습니다. aqua|aquamarineaqua(|marine)또는 처럼 aqua(marine)?.
Paŭlo Ebermann

6

이것은 매우 간단하지만 진술 할 가치가 있습니다.

당신은 문자 클래스를 반복하는 자신을 발견 할 경우, [a-zA-Z]당신은 아마 사용할 수 있습니다 [a-z]및 APPEND i(대소 내가 nsensitive 수정) 정규식에.

예를 들어, Ruby에서 다음 두 정규식은 동일합니다.

/[a-zA-Z]+\d{3}[a-zA-Z]+/
/[a-z]+\d{3}[a-z]/i -7 바이트 더 짧음

그 문제에 대해 다른 수정자는 총 길이를 단축시킬 수 있습니다. 이것을하는 대신 :

/(.|\n)/

점이 개행 문자와 일치하지 않기 때문에 모든 문자와 일치하는 s ingle-line 한정자 s를 사용하면 점이 개행과 일치합니다.

/./s -3 바이트 더 짧음


루비에는 정규 표현식을위한 수많은 내장 문자 클래스가 있습니다. 참조 페이지 "문자 특성"에 대한 검색을.
좋은 예는 "통화 기호"입니다. Wikipedia 에 따르면 가능한 많은 통화 기호가 있으며 문자 클래스에 넣는 것은 매우 비싸지 만 ( [$฿¢₡Ð₫€.....]) 6 바이트로 일치시킬 수 있습니다.\p{Sc}


1
s수정자를 지원하지 않는 JavaScript는 제외합니다 . :( 그러나 거기에서 JavaScript의 독자적인 /[^]/트릭을 사용할 수 있습니다 .
manatwork

참고 (.|\n)때문에 심지어 어떤 맛에서 작동하지 않습니다 .종종 라인 분리의 다른 유형과 일치하지 않습니다. 그러나이 작업을 수행하는 일반적인 방법은와 (과 s) [\s\S]동일한 바이트 (.|\n)입니다.
Martin Ender

@ MartinBüttner, 내 생각은 다른 라인 엔딩 관련 팁과 함께 유지하는 것이 었습니다. 그러나이 답변이 수정 자에 관한 것이라고 생각하면 다시 게시하면 반대 의견이 없습니다.
manatwork

@manatwork done (및 관련 비 ES 특정 트릭도 추가)
Martin Ender

6

간단한 언어 파서

RE와 같이 매우 간단한 파서를 만들 수 있습니다 \d+|\w+|".*?"|\n|\S. 일치해야하는 토큰은 RE '또는'문자로 구분됩니다.

RE 엔진이 텍스트의 현재 위치에서 일치를 시도 할 때마다 첫 번째 패턴을 시도한 다음 두 번째 패턴 등을 시도합니다. 예를 들어 공백 문자에서 실패하면 계속 이동하여 다시 시도합니다. . 순서가 중요합니다. \S용어 앞에 용어를 배치하면 공백이 아닌 문자에서 먼저 일치 \d+하여 \S구문 분석기를 손상시킵니다.

".*?"우리는 한 번에 하나의 문자열과 일치하므로 문자열 정규가 아닌 욕심 수정을 사용합니다. RE에 욕심없는 기능이 없다면, "[^"]*"동등한 기능을 사용할 수 있습니다 .

파이썬 예제 :

text = 'd="dogfinder"\nx=sum(ord(c)*872 for c in "fish"+d[3:])'
pat = r'\d+|\w+|".*?"|\n|\S'
print re.findall(pat, text)

['d', '=', '"dogfinder"', '\n', 'x', '=', 'sum', '(', 'ord', '(', 'c', ')',
    '*', '872', 'for', 'c', 'in', '"fish"', '+', 'd', '[', '3', ':', ']', ')']

골프 파이썬 예제 :

# assume we have language text in A, and a token processing function P
map(P,findall(r'\d+|\w+|".*?"|\n|\S',A))

일치해야하는 언어의 패턴과 순서를 조정할 수 있습니다. 이 기술은 JSON, 기본 HTML 및 숫자 표현식에 적합합니다. Python 2에서는 여러 번 성공적으로 사용되었지만 다른 환경에서 작동하려면 충분히 일반적이어야합니다.


6

\K 긍정적 인 전망 대신

PCRE와 Perl은 이스케이프 시퀀스를 지원 \K하여 일치의 시작을 재설정합니다. 즉 ab\Kcd, 입력 문자열에 포함해야 abcd하지만보고 된 일치는에만 있습니다 cd.

패턴의 시작 부분에서 긍정적 인 전망을 사용하는 경우 (아마도 가장 가능성이 높은 장소) 대부분의 경우 \K대신 3 바이트를 사용할 수 있습니다 .

(?<=abc)def
abc\Kdef

이것은 대부분의 목적 과 동일 하지만 전부는 아닙니다. 차이점은 장점과 단점을 모두 가져옵니다.

  • 거꾸로 : PCRE와 Perl은 임의의 길이 비하인드를 지원하지 않습니다 (.NET 만 해당). 즉, 당신은 같은 것을 할 수 없습니다 (?<=ab*). 그러나 \K당신은 그것의 앞에 어떤 종류의 패턴을 넣을 수 있습니다! 그래서 ab*\K작동합니다. 이것은 실제로 적용 가능한 경우에이 기술을 훨씬 더 강력하게 만듭니다.
  • 거꾸로 : Lookarounds는 역 추적하지 않습니다. 이것은 나중에 역 참조하기 위해 lookbehind에서 무언가를 캡처하려는 경우에 관련이 있지만 모두 유효한 일치로 이어지는 몇 가지 가능한 캡처가 있습니다. 이 경우 정규식 엔진은 이러한 가능성 중 하나만 시도합니다. \K정규식의 해당 부분을 사용하면 다른 모든 것과 마찬가지로 역 추적됩니다.
  • 단점 : 아시다시피, 정규 표현식과 일치하는 여러 항목이 겹칠 수 없습니다. lookahead는 이전의 일치 항목에 의해 이미 사용 된 문자열 부분의 유효성을 검사 할 수 있기 때문에이 제한을 부분적으로 해결하기 위해 lookaround가 사용되는 경우가 많습니다. 따라서 뒤에 나오는 모든 문자를 일치 시키 ab려면을 사용할 수 있습니다 (?<=ab).. 주어진 입력

    ababc
    

    이것은 두 번째 및와 일치 a합니다 c. 이것은 수 없습니다 재현 할 수 \K. 을 사용한 경우 ab\K.첫 번째 일치 항목 만 가져 ab옵니다.


패턴 \K이 양의 어설 션 내 에서 이스케이프 시퀀스를 사용하는 경우 보고 된 성공적인 일치 시작은 일치 종료보다 클 수 있습니다.
hwnd

@ hwnd 내 요점은 주어진 것과 ababc, 두 번째 a와와 일치하는 방법이 없다는 것 c입니다 \K. 한 번만 일치합니다.
Martin Ender

기능 자체가 아니라 정확합니다. 다음과 같이 고정해야합니다\G
hwnd

@ hwnd 아 나는 지금 당신의 요점을 참조하십시오. 그러나 그 시점에서 (골프 관점에서) 당신은 .마지막 경기에서 실제로가 이었다는 것을 확신 할 수 없기 때문에 실제로는 어쨌든 필요할 수도 있기 때문에 부정적인 전망을 가진 것이 더 낫습니다 a.
Martin Ender

1
\ K =) 의 흥미로운 사용
hwnd

5

어떤 문자와 일치

ECMAScript 특징 s.모든 문자 (개행 포함)와 일치 하는 수정자가 부족합니다 . 이것은 완전히 임의의 문자를 일치시키는 단일 문자 솔루션이 없음을 의미합니다. 다른 맛의 표준 솔루션 ( s어떤 이유로 사용하고 싶지 않은 경우 )은 [\s\S]입니다. 그러나 ECMAScript는 빈 문자 클래스를 지원하는 유일한 풍미 (내 지식으로는)이므로 훨씬 짧은 대안이 [^]있습니다. 이것은 부정 된 빈 문자 클래스입니다. 즉, 어떤 문자와도 일치합니다.

다른 풍미의 경우에도이 기술을 통해 배울 수 있습니다. s예를 들어 .다른 장소에서 일반적인 의미를 유지해야하기 때문에 사용하고 싶지 않은 경우 에도 줄 바꿈 문자와 인쇄 가능한 문자를 모두 일치시키는 짧은 방법이있을 수 있습니다. 입력에 나타나지 않는 문자가 있다면 말입니다. 예를 들어, 줄 바꿈으로 구분 된 숫자를 처리하고 있습니다. 그런 다음 문자열의 일부가 될 수 없다는 [^!]것을 알고 있기 때문에 모든 문자를와 일치시킬 수 있습니다 !. 이렇게하면 순진 [\s\S]또는 두 바이트 이상이 절약 [\d\n]됩니다.


4
Perl에서 모드의 영향을받지 않는 것을 제외하고는 모드 외부의 \N의미를 정확하게 .의미 /s합니다.
Konrad Borowski

4

원자 그룹 및 소유 수량 자 사용

나는 원자 그룹 (발견 (?>...))와 소유 한정사 ( ?+, *+, ++, {m,n}+) 골프 때로는 매우 유용합니다. 문자열과 일치하고 나중에 역 추적을 허용하지 않습니다. 따라서 정규식 엔진에서 찾은 첫 번째 일치 문자열 만 일치합니다.

예를 들어 a, 처음에 홀수의를 가진 문자열을 일치시키기 위해 다음에 더 많은 것을 사용하지 않으 a려면 다음을 사용할 수 있습니다.

^(aa)*+a
^(?>(aa)*)a

이를 통해 .*자유롭게 같은 것을 사용할 수 있으며, 일치하는 항목이 있으면 너무 많거나 적은 문자와 일치하는 다른 가능성이 없으므로 패턴이 손상 될 수 있습니다.

.NET 정규식 (소유 수량화 도구가없는)에서이 그룹을 사용하여 그룹 1을 3의 최대 배수 (최대 30 회) (골프가 잘되지 않음)로 만들 수 있습니다.

(?>((?<-1>){3}|){10})

1
ECMAscript는 또한 소유 정량 자 또는 원자 그룹이 누락되었습니다 :(
CSᵠ

4

하위 표현식 (PCRE) 후 캡처 된 그룹 잊어 버림

이 정규식의 경우 :

^((a)(?=\2))(?!\2)

그룹 1 다음에 \ 2를 지우려면 재귀를 사용할 수 있습니다.

^((a)(?=\2)){0}(?1)(?!\2)

aa이전의 것과는 일치 하지 않습니다. 때로는 ??또는 ?대신 사용할 수도 있습니다 {0}.

재귀를 많이 사용하고 일부 역 참조 또는 조건부 그룹이 정규식의 다른 위치에 나타난 경우에 유용 할 수 있습니다.

또한 원자 그룹은 PCRE에서 재귀를 가정합니다. 따라서 이것은 단일 문자와 일치하지 않습니다 a.

^(a?){0}(?1)a

나는 다른 맛으로 아직 시도하지 않았습니다.

lookaheads의 경우이 목적으로 이중 네거티브를 사용할 수도 있습니다.

^(?!(?!(a)(?=\1))).(?!\1)

4

선택적 표현

때때로 기억하는 것이 유용합니다

(abc)?

이다 대부분 과 동일

(abc|)

그래도 작은 차이가 있습니다. 첫 번째 경우에는 그룹이 캡처 abc하거나 전혀 캡처하지 않습니다. 후자의 경우 역 참조가 무조건 실패하게됩니다. 두 번째 표현식에서 그룹은 abc빈 문자열을 캡처 하거나 후자의 경우 역 참조를 무조건 일치 시킵니다. 후자의 동작을 에뮬레이트하려면 ?2 바이트의 비용이 드는 다른 그룹의 모든 것을 둘러싸 야합니다.

((abc)?)

사용하는 버전 |은 어쨌든 다른 형태의 그룹으로 표현을 감싸고 캡처에 신경 쓰지 않을 때 유용합니다.

(?=(abc)?)
(?=abc|)

(?>(abc)?)
(?>abc|)

마지막 으로이 트릭은 ?원시 형식으로도 바이트를 저장하는 (그리고 다른 형태의 그룹과 결합 할 때 3 바이트) 불확실성에도 적용될 수 있습니다 .

(abc)??
(|abc)

1

항상 일치하는 여러 개의 미리보기 (.NET)

하위 표현식을 캡처하기 위해 항상 일치하는 lookahead 구문이 3 개 이상이거나 lookahead에 수량 화가 있고 그 뒤에 다른 것이 있으면 반드시 캡처되지 않은 그룹에 있어야합니다.

(?=a)(?=b)(?=c)
((?=a)b){...}

이것들은 더 짧습니다 :

(?(?(?(a)b)c))
(?(a)b){...}

여기서 a캡처 된 그룹의 이름이 아니어야합니다. 당신이 사용할 수 |있는 보통의 일을 의미 b하고 c괄호의 또 다른 쌍을 추가하지 않고.

불행히도 조건부에서 그룹을 균형 조정하는 것은 버그가있어 많은 경우에 쓸모가 없었습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.