정규 표현식이 X에서는 작동하지만 Y에서는 작동하지 않는 이유는 무엇입니까?


76

나는 특정 프로그램 (grep, sed, awk, perl, python, ruby, ksh, bash, zsh, find, emacs, vi, vim, gedit 등)에서 잘 작동하는 정규 표현식을 작성했습니다. 그러나 다른 프로그램 (또는 다른 유닉스 변형)에서 사용하면 일치하지 않습니다. 왜?

답변:


102

불행히도, 역사적인 이유로 인해 도구마다 정규 표현식 구문이 약간 다르고 때로는 일부 구현에 다른 도구에서 지원하지 않는 확장이 있습니다. 공통점이 있지만 모든 도구 작성자가 다른 선택을 한 것처럼 보입니다.

결과적으로 한 도구에서 작동하는 정규식이있는 경우 다른 도구에서 작동하도록 수정해야 할 수도 있습니다. 일반적인 도구의 주요 차이점은 다음과 같습니다.

  • 연산자 +?|(){}에 백 슬래시가 필요한지 여부
  • 기본을 넘어 .[]*^$일반적으로 지원되는 확장+?|()

이 답변에는 주요 표준이 나열되어 있습니다 . 자세한 내용은 사용중인 도구의 설명서를 확인하십시오.

Wikipedia의 정규 표현식 엔진 비교에는 일반적인 구현에서 지원되는 기능이 나열된 표가 있습니다.

기본 정규 표현식 (BRE)

기본 정규식은 POSIX 표준으로 체계화되어 있습니다 . 그것은 의해 사용되는 구문 grep, sedvi. 이 구문은 다음과 같은 기능을 제공합니다.

  • ^그리고 $만 라인의 시작과 끝에서 일치합니다.
  • . 모든 문자 (또는 개행 문자를 제외한 모든 문자)와 일치합니다.
  • […]대괄호 안에 나열된 하나의 문자 (문자 세트)와 일치합니다. 여는 대괄호 뒤의 첫 문자가이면 ^목록에없는 문자가 대신 일치합니다. 를 포함하려면 ]개봉 직후 [(또는 [^음수 세트 인 경우) 뒤에 넣으십시오 . -두 문자 사이에 있으면 범위를 나타냅니다. 리터럴을 포함하려면 -범위로 파싱 할 수없는 곳에 넣으십시오.
  • ^$.*\[다음 문자 를 인용 하기 전에 백 슬래시 .
  • * 선행 문자 또는 하위 표현식을 0 번, 1 번 이상 일치시킵니다.
  • \(…\)*연산자 또는 역 참조 및 \DIGIT대체 와 함께 사용하기위한 구문 그룹 입니다.
  • 역 참조 \1, \2…는 해당 그룹과 일치하는 정확한 텍스트와 일치합니다 (예 : \(fo*\)\(ba*\)\1일치 foobaafoo하지만 일치 하지 않음) foobaafo. 10 번째 그룹 이상을 참조하는 표준 방법은 없습니다 (의 표준 의미 \10는 첫 번째 그룹 다음에 0).

다음 기능도 표준이지만 일부 제한된 구현에서는 누락되었습니다.

  • \{m,n\}m 에서 n 번 사이의 선행 문자 또는 하위 표현식과 일치합니다 . n 또는 m 은 생략 할 수 있으며 정확히 m을 의미합니다 .\{m\}
  • 대괄호 안에 문자 클래스를 사용할 수 있습니다 (예 : [[:alpha:]]모든 문자와 일치). 대괄호 표현 의 현대적인 구현은 또한 비슷한 요소[.ll.] 와 같은 클래스를 포함 [=a=]합니다.

다음은 일반적인 확장 (특히 GNU 도구)이지만 모든 구현에서 찾을 수는 없습니다. 사용중인 도구의 설명서를 확인하십시오.

  • \|교대 : foo\|bar일치 foo또는 bar.
  • \?(짧게 \{0,1\}) 및 \+(짧게 \{1,\})는 각각 앞의 문자 또는 하위 표현식과 최대 1 번 또는 1 번 이상 일치합니다.
  • \n줄 바꿈과 \t일치하고 탭과 일치합니다.
  • \w단어 구성 요소 ( [_[:alnum:]]지역화와 관련하여 짧지 만 변형 \W이있는 단어 )와 일치하고 단어 구성 요소가 아닌 모든 문자 와 일치합니다.
  • \<그리고 \>시작에 불과 또는 각각 단어의 끝 부분에있는 빈 문자열과 일치; \b일치하고 그렇지 않은 \B위치 와 일치 \b합니다.

\|연산자가없는 도구 는 정규 표현식의 모든 기능을 갖지 않습니다. 역 참조는 수학적 의미에서 정규 표현식으로 수행 할 수없는 몇 가지 추가 작업을 허용합니다.

확장 정규식 (ERE)

확장 정규 표현식은 POSIX 표준에 의해 체계화됩니다 . BRE에 대한 주요 장점은 규칙 성입니다. 모든 표준 연산자는 문장 부호 문자이며 문장 부호 문자 앞의 백 슬래시는 항상 따옴표로 묶습니다. awk, grep -E또는 egrep, GNU sed -rbash의=~ 연산자에서 사용하는 구문 입니다. 이 구문은 다음과 같은 기능을 제공합니다.

  • ^그리고 $만 라인의 시작과 끝에서 일치합니다.
  • . 모든 문자 (또는 개행 문자를 제외한 모든 문자)와 일치합니다.
  • […]대괄호 안에 나열된 하나의 문자 (문자 세트)와 일치합니다. 초기 ^및 범위를 보완하면 BRE에서와 같이 작동합니다 (위 참조). 문자 클래스를 사용할 수 있지만 일부 구현에서 누락되었습니다. 현대의 구현은 동등성 클래스와 조합 요소도 지원합니다. 괄호 안의 백 슬래시는 일부 구현에서 다음 문자를 인용하지만 모든 구현은 아닙니다. \\이식성을위한 백 슬래시를 의미하는 데 사용 합니다.
  • (…)은 구문 그룹으로 사용 *되거나 \DIGIT대체됩니다.
  • |교대 : foo|bar일치 foo또는 bar.
  • *, +그리고 ?앞의 문자와 일치 또는 여러 번 표현식 : 0 이상 *, 1 이상 +, 0 또는 1을 위해 ?.
  • 영숫자가 아닌 경우 백 슬래시는 다음 문자를 인용합니다.
  • {m,n}mn 사이의 선행 문자 또는 하위 표현식과 일치합니다 (일부 구현에서 누락 됨). n 또는 m 은 생략 할 수 있으며 정확히 m을 의미합니다 .{m}
  • BRE와 같은 몇 가지 일반적인 확장 : 역 참조 (특히 사용 가능한 busybox 구현을 제외하고 awk에는 없음 ); 특수 문자 , 등; 단어 경계 와 , 단어 구성 과 , ...\DIGIT$0 ~ "(...)\\1"\n\t\b\B\b\B

PCRE (Perl 호환 정규식)

PCRE는 원래 Perl에 의해 도입되고 GNU grep -P많은 현대 도구 및 프로그래밍 언어 에서 일반적으로 PCRE 라이브러리 를 통해 채택 된 ERE의 확장입니다 . 예제가 포함 된 멋진 형식에 대해서는 Perl 설명서 를 참조하십시오 . 최신 버전의 Perl의 모든 기능이 PCRE에서 지원되는 것은 아닙니다 (예 : Perl 코드 실행은 Perl에서만 지원됨). 지원되는 기능에 대한 요약은 PCRE 설명서 를 참조하십시오 . ERE의 주요 추가 사항은 다음과 같습니다.

  • (?:…)캡처 (…)하지 않은 그룹 : like 이지만 역 참조를 계산하지 않습니다.
  • (?=FOO)BAR(lookahead)는 일치 BAR하지만 FOO동일한 위치에서 시작 하기위한 일치 항목이있는 경우에만 일치합니다 . 이 경기에서 다음 텍스트를 포함하지 않고 경기를 고정하기 위해 가장 유용하다 : foo(?=bar)경기 foo가 뒤에있어하지만 경우 bar.
  • (?!FOO)BAR(음수 미리보기)는 일치 BAR하지만 FOO같은 위치에 일치하는 항목이 없습니다 . 예를 들어 ;으로 (?!foo)[a-z]+시작하지 않는 모든 소문자와 일치합니다 foo. [a-z]+(?![0-9)뒤에 숫자가없는 소문자 단어와 일치합니다 (따라서 foo123일치 fo하지만 일치 하지 않음 foo).
  • (?<=FOO)BAR(lookbehind)는 일치 BAR하지만 바로 앞에 일치하는 경우에만 일치합니다 FOO. FOO길이는 알고 있어야합니다 (와 같은 반복 연산자를 사용할 수 없음 *). 이 경기의 선행 텍스트를 포함하지 않고 경기를 고정하기 위해 가장 유용하다 : (?<=^| )foo경기 foo가 공백이나 문자열의 시작 앞에있어 만합니다.
  • (?<!FOO)BAR(negative lookbehind)는 일치 BAR하지만 바로 앞에 일치하지 않는 경우에만 일치합니다 FOO. FOO길이는 알고 있어야합니다 (와 같은 반복 연산자를 사용할 수 없음 *). 이는 일치하는 선행 텍스트를 포함하지 않고 일치를 고정하는 데 가장 유용합니다 : (?<![a-z])foo일치 foo하지만 소문자가 앞에 있지 않은 경우에만 일치 합니다.

이맥스

Emacs의 구문 은 BRE와 ERE의 중간입니다. Emacs 외에도 -regexGNU find 의 기본 구문입니다 . 이맥스는 다음과 같은 연산자를 제공합니다.

  • ^, $, ., […], *, +, ?ERE와 같이
  • \(…\), \|, \{…\}, BRE와 같이\DIGIT
  • 더 많은 백 슬래시 문자 시퀀스 ; \<그리고 \>단어 경계를 위해; Emacs와 같은 구문을 사용하는 다른 엔진에서는 지원되지 않는 최신 버전의 Emacs가 있습니다.

껍질 글로브

쉘 글롭 (와일드 카드)은 정규 표현식과 완전히 다르고 덜 강력한 구문으로 패턴 일치를 수행합니다. 쉘 외에도 이러한 와일드 카드는 find -namersync 필터와 같은 다른 도구와 함께 사용할 수 있습니다 . POSIX 패턴 에는 다음 기능이 포함됩니다.

  • ? 단일 문자와 일치합니다.
  • […]일반 정규식 구문과 같은 문자 집합입니다. 일부 쉘은 문자 클래스를 지원하지 않습니다. 일부 쉘 은 세트를 무효화하는 !대신 필요 합니다 ^.
  • *모든 문자 시퀀스와 일치합니다 ( /파일 경로를 일치시킬 때를 /제외하고 *, 에서 제외 된 **경우 포함하는 /경우도 있지만 도구 설명서를 확인하십시오).
  • 백 슬래시는 다음 문자를 인용합니다.

Ksh는 정규 표현식의 모든 기능과 일치하는 패턴을 제공하는 추가 기능 을 제공합니다. 이러한 기능은 실행 후 bash에서도 사용할 수 있습니다 shopt -s extglob. Zsh는 다른 구문을 사용 하지만 이후에 ksh의 구문을 지원할 수도 있습니다 setopt ksh_glob.


언급하고 싶은 다른 풍부한 RE vim는와 AT & T libast ksh93입니다.
Stéphane Chazelas

@ StéphaneChazelas vim 외에도 어떤 프로그램이 vim regexp를 사용합니까? ksh 외에도 libast를 사용하는 프로그램은 무엇입니까?
Gilles

AT & T 도구 세트 모두는 AT & T RES (사용 grep, tw, expr...)를. 를 제외하고 ksh는 AT & T 이외의 툴셋은 거의 없습니다.
Stéphane Chazelas

내 이해 (및 Wikipedia 's)에 따르면, "캐릭터 클래스"라는 용어는 실제로 "POSIX 캐릭터 클래스"를 의미하지만, regex(7)귀하와 동의하고 [these]"브래킷 표현"및 ( "브래킷 표현"내) [:these:]"문자 클래스 "라고 부릅니다 . 그 문제를 가장 잘 해결하는 방법을 잘 모르겠습니다.
Adam Katz

무엇을 호출하든 범위를 지원합니다. -범위 를 지정하고 먼저 (선택 사항 후) 이스케이프해야하거나 ^문자 그대로 가져 가야하는 경우를 주목할 가치가 있습니다. (예를 들어 [A-z]코드 65에서 122까지의 문자와 일치하고 실수로 각각의 코드를 포함하는 버그 (예 : 대소 문자 변경)에서 비롯된 많은 버그를 보았습니다 [\]^_`. 또한 [!-~]ANSI의 모든 인쇄 가능한 문자와 일치 하는 유효하지만 혼동 되는 것을 보았습니다. , 나는 [\x21-\x7e]다른 차원에서 혼동하기는하지만 그것의 행동에있어 최소한 간단 하다는 것을 선호한다 .)
Adam Katz
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.