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

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



답변

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

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

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

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

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.


답변