영원한사랑

PCRE 정규표현식 예제로 개념잡기.

http://kr2.php.net/manual/en/ref.pcre.php
http://kr2.php.net/manual/en/reference.pcre.pattern.syntax.php
http://kr2.php.net/manual/en/reference.pcre.pattern.modifiers.php
위 링크가 이해가 안되어도 스크롤을 천천히 내려가며 한번 읽어주고 본문을 읽어주세요.
본문에 없는건 묻지 마세요. 모릅니다.

pattern syntax

1. [0-9] 는 \d 로 표현하는것이 편리하다.
글 수정시에 글번호를 체크해 보자.
<?php
if(!isset($_POST['seq']) || !preg_match('/^[1-9]\d*$/', $_POST['seq'])) { // 시퀀스는 1부터 시작하므로 처음은 1-9 이다.
    header('HTTP/1.1 400');
    echo str_repeat('해킹은 사절<br />', 200);
    exit;
}
?>
2. ' '(공백)은 알아보기 쉽도록 \s 로 써주면 좋다.
3. \(백슬래시) 를 표현할때 버그인지 \\ 로 하면 안된다.
\\\ \\\\\ 이런식으로 홀수가 되는데 그냥 \x5c 로 hex 표현해주면 편하다.
4. (?) 로 매칭결과에 표현되지 않고 조건만 표현할 수 있다.
문자는 *나 + 등의 가변길이를 지원하지 않는다.
(?=문자) (?!문자) : 문자열 길이 계산에 반영되지 않고 조건만 검사한다.
<?php
$text = 'abcd';
echo preg_replace('/(?=b)./', 'e', $text); // 조건에 맞는곳에서 한글자 가져오기.
?>
aecd
(?<=문자) (?<!문자) : 문자열 길이 계산에 반영된다.
<?php
$text = 'abcd';
echo preg_replace('/(?<=b)./', 'e', $text); // 조건이 맞는곳 다음 한글자 가져오기.
?>
abed
따옴표로 감싼 문자열에 \ 가 있어도 정확하게 뽑아내 보자.
<?php
$text = <<<TEXT
<script type="text/javascript">
document.body.innerHTML += "<div style=\"font-size:12px; color:white; background-color:black;\">";
document.body.innerHTML += '\'예제 만들기 귀찮네...\'';
document.body.innerHTML += "</div>";
TEXT;
$cnt = preg_match_all('@(?<!\x5c)([\'"])(.*?)(?<!\x5c)\1@', $text, $matches);
print_r($matches[2]);
?>
Array
(
     [0] => text/javascript
     [1] => <div style=\"font-size:12px; color:white; background-color:black;\">
     [2] => \'예제 만들기 귀찮네...\'
     [3] => </div>
)
5. 줄바꿈이 \r\n 인지 \n 인지 비교하기 귀찮으므로 [\r\n]+ 으로 표현하자.
6. UTF-8 을 사용한다면 /u modifier 에서 \x{ac00} 같은 표현이 가능해진다.
[\x{ac00}-\x{d7af}] 이렇게 쓰면 [가-ㅤㅎㅣㅎ] 이다.
가-ㅤㅎㅣㅎ 만이라면 그냥 UTF-8 로 써도 동작하는데,
타 언어나 특수문자 같은 경우에 잘 안될수가 있다.
그럴때를 위해 기억해 두자. (코드는 UCS-2)
7. UTF-8 에서 한가지 더 이점이 있다. \p 가 그것이다.
<?php
$text = '가 나 다'; // 나와 다 사이는 묶음빈칸이다.
echo preg_replace('/\p{Zs}/u', '', $text);
?>
가나다
이렇듯 문자들을 속성에 따라 그룹으로 나누어 표기할 수 있다.
위의 예제는 Space separator 이고, /u 선언에 의해 UTF-8 로 정의되어 묶음빈칸도 함께 처리되었다.
공백이 아닌것을 매칭하려면 [^\p{Zs}] 로 해도 되겠지만 \P 라는 표현으로 쉽게 표현할 수도 있다.
\pZ 으로 한다면 엔터, 탭 등도 모조리 매칭될것이다.
메뉴얼에 사용된 명칭은 http://unicode.org 에서 확인할 수 있다.

pattern modifier

1. /m
여러 줄이 있고 ^ 나 $ 를 매 줄의 시작과 끝으로 하고자 한다면 /m 을 사용한다.
<?php
$text = <<<TEXT
1. 가
2. 나
3. 다
TEXT;
preg_match_all('/(^(\d+)|(.)$)/mu', $text, $matches); // 앞의 수와 뒤의 한글자를 가져온다.
print_r($matches[2]);
print_r($matches[3]);
?>
Array
(
     [0] => 1
     [1] =>
     [2] => 2
     [3] =>
     [4] => 3
     [5] =>
)
Array
(
     [0] =>
     [1] => 가
     [2] =>
     [3] => 나
     [4] =>
     [5] => 다
)
2. .* 로 여러줄을 다 매칭할 때는 /s 를 사용한다.
3. 태그를 표현할 때 처럼 / 가 많은 곳에서는 @ 처럼 잘 안나오는것으로 패턴구분자를 바꾼다.
<?php
$text = <<<TEXT
<a href="http://xenosi.de/" target="_blank" title="송효진의 홈페이지">
    아무것도
없어요.
</a>
TEXT;
preg_match('@<a\s.*?>(.*?)</a>@su', $text, $matches);
print_r($matches[1]);
?>
         아무것도
없어요.
4. 기본적으로 정규식은 매치되는 표현중 가장 큰 값을 가져온다.
가장 작은 값을 가져오는 방식은 3가지가 있다.
<?php
$text = <<<TEXT
<a href="http://xenosi.de/" target="_blank" title="송효진의 홈페이지">
     아무것도
없어요.
</a>
<a href="http://xenosi.de/" target="_blank" title="송효진의 홈페이지">
     아무것도
없어요.
</a>
TEXT;
echo "--1--\n";
preg_match('@<a.*?>(.*)</a>@su', $text, $matches); // 모두 다 가져올 것이다.
print_r($matches[1]);
echo "--2--\n";
preg_match('@<a.*?>(.*?)</a>@su', $text, $matches); // 가장 간편하고 알아보기 좋다. 추천.
print_r($matches[1]);
echo "--3--\n";
preg_match('@<a(?U).*>(?U)(.*)</a>@su', $text, $matches); // pattern modifier 식을 부분만 적용하는데 범위를 알아보기가 좋지 않다.
print_r($matches[1]);
echo "--4--\n";
preg_match('@<a.*>(.*)</a>@Usu', $text, $matches); // 식 전체에 적용된다.
print_r($matches[1]);
?>
--1--
     아무것도
없어요.
</a>
<a href="http://xenosi.de/" target="_blank" title="송효진의 홈페이지">
     아무것도
없어요.
--2--
     아무것도
없어요.
--3--
     아무것도
없어요.
--4--
     아무것도
없어요.
5. 대소문자 구별 없애는 /i 는 설명하면 손가락 아프다.

응용 예제.

<?php
$text = <<<TEXT
<a href="http://xenosi.de/" target="_blank" title ="송효진의 홈페이지">
     아무것도
없어요.
</a>
<a href="http://xenosi.de/?a=가&b=나&c=다&d&e" target="_blank" title = "송효진의 홈페이지">
     아무것도
없어요.
</a>
TEXT;
if(preg_match('@<a\s(.*?)>@s', $text, $matches)) {
     $cnt = preg_match_all('@([^\pZ=]+?)\pZ*=\pZ*([\'"])(.*?)\2@us', $matches[1], $matches2);
     print_r($matches2[1]);
     print_r($matches2[3]);
}
echo preg_replace_callback('@href=([\'"])((https?://[^\?]+\??)?(.*?))\1@', 'urlencode_callback', $text);
function urlencode_callback($matches)
{
     return 'href='.$matches[1].$matches[3].preg_replace_callback('/(.*?)=([^&]+)/', 'urlencode_value_callback', $matches[4]).$matches[1];
}
function urlencode_value_callback($matches)
{
     return $matches[1].'='.urlencode($matches[2]);
}
?>
Array
(
     [0] => href
     [1] => target
     [2] => title
)
Array
(
     [0] => http://xenosi.de/
     [1] => _blank
     [2] => 송효진의 홈페이지
)
<a href="http://xenosi.de/" target="_blank" title ="송효진의 홈페이지">
         아무것도
없어요.
</a>
<a href="http://xenosi.de/?a=%EA%B0%80&b=%EB%82%98&c=%EB%8B%A4&d&e" target="_blank" title = "송효진의 홈페이지">
         아무것도
없어요.
</a>

인덱싱을 위한 단어 추출 예제

http://www.phpschool.com/gnuboard4/bbs/board.php?bo_table=tipntech&wr_id=50824&sca=&sfl=wr_name%7C%7Csubject&stx=%BC%DB%C8%BF%C1%F8&sop=and&page=2

끝으로 이 문서를 하일라이팅 하기 위한 소스를 붙이고 마친다.

원본글은 첨부파일로 올린다.
<?php
$pattern[] = '/&/';
$replacement[] = '&amp;';
$pattern[] = '/</';
$replacement[] = '&lt;';
$pattern[] = '/>/';
$replacement[] = '&gt;';
$pattern[] = '/[\r\n]+/';
$replacement[] = "<br />\n";
$pattern[] = '/\s{4}|\t/';
$replacement[] = '&nbsp;&nbsp;&nbsp;&nbsp;';
$pattern[] = '@^\*\*(.*)<br />@m';
$replacement[] = '<h3>\1</h3>';
$pattern[] = '@^\*(.*)<br />@m';
$replacement[] = '<h2>\1</h2>';
$pattern[] = '@(https?://[^\s<"]+)@';
$replacement[] = '<a href="\1" target="_blank">\1</a>';
$pattern[] = '@(&lt;\?php<br />.*?\?&gt;<br />)@s';
$replacement[] = '<div style="background-color:black; color:white; padding:10px; font-family:GungSuhChe,MonoSpace;">\1</div>';
$pattern[] = '@&lt;-<br />(.*?)-&gt;<br />@s';
$replacement[] = '<div style="background-color:#003300; color:white; padding:10px; font-family:GungSuhChe,MonoSpace;">\1</div>';
$pattern[] = '@&lt;#<br />(.*?)#&gt;<br />@s';
$replacement[] = '<div style="background-color:#330000; color:white; padding:10px; font-weight:bold; font-family:GungSuhChe,MonoSpace;">\1</div>';
echo preg_replace($pattern, $replacement, $_POST['code']);
exit;
?>
최신 php 는 메모리 관리를 위해 아래와 같은 설정이 포함되었다.
큰 텍스트에 적용할 경우 아무 오류없이 안되어버리는 현상이 있으면,
이 값을 의심하자.
pcre.backtrack_limit integer
pcre.recursion_limit integer

출처:http://www.phpschool.com/gnuboard4/bbs/board.php?bo_table=tipntech&wr_id=58121&page=1