그동안 Perl 스크립트에서 많이 보았지만 굳이 해석을 피해왔던 정규표현식 문법을 Wiki의 PHP Script 버그를 잡기 위해 드디어 보아야만 했다. ㅠ.ㅠ
정말 난해한 표현식이다. C의 scanf에서도 일부 사용되는 표현식이지만, 정말 알고싶지 않은 표현식이다.
하지만 어쩌겠는가?
PHP 매뉴얼을 참조하였다.
http://www.linuxinfor.com/korean/PHP-Manual/pcre.pattern.syntax.html
컥! 정규표현식이 생각만큼 그리 간단한게 아니었다. 정규표현식만 가지고도 책한권이 된다니.
PHP매뉴얼의 번역은 실로 정말 실망이다. 다른 책을 찾아봐야 겠당.
http://www.linuxfocus.org/Korean/July1998/article53.html
http://eldercrow.i-i.st/temptemp/regexp.htm
정규표현식에 관해서만 책으로 이루어진게 있었다. 하지만 바로 위 두개의 포스트에서 기본적인 정규표현식을 이해한 뒤 첫번째 포스트인 PHP 매뉴얼 부분을 보면 웬만한 표현식을 이해하는데 문제가 없을 것으로 생각된다.
문제는 HTML 내에서 다음과 같이 표현하였을 경우
[code]
<cli prompt="'" comment="$">
test ' rpm -qa test $ test rpm
</cli>
<cli prompt='#'>
test # rpm -qa test $ test rpm
</cli>
<cli comment='//'>
test # rpm -qa test // test rpm
</cli>
<cli prompt="$" comment="#">
user@host:~/somedir $ ls
conf lang README screen.gif ui
info.txt manager.dat renderer.php syntax.php
user@host:~/somedir $ wc info.txt # count words in info.txt
55 108 1032 info.txt
user@host:~/somedir $
</cli>
[/code]
실제 아래와 같이 나타나도록 Parsing하는 PHP 코드에서 발생하였다.

다음은 말썽을 일으킨 PHP 코드의 부분이다.
[code]
function _process_args($args) {
// process args to CLI tag: sets $comment_str and $prompt_str
$a_match = false;
if ($args) {
if (preg_match('/prompt\s*=\s*"([^"]*)"|\'([^\']*)\'/', $args, $matches)) {
$this->prompt_str = $matches[1];
$a_match = true;
}
if (preg_match('/comment\s*=\s*"([^"]*)"|\'([^\']*)\'/', $args, $matches)) {
$this->comment_str = $matches[1];
$a_match = true;
}
}
return $a_match;
}
[/code]
원본 코드는 정규표현식 /prompt\s*=\s*"([^"]*)"|\'([^\']*)\'/ 에서 |(or)의 범위- (prompt\s*=\s*"([^"]*)" or \'([^\']*)\')인가 또는 prompt\s*=\s* 를 제외한 부분인가? - 및 preg_match 함수의 사용법에 대한 오해에서 온듯한 결과로 보인다.
결론적으로 실제 예에서 prompt="#" comment='$' 이와 같이 사용하였을때 정규식 첫번째 ()로 묶인 표현식의 실예 "#"의 match 부분인 #은 matches[1]으로 리턴되지만 정규식 두번째 ()에 해당하는 실예 '$'는 matches[2]로 결과 $가 리턴된다는데 문제가 있다.
즉, 프로그래머의 의도와 달리 정규표현식에도 오류가 있지만 preg_match의 리턴값인 $matches 배열 사용에도 오류가 있다는 것이다.
다음의 코드를 시도해 보았다. (정규표현식 : /prompt\s*=\s*(["\'])([^\1]*)\1/)
[code]
function _process_args($args) {
// process args to CLI tag: sets $comment_str and $prompt_str
$a_match = false;
if ($args) {
if (preg_match('/prompt\s*=\s*(["\'])([^\1]*)\1/', $args, $matches)) {
$this->prompt_str = $matches[2];
$a_match = true;
}
if (preg_match('/comment\s*=\s*(["\'])([^\1]*)\1/', $args, $matches)) {
$this->comment_str = $matches[2];
$a_match = true;
}
}
return $a_match;
}
[/code]
아쉽게도 정규표현식 []안에서 () 메모리 참조 표현인 \1를 사용할 수 없는 것으로 보인다.
그래서 위 코드는 정상 동작하지 않았다.
부득이 다음과 같이 수정하여 처음 프로그래머가 하고자 했던 의도를 완성해 보았다.
[code]
function _process_args($args) {
// process args to CLI tag: sets $comment_str and $prompt_str
$a_match = false;
if ($args) {
//echo "args:".$args."<br>";
if ($ret = preg_match('/prompt\s*=\s*("([^"]*)"|\'([^\']*)\')/', $args, $matches)) {
$this->prompt_str = $matches[2];
if($this->prompt_str == null)
$this->prompt_str = $matches[3];
//echo "prompt($ret):".$this->prompt_str."<br>";
$a_match = true;
}
//echo "args:".$args."<br>";
if ($ret = preg_match('/comment\s*=\s*("([^"]*)"|\'([^\']*)\')/', $args, $matches)) {
$this->comment_str = $matches[2];
if($this->comment_str == null)
$this->comment_str = $matches[3];
//echo "comment($ret):".$this->comment_str."<br>";
$a_match = true;
}
}
return $a_match;
}
[/code]
^^ 이제는 정규표현식에 거부감을 갖지 않을 수 있을래나?!






