profile

이 세상에 하나는 남기고 가자

세상에 필요한 소스코드 한줄 남기고 가자

PHP 정규식(PCRE)의 모든 것 - 역 참조(Back references)

유영재

Back references (역 참조)

캐릭터 클래스 밖에서 백 슬래시 다음에 0 보다 큰 숫자는 패턴에서 이전(즉, 왼쪽으로) 캡처 서브 패턴에 대한 역 참조다(주어진 수보다 캡처된 서브 패턴의 수가 같거나 더 많을 경우).

그러나 백 슬래시 뒤의 10진수가 10 보다 작은 경우에는 항상 역 참조로 사용되며 전체 패턴에 많은 왼쪽 여는 괄호(()가 없는 경우에만 오류가 발생한다. 즉, 참조된 괄호는 10 보다 작은 숫자의 참조 왼쪽에 있을 필요는 없다. "전방 참조"는 반복이 관련되어 있고 오른쪽의 서브 패턴이 이전 반복에 참여했을 때 의미가 있다. 백 슬래시 뒤에 나오는 숫자 처리에 대한 자세한 내용은 위의 "백 슬래시"절을 참조하자.

역 참조는 현재 문자열에서 캡처하는 서브 패턴과 실제로 일치하는 것과 일치한다. 그래서 패턴 (sens|respons)e and \1ibility는 "sense and sensibility"와 "response and responsibility"와 일치하지만 "sense and responsibility"은 일치하지 않는다. 대소문자를 구분하는(caseful) 일치일 경우 역 참조 또한 문자의 대소문자를 일치한다. 예를 들어 ((?i)rah)\s+\1은 "rah rah"및 "RAH RAH"와 일치하지만 "RAH rah"와 일치하지 않는다(원래 캡처 서브 패턴이 대소문자를 구분하지 않더라도).

<?php
$str = 'RAH rah';
preg_match('/((?i)rah)\s+\1/', $str, $matches);
print_r($matches);
//Array
//(
//)

preg_match('/(RAH)\s+(?i)\1/', $str, $matches);
print_r($matches);
//Array
//(
//  [0] => RAH rah
//[1] => RAH
//)

같은 서브 패턴에 대한 복수의 역 참조가 있을 수 있다. 특정 패턴에서 실제로 서브 패턴을 사용하지 않은 경우 항상 실패한다. 예를 들어 패턴 (a|(bc))\2는 "bc"가 아닌 "a"와 일치하기 시작하면 항상 실패한다.

<?php
$str = 'abc';
preg_match('/(a|(bc))\2/', $str, $matches);
print_r($matches);
//Array
//(
//)

$str = 'bcbc';
preg_match('/(a|(bc))\2/', $str, $matches);
print_r($matches);
//Array
//(
//  [0] => bcbc
//  [1] => bc
//  [2] => bc
//)

최대 99개의 역 참조가 있을 수 있으므로 백 슬래시 뒤의 모든 숫자는 잠재적인 참조 번호의 일부로 사용된다. 패턴이 숫자로 계속되면 뒤로 구분을 종료하기 위한 구분 기호를 사용해야 한다. PCRE_EXTENDED 옵션이 설정되면 공백이 될 수 있다. 그렇지 않으면 빈 주석을 사용할 수 있다.

<?php
$str = 'bcbc2';
preg_match('/(a|(bc))\2(?#)2/', $str, $matches);
print_r($matches);
//Array
//(
//  [0] => bcbc2
//  [1] => bc
//  [2] => bc
//)

서브 패턴이 처음 사용될 때 참조하는 괄호 안쪽에서 발생하는 역 참조는 실패한다. 예를 들어, (a\1)은 결코 일치하지 않는다. 그러나 이러한 참조는 반복되는 서브 패턴 내부에서 유용할 수 있다. 예를 들어, 패턴 (a|b\1)+는 "a" 및 "aba", "ababba" 등의 임의의 수와 일치한다. 서브 패턴의 각 반복에서 이전 참조는 이전 반복에 해당하는 문자열과 일치한다. 이 작업을 수행하려면 첫 번째 반복이 역 참조와 일치할 필요가 없는 패턴이어야 한다. 위의 예와 같이 한정 기호를 사용하거나 최솟값이 0인 수량 기호를 사용하여 이 작업을 수행 할 수 있다.

PHP 5.2.2부터는 \g 이스케이프 시퀀스를 사용하여 서브 패턴의 절대 참조 및 상대 참조를 사용할 수 있다. 이 이스케이프 시퀀스 뒤에는 부호없는 숫자 또는 음수가 와야하며, 선택적으로 중괄호로 묶을 수 있다. \1, \g1\g{1}은 서로 동의어다. 역 참조 뒤에 문자 숫자(\g{2}1)가 나타나는 경우 중괄호를 사용하면 모호성을 제거하는데 도움이 된다.

음수와 함께 \g 시퀀스를 사용하면 상대 참조를 의미한다. 예를 들어 (foo)(bar)\g{-1}은 "foobarbar"와 (foo)(bar)\g{-2}는 "foobarfoo"와 일치한다. 이것은 긴 패턴에서 특정 이전 서브 패턴을 참조하기 위해 서브 패턴의 수를 추적하는 대신에 사용하면 유용하다.

이름이 지정된 서브 패턴에 대한 역 참조는 (?P=name) 또는 PHP 5.2.2 이후 \k<name> 또는 \k'name'을 사용하여 수행 할 수 있다. 또한 PHP 5.2.4에서는 \k{name}\g{name}에 대한 지원이 추가되었다.


comments powered by Disqus