2016-09-03 1 views
11

목록의 정수가 항상 1 씩 증가하는 쉼표로 구분 된 10 진수 정수 목록을 일치시킬 수 있습니까?정규식을 사용하여 증가하는 정수의 일치 목록

이 일치해야합니다

0,1,2,3 
8,9,10,11 
1999,2000,2001 
99,100,101 

이 일치하지한다 (전체적으로 - 마지막 두 일치하는 서브 시퀀스가) :

42 
3,2,1 
1,2,4 
10,11,13 

답변

21

정규식 엔진을 사용하는 경우 예,이 가능하다 역 참조 및 조건을 지원합니다.

(?=(?&cons))\d+ 
(?:,(?=(?&cons))\d+)* 
,\d+ 
여기

(?=(?&cons))는 두 값의 연속이다되도록 술어 대한 자리이다

먼저, 연속 번호 목록 번호의 각 쌍에서 연속리스트로 분해 될 수있다. 로 보일 수 있습니다이 술어는 다음과 같습니다

(?<cons>\b(?: 
    (?<x>\d*) 
    (?:(?<a0>0)|(?<a1>1)|(?<a2>2)|(?<a3>3)|(?<a4>4) 
       |(?<a5>5)|(?<a6>6)|(?<a7>7)|(?<a8>8)) 
    (?:9(?= 9*,\g{x}\d (?<y>\g{y}?+ 0)))* 
    ,\g{x} 
    (?(a0)1)(?(a1)2)(?(a2)3)(?(a3)4)(?(a4)5) 
    (?(a5)6)(?(a6)7)(?(a7)8)(?(a8)9) 
    (?(y)\g{y}) 
    # handle the 999 => 1000 case separately 
    | (?:9(?= 9*,1 (?<z>\g{z}?+ 0)))+ 
    ,1\g{z} 
)\b) 

는 간단한 설명은 999,1000 유형 쌍을 처리하는 두 번째 경우는 이해하기 쉽다 - 그것은 this answer concerned with matching a^n b^n에서 작동하는 방법의 아주 자세한 설명이 있습니다. 이 두 경우의 연결은 9^n ,1 0^n과 일치해야합니다.

첫 번째 경우는 약간 더 복잡합니다. 첫번째 블록 군는 AND 번째로 디지트인지 N을 캡처

(?:(?<a0>0)|(?<a1>1)|(?<a2>2)|(?<a3>3)|(?<a4>4) 
      |(?<a5>5)|(?<a6>6)|(?<a7>7)|(?<a8>8)) 

(?(a0)1)(?(a1)2)(?(a2)3)(?(a3)4)(?(a4)5) 
(?(a5)6)(?(a6)7)(?(a7)8)(?(a8)9) 

: 그것의 큰 부분으로 인해 상기 자릿수를 비교적 상세 진수 숫자를 증가시키는 간단한 경우를 처리 그런 다음 조건부를 사용하여 이러한 그룹 중 어떤 것이 사용되었는지 확인합니다. 그룹 aN이 비어 있지 않으면 다음 숫자는 N + 1이어야합니다.

첫 번째 사례의 나머지 부분은 1999,2000과 같은 사례를 처리합니다. 이것은 패턴 N 9^n, N+1 0^n에 다시 속하므로 a^n b^n을 일치시키고 십진수를 증가시키는 방법의 조합입니다. 1,2의 간단한 경우는 n = 0 인 제한적인 경우로 처리됩니다.

완료 정규식 : 대안 (?&cons) 술어가 약간 더 직접 재귀 서브 패턴 참조가 지원되는 경우 구현 될 수 https://regex101.com/r/zG4zV0/1


이 경우

(?<cons>\b(?: 
    (?<x>\d*) 
    (?:(?<a0>0)|(?<a1>1)|(?<a2>2)|(?<a3>3)|(?<a4>4) 
       |(?<a5>5)|(?<a6>6)|(?<a7>7)|(?<a8>8)) 
    (?<y> 
     ,\g{x} 
     (?(a0)1)(?(a1)2)(?(a2)3)(?(a3)4)(?(a4)5) 
     (?(a5)6)(?(a6)7)(?(a7)8)(?(a8)9) 
     | 9 (?&y) 0 
    ) 
    # handle the 999 => 1000 case separately 
    | (?<z> 9,10 | 9(?&z)0) 
)\b) 

두 문법 9^n ,1 0^n, N> = 1 및 prefix N 9^n , prefix N+1 0^n, n> = 0은 꽤 많이 명시 적으로 작성되었습니다.

완벽한 대안 정규식 : https://regex101.com/r/zG4zV0/3

+0

멋진 게시 할 수 있습니다. _nested back reference_에 관한 일반적인 질문이 있습니다. 정규 표현식에서이 표현식은 (? \ g {y}? + 0)'입니다. 대부분 PCRE와 Perl 호환 _Boost regex_ 엔진을 사용합니다. 때로는 특정 상황에 대한 해결 방법을 사용해야합니다. 예를 들어'(? (? & _ y)? + 0) (? (DEFINE) (?<_y> \ g {y}))'undefined backref' 메시지로 가끔 나를 괴롭히는 경우가 있습니다. 함수 호출이 필요없는 더 나은 해결 방법을 안다면 궁금하십니까? (_workaround https://regex101.com/r/zG4zV0/2_). – sln

+0

@sln 죄송합니다. 부스트 정규식 엔진에 익숙하지 않습니다. 내가 올바르게 이해한다면, 문제는 부스트가 아직 완전히 일치하지 않은 그룹에 대한 하위 참조를 지원하지 않는다는 것입니다. 이 경우 귀하의 해결 방법은 합리적인 것으로 보입니다. 또한 재귀 하위 패턴 참조를 기반으로하는 대체 솔루션을 추가했습니다. 아마도 상자 밖에서 작동합니다. – NikiC

+0

파싱하는 동안 컴파일 시간이 있습니다 :'아직 완전히 (전체적으로) 파싱되지 않은 그룹 '. 따라서 부모 캡쳐 그룹에 대한 참조입니다. 이 문제는 그룹이 열렸을 때 내부 마크가 재귀 구문 분석을 통해 추가되기 전에이 마크에 대한 역주를 허용함으로써 해결되었습니다. 이전에는'''닫는 중 구문이 해석되었을 때만이 백 마크를 허용했습니다. 그것은 단순한 비트 마스크'm_backrefs | = 1 << (markid-1)'입니다. 닫는 괄호가 발견되지 않으면 오류가 생성되고 모든 것이 unwind됩니다. 예상대로 작동합니다. 나는 이것을 다른 mods에 추가한다. – sln

관련 문제