정규식의 기초 > 개발자팁 | IOTsw_u2 U2 Project
개발자팁

PHP 정규식의 기초

본문

우선 정규식을 공부하기 위한 소스로 다음과 같이 문자열을 작성합니다. 

아래에 실전으로 하는 소스들은 모두 이 문자열을 바탕으로 실습해 볼 것이므로 

문자열을 지정한 곳 아래에 정규식 사용의 소스를 넣어주시면 됩니다.

source.gif


1. 가장 기초적인 형태의 정규식

preg_match
위의 주소에서 우선 가장 간단한 형태로 "메일" 이라는 단어의 존재 유무를 판별해봅니다. 

정규식은 만들기 전에 그것으로 무엇을 먼저 할 것인가, 그리고 어떤 것들을 뽑아낼 것인가를 잘 생각하셔야 합니다. 

정규식 함수부분에서 이미 "존재 유무"를 판별하는 함수에 대해서 배운 적이 있습니다. 바로 preg_match 죠~ ^^;
 

echo preg_match("/메일/", $subject);


당연히 결과는 1입니다. 눈으로도 보이지만 분명히 대상 문자열에는 "메일"이라는 단어가 있거든요. 

그럼 슬래시가 있는지 찾아보도록 할까요? 

슬래시(/)는 구획문자로 지정이 되어있기 때문에 메타문자의 역할을 합니다. 

따라서, 슬래시를 찾기 위해서는 메타문자로서의 효력을 잃게 하는 방법 - 즉 구획문자를 다른 문자로 대체해버리는 방법이 있고, 

혹은 이스케이프 문자()를 붙여서 일반 문자로 인식하게 하는 방법이 있죠. 

두가지 경우에 대해서 작성해보도록 하세요.

이번에는 조금 더 복잡하게 해서... 물음표의 갯수를 찾습니다.
 

echo preg_match_all("/?/", $subject, $match);


소스가 간단하니까 이해가 쉽게 되실거예요. $match에 대해서는 아직 신경쓰지 마세요.
자... 그 다음은 구분자를 사용해보도록 하죠. 

본문중 nzeo.com의 숫자를 세는 겁니다. 음... 1개밖에 안 보이네요. 그럼 대소문자를 구분하지 않으면?
 


소스1.
echo preg_match_all("/nzeo.com/", $subject, $match);

소스2.
echo preg_match_all("/nzeo.com/i", $subject, $match);




2. 서브 패턴의 활용
그럼 이번에는 서브패턴이라는 넘을 사용해봅니다. 

서브 패턴은 괄호 () 로 묶어 주는 부분을 말하는 것으로,  

이 부분만 따로 추려내고자 할 때에도 사용될 수 있습니다.
예로, 링크 걸린 URL들을 뽑아와봅니다. 

우선, 규칙을 생각해야 되는데, 소스에 보면, a href="URL" 이라는 형태로 URL들이 링크되어있습니다. 그쵸? ^^
 

echo preg_match_all("/a href="(.+)"/i", $subject, $match);


여기에서 쓰인 정규식 패턴은 /a href="(.+)"/i 입니다. 어떤 의미인지 살펴보도록 하겠습니다. 

우선 구분자 i가 눈에 띄이죠? 당연히 대소문자 구별을 안하기 위해서입니다. 

그 다음에 눈에 띄는 것이 " 일텐데 당연히 문자열 속에 큰따옴표를 쓰기 위해서 이스케이프 시켜준 것입니다. 

그 다음은 단연 (.+) 부분이 눈에 띄이죠? 

()는 서브 패턴으로 나중에 어떤 것들이 패턴에 일치하는지 알아보기 위함인데, 

뒷 부분에 설명드리기로 하고, .+ 부터 살펴보자면, 도트(.)는 s 옵션이 없을 때에는 

개행문자를 제외한 모든 문자를 의미하는 메타문자라고 했고, 

플러스 기호(+)는 바로 앞 패턴 혹은 문자가 1개 이상있다는 의미라고 그랬습니다. 

즉, .+의 의미는 개행문자를 제외한 모든 문자가 1개 이상 있다는 의미가 되겠습니다. 

그리고 이것을 괄호로 묶었죠. 이제부터 거기에 대해서 설명을 드립니다.

preg_ 계열의 함수의 변수 중 $match 혹은 $matches 라고 되어있는 부분들은 전부 저러한 서브 패턴들을 받아오기 위해서라고 보시면 됩니다. 저 소스 다음에 다음 부분을 추가해보세요.
 

echo $match[0][0];


차이가 보이시죠? 그럼, 같은 방식으로 다음 소스를 추가해보세요.
 

echo $match[1][0];


나온 부분이 어디인지 짐작이 가시나요? 바로 (.+)에 해당하는 부분입니다! 만약 패턴안에 괄호가 또 있다면 괄호의 순서대로 1번 2번 3번...의 순서를 가지게 됩니다. 저렇게 2차원배열 표현되는 이유는 preg_match_all 함수가 각각의 경우에 대해서 배열을 가지고 있기 때문입니다. 즉, 다음과 같이 됩니다.

패턴에 일치한 전체 문자열 -> $match[0] 에 저장되고,
패턴에 일치한 문자열 중 첫번째 서브패턴 -> $match[1]에 저장됩니다.
단, preg_match_all 이 모든 경우를 조사하게 되어있는 함수이므로,

패턴에 일치한 첫번째 전체 문자열 -> $match[0][0]에 저장되고,
패턴에 일치한 두번째 전체 문자열 -> $match[0][1]에 저장됩니다.

preg_match의 경우라면 하나만 검사하게 되니까 $match[0] 과 $match[1] 은 배열이 아니게 됩니다. 즉, $match[0]과 $match[1]의 값을 바로 쓸 수 있다는 것이죠. 위의 소스에서 preg_match_all을 preg_match 의 경우로 바꾸어서 실험해보세요.

그럼 이번에는 메일주소를 패턴으로 만들어봅시다.
우선, 일반적인 메일주소의 규칙에 관해서 생각해보면...

1. 아이디는 한개이상의 영문자, 숫자, 언더스코어(_), 하이픈(-) 으로 이루어져있다.
2. 아이디뒤에는 반드시 골뱅이(@) 가 붙는다.
3. 골뱅이 뒤에 오는 도메인은 한개이상의 영문자, 숫자, 언더스코어, 하이픈 그리고 도트(.)로 구성된다.

규칙들을 차근차근따져가면서 하도록 할께요. ^^
우선, 허용하는 문자들의 범위에 대해서 생각해보면 영문자 숫자, 언더스코어, 하이픈입니다. 이것들로 문자범위를 지정해줄 건데 그 중 하이픈은 메타문자로군요. 따라서 하이픈에만 이스케이프 문자()를 붙여주고 나머지는 범위로 지정하도록 합니다.

[a-zA-Z0-9_-]

허용하는 문자의 범위는 a부터 z까지, A부터 Z까지 0부터 9까지 그리고 언더스코어와 하이픈입니다. 왜 a-Z라고 하지 않는지는 아스키 코드표를 보시면 이해하시리라고 생각합니다. ^^ 문자의 범위는 그렇게 나누었지만, 이 문자들은 반드시 1개 이상이어야 합니다. 없어서는 안되고 없을 수도 없는 값이죠. 따라서...

[a-zA-Z0-9_-]+

와 같은 패턴이 나옵니다. 만약에 "메일주소의 아이디는 반드시 3글자 이상이어야 한다."는 규칙을 세웠다면 어떻게 될까요? 문자의 갯수를 지정하는 메타문자로 중괄호 {} 가 있었습니다. 만약 3글자 이상이라는 규칙을 따르려면

[a-zA-Z0-9_-]{3}

으로 적어주시면 되고, 3글자 이상 8글자이하 라는 규칙은

[a-zA-Z0-9_-]{3,8}

로 표현합니다. 이제 중괄호의 쓰임도 아시겠죠? 사실 + 라는 것은 {1} 과 같은 의미입니다. *도 {0}과 같은 의미이구요. ^^;;

그 다음에는 골뱅이를 넣어야 합니다. 골뱅이는 메타문자가 아닌 관계로 그냥 써주시면 되고, 그 다음은 도메인의 규칙인데... 도메인의 규칙을 잘 살펴보시면...

[a-zA-Z0-9_.-]+

정도는 생각해낼 수 있으실 겁니다. 물론, 조금만 더 깊게 생각한다면 도메인 명이 최소 3글자 이상이여야 한다는 사실도 알 수 있죠. ^^;; 이유는 곰곰히 생각해보세요.

자... 이제 패턴이 완성되었습니다.

/[a-zA-Z0-9_-]+@[a-zA-Z0-9_.-]{3}/

완성된 패턴입니다. 여기서 서브패턴을 추가해보자면... 골뱅이를 중심으로 나누어져있는 아이디와 도메인을 가져와보도록 하겠습니다.

/([a-zA-Z0-9_-]+)@([a-zA-Z0-9_.-]{3})/

이 패턴으로 preg_match 함수를 써보세요. $match[0] 에는 메일주소 전체가, $match[1]에는 첫번째 서브패턴에 해당하는 아이디가, $match[2]에는 두번째 서브패턴에 해당하는 도메인이 각각 저장됩니다. 만약 도메인 중에서 hanmail.net 과 daum.net 의 주소만 골라내려면? OR 의 의미를 가지는 메타문자 찾아보고 계시나요? 저번 강의중에 있던 내용입니다. ^^

결론은 간단하게...

/([a-zA-Z0-9_-]+)@(hanmail.net|daum.net)/

입니다. OR의 의미를 가지는 메타문자(|)를 중간에 써주면 "hanmail.net 혹은 daum.net" 이라는 의미가 됩니다.
이번에는 도메인 패턴을 작성해봅니다. 먼저 규칙을 생각해보면...

1. 도메인 앞부분에 "http://" 가 붙을 수도 있고, 그렇지 않을 수도 있다.
2. 도메인은 한개이상의 영문자, 숫자, 언더스코어, 하이픈 그리고 도트(.)로 구성된다.

메일 주소를 찾아낼 때 했던 것이기 때문에 당연히 더 간단하게 할 수 있습니다. 버뜨... 우리가 할 것은... 도메인을 찾아서 도메인 앞에 http:// 가 없으면 붙여주는 정규식 패턴과 함수를 작성할 것입니다. 우선 패턴부터 만들어봅니다.

/(http://)?([a-zA-Z0-9_-]+.[a-zA-Z0-9_.-]+)/

이렇게 될 수 있겠죠? 머... 스스로 읽을 줄 알 것이라고 생각하지만... 이것까지는 분석해보도록 합니다.

(http://)?
물음표의 의미를 모르시겠다면 정규식 패턴 문법 부분을 다시 보시기를 바랍니다. 중괄호로 표현하자면 {0,1} 쯤 됩니다.

도메인 부분에서는 지정된 문자와 점을 포함하는 문자를 도메인으로 인식하도록 했습니다. 대괄호 [] 속의문자는 그 문자들을 "허용"한다는 것이지 반드시 있어야 한다라는 의미는 못되거든요. 따라서 점을 반드시 포함시키기 위해서는 대괄호 밖으로 빼낼 필요가 있었습니다.
 

preg_match("/(http://)?([a-zA-Z0-9_-]+.[a-zA-Z0-9_.-]+)/ ", $subject, $match);


당연히 반환되는 값이야 1이겠지만 그게 중요한게 아니라 우리가 볼 것은 $match[1]의 값. 즉, http:// 가 있는지 없는지가 중요합니다. 만약 있다면 그대로 놔두고 없다면 http://를 붙여줘야겠죠. 이럴 때 사용하는 함수가 바로 preg_replace_callback 입니다. 정규식을 통해 동적으로 치환을 하는 강력한 함수죠.
 

<?php

$subject = ~~~ 생략
$pattern = "/(http://)?([a-zA-Z0-9_-]+.[a-zA-Z0-9_.-]+)/i";

echo preg_replace_callback($pattern, "callback_func", $subject);

function callback_func($input){
...if(!$input[1]){
......return "http://".$input[0];
...}
}
?>


아주 간단한 형태의 preg_replace_callback 함수 사용법이었습니당. ^^

자.. 그러면 이번에는 preg_replace 를 이용해서 a 태그 사이에 있는 문자열만 뽑아서 a 태그를 없애버리는 겁니다.
그럴려면 우선 a태그의 특성을 알아야 합니다.

1. 시작부분은 "<a"로 시작하고 >로 끝을 맺는다.
2. 시작과 끝 태그 사이에는 어떤 문자라도 올 수 있다.
3. 끝 부분은 "" 이다.
4. 태그는 대소문자를 구분하지 않는다.

규칙이 완성되었습니다. 규칙에 의해서 정규식 패턴을 작성해보면...

/<a(.*)>(.*)</a>/is

와 같이 나타나게 됩니다. ^^;; preg_replace 함수의 사용법은 대강 보셨죠?
 

preg_replace("/<a(.*)>(.*)</a>/is", "$2", $subject);


^^ preg_replace 함수에 보면 replacement 라고 정의된 부분이 있는데 이 부분이 치환할 문자열을 저장하는 곳입니다. 그리고 $숫자 의 형태로 위에서의 $match[1] 과 같은 내용을 받아옵니다. 즉, preg_match에서의 $match[숫자]의 형태가 preg_replace에서는 $숫자 의 형태로 변환될 수 있습니다. 그렇지만 일반 문자열에서 달러문자($)는 메타문자의 성격을 지니기 때문에 이스케이프 문자()를 붙여줘야 합니다.

즉, 위의 소스는 조건을 만족하는 문자열을 태그를 제외한 나머지 부분만으로 치환시켜 버린다는 거죠. ^^;;
이걸로 대강 정규식에 대한 이해가 되었나요? 가능하면 쉽게 풀어쓰려고 했지만, 원래 어렵기도 하고 또 저도 시간에 쫓기다 보니 쉽지만은 않았네요. 더욱 더 고급응용을 하게 되면 템플릿을 만든다거나 하는 고급 활용도 가능하지만 이 부분은 접고 다른 걸 하도록 하죠. 

댓글목록

개발자팁 목록

Total 24건 2 페이지
게시물 검색

IOTsw_u2 정보

회사 . U2
주소 . 어느별 하늘 아래에 있것지요
사업자 등록번호 . 백수임 대표 . 김씨 전화 . 02-123-4567 팩스 . 팩스없음
통신판매업신고번호 . 낼할께 개인정보관리책임자 . 김씨가 알아서 함 부가통신사업신고번호 신고안함
Copyright © 2001-2013 U2. All Rights Reserved.
닫기