임의의 양의 캡처 그룹이있는 정규 표현식이 있다고 가정 해 보겠습니다.
pattern = /(some)| ..a lot of masks combined.... |(other)/
그 그룹의 수를 결정하는 방법이 있습니까?
주어진 정규식과 일치하는 문자열을 항상 찾을 수 있다면 정규식과 일치시키는 것으로 충분 하고 일치 데이터 길이를 살펴보십시오 . 그러나 정규 표현식에 일치하는 문자열 이 있는지 확인하는 것은 np-hard [1] 입니다. 이것은 어떤 종류의 정규식을 얻을 것인지 미리 알고있는 경우에만 가능합니다.
Regexp
클래스 에서 차선책으로 가장 좋은 방법 은 Regexp#source
또는 Regexp#to_s
입니다. 그러나 이렇게하면 정규식을 구문 분석해야합니다.
나는 미래에 대해 말할 수 없지만 Ruby 2.0 에서는 Regexp
코어 클래스 에 더 좋은 방법이 없습니다 .
이스케이프 처리되지 않은 백 슬래시가 앞에 오는 경우 왼쪽 괄호는 리터럴 왼쪽 괄호를 나타냅니다. 이스케이프 처리되지 않은 백 슬래시가 앞에 나오지 않는 한 백 슬래시는 이스케이프 처리되지 않습니다. 따라서 문자는 홀수의 백 슬래시가 앞에 오는 경우 이스케이프됩니다.
이스케이프 처리되지 않은 왼쪽 괄호는 물음표가 뒤에 나오지 않는 경우 캡처 그룹을 나타냅니다. 물음표와 함께, 다양한 것을 의미 할 수 있습니다 (?'name')
및 (?<name>)
명명 된 캡처 그룹을 나타낸다. 명명 된 캡처 링 그룹과 명명되지 않은 캡처 링 그룹은 동일한 정규식에서 공존 할 수 없지만 [2] . (?:)
캡처하지 않는 그룹을 나타냅니다. 이것은의 특별한 경우입니다 (?flags-flags:)
. (?>)
원자 그룹을 나타냅니다. (?=)
, (?!)
, (?<=)
및 (?<!)
나타내고 lookaround. (?#)
주석을 나타냅니다.
Ruby regexp 엔진은 regexe의 주석을 지원합니다. 기본 정규식에서 고려하는 것은 매우 어려울 것입니다. 우리가 정말로 이것을 지원하고 싶다면 그것들을 제거하려고 시도 할 수 있지만, 정규 표현식이 캡처 할 수없는 방식으로 확장 모드 (및 라인 주석)를 켜고 끌 수있는 인라인 플래그의 가능성으로 인해 완전히 지원할 수 있습니다. 계속해서 정규식 주석에서 이스케이프 처리되지 않은 괄호를 지원하지 않을 것입니다 [3] .
우리는 다음을 계산합니다.
\(
(?<!(?<!\\)(?:\\\\)*\\)
(읽기 : 앞에 또 다른 백 슬래시가없는 홀수의 백 슬래시가 선행되지 않음)(?!\?)
Ruby는 제한없는 lookbehind를 지원하지 않지만 소스를 먼저 뒤집 으면 첫 번째 주장을 약간 다시 작성할 수 있습니다 (?!(?:\\\\)*(?!\\))
.. 두 번째 주장은 lookbehind : (?<!\?)
.
전체 솔루션
def count_groups(regexp)
# named capture support:
# named_count = regexp.named_captures.count
# return named_count if named_count > 0
# main:
test = /(?!<\?)\((?!(?:\\\\)*(?!\\))/
regexp.source.scan(test).count
end
[1] : 만족도 문제를 다음과 같이 변환하여 NP 경도를 나타낼 수 있습니다.
xy
( x
어설 션이어야 함)x|y
(?!x)
(?=1)
, (?=.1)
, (?=..1)
, ..., (?!1)
, (?!.1)
...예 (XOR) : /^(?:(?=1)(?!.1)|(?!1)(?=.1))..$/
이는 다항식 시간에 테스트 할 수있는 모든 정규식 클래스에 대한 NP 완전성으로 확장됩니다. 여기에는 중첩 된 반복 (또는 반복 또는 반복에 대한 반복 된 역 참조)이없고 선택적 일치의 중첩 된 중첩 깊이가있는 모든 정규식이 포함됩니다.
[2] :를 /((?<name>..)..)../.match('abcdef').to_a
반환합니다 ['abcdef', 'ab']
. 이는 명명 된 캡처 링 그룹이있는 경우 명명되지 않은 캡처 링 그룹이 무시됨을 나타냅니다. Ruby 1.9.3에서 테스트 됨
[3] : 인라인 주석은로 시작 (?#
하고로 끝납니다 )
. 이스케이프 처리되지 않은 오른쪽 괄호는 포함 할 수 없지만 이스케이프 처리되지 않은 왼쪽 괄호는 포함 할 수 있습니다. 이것들은 쉽게 벗겨 질 수 있고 (우리가 "이스케이프되지 않은"정규식을 어디에나 뿌려야하더라도) 덜 악하지만, 이스케이프되지 않은 왼쪽 괄호를 포함 할 가능성도 적습니다.
줄 주석은 #
개행으로 시작 하고 끝납니다. 확장 모드에서는 주석으로 만 처리됩니다 . 확장 모드 외부에서는 리터럴 #
및 개행 문자 와 일치합니다 . 이스케이프를 다시 고려해야하더라도 여전히 쉽습니다 . 정규식에 확장 플래그 세트가 있는지 확인하는 것은 그리 어렵지 않지만 플래그 수정 자 그룹은 완전히 다른 짐승입니다.
Ruby의 멋진 재귀 정규식을 사용하더라도 확장 모드를 수정하는 이전에 열린 그룹이 이미 닫혔는지 확인하는 것만으로도 매우 불쾌한 정규식을 생성 할 수 있습니다 (하나씩 교체하고 주석을 건너 뛸 필요가없는 경우에도). 탈출). (보간을 사용해도) 예쁘지 않을 것이고 빠르지도 않을 것입니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다