정규표현식이란?
- 특정한 규칙을 가진 문자열의 집합을 표현하는 형식 언어이며, 정규 표현식은 문자열의 검색과 치환을 위해 사용이 된다.
- 정규표현식에는 POSIX확장 형식(ereg함수)과 펄호환 형식(pcre함수)이 있는데 빠르고, 기능도 좋고 많이 사용하는 PCRE를 알아본다.
- 정규식을 사용하려면 우선 찾고자 하는 문자열의 패턴을 찾아 표현식으로 작성을 해야 한다.
패턴 정의에 이용되는 문자들
- 리터럴
- 메타문자
- 수량자
- 문자클래스
- 패턴변경자
패턴 검색에 주로 이용되는 함수들
- preg_match
- preg_match_all
- preg_replace
- preg_replace_callback
- preg_quote
- preg_split
앞으로 위 내용들을 알아볼것이다.
정규표현식의 시작과 끝
- 패턴의 시작과 끝은 구분자로 구별하며, 같은 구분자를 써야한다.
- 구분자는 영문, 숫자, 역슬래쉬를 제외한 모든 문자를 사용할 수 있다.
- 보통 /(슬래시)를 많이 사용하며, 패턴에 /를 찾아야 하는경우 다른 구분자를 사용한다.
- 예) "/test/", "$test$", "|test|" 등으로 구분자 사용가능
리터럴(Literal)
- 리터럴은 문자 그대로의 값을 이야기한다.
- 패턴내에 dog라고 작성하면 dog라는 문자열과 매치된다.
메타문자
- 정규표현식 내부에서 특정한 의미를 갖는 문자를 말한다.
- 메타 문자
- \ - 이스케이프 문자
- ^ - 문자열의 시작
- $ - 문자열의 끝
- . - 개행문자를 제외한 모든 단일문자
- | - OR연산(선택)
- [ - 클래스의 시작
- ] - 클래스의 끝
- ( - 서브패턴의 시작
- ) - 서브패턴의 끝
- { - 수량자의 시작
- } - 수량자의 끝
- 단일 \(역슬래시)를 매치하려면, 표현식에 \\\\를 사용해야한다.
- 표현식에서 \를 나타내려면 이스케이프를 시켜야 하기때문에 \\이 사용되며, PHP문자열에서 \또한 이스케이프 시켜야하므로 \가 4개가 필요하다.
- ^(삽입기호) 다음에 오는 문자와 주어진 문자열의 시작부분과 매치
- 예) '/^test/' - "test game" -> 매치됨, "1st test game" -> 매치안됨
- $(달러기호) 이전에 오는 문자와 주어진 문자열의 끝부분과 매치
- 예) '/test$/' - "1st test game" -> 매치안됨, "1st game test" -> 매치됨
- .(마침표) 위치에 개행문자를 제외한 어떤 문자 하나와 매치
- 예) '/b.d/' - "bed", "bad", "bod", "b.d" 등과 매치
- |(파이프)는 OR과 같은 의미로 둘중 하나의 단어와 매치
- 예) '/(even|odd) number/' - "even number", "odd number"등과 매치
수량자
- 수량자 바로앞의 문자가 몇번을 나와야하는지, 몇번을 나올수 있는지를 지정한다.
- 수량자
- ? - 0 또는 1번만
- * - 0 또는 1번이상
- + - 1번이상
- {x} - x번만
- {x,y} - x에서 y번사이
- {x,} - x번이상
- ?(물음표) 앞에 나오는 문자가 나오지 않거나 1번만 나오면 매치
- 예) '/scx?/' - "sc", "scx"와 매치
- *(별표) 앞에 나오는 문자가 나오지 않거나 1개이상 나오면 매치
- 예) '/scx*/' - "sc", "scx", "scxx", "scxxx", "scxxxxxxxxxx"등과 매치
- +(플러스) 앞에 나오는 문자가 무조건 1번이상 나오면 매치
- 예) '/scx+/' - "sc" -> 매치안됨, "scx", "scxx", "scxxx", "scxxxxxxx"등과 매치
- {x} 앞에 나오는 문자가 x번만큼 나오면 매치
- 예) '/go{2}d/' - "good"와 매치
- {x,y} 앞에 나오는 문자가 x번에서 y번 사이만큼 나오면 매치
- 예) '/go{2,3}d/' - "good", "goood"와 매치
- {x,} 앞에 나오는 문자가 x번이상 나오면 매치
- 예) '/go{2,}d/' - "god" -> 매치안됨, "good", "goood", "goooooooood"등과 매치
문자클래스
- 리터럴(문자)의 모아놓은 집합을 말한다.
- \, |, ^, -를 제외한 모든 문자가 리터럴로 취급된다.
- -(하이픈)이 클래스 마지막에 사용되는 경우에는 리터럴로 사용됨
- 많이 사용되는 문자클래스는 약어로도 지정되어 있다.
- [0-9] - \d - 모든 숫자
- [\f\r\t\n\v] - \s - 모든 공백
- [A-Za-z0-9] - \w - 모든 단어 문자
- [^0-9] - \D - 숫자가 아닌 모든 문자
- [^\f\r\t\n\v] - \S - 공백이 아닌 모든 문자
- [^A-Za-z0-9] - \W - 단어 문자가 아닌 모든 문자
패턴변경자
- 정규표현식의 수행방법을 변경한다.
- 변경자 문자들은 끝 구분자 바로 뒤에 적는다.
- 패턴변경자
- A - 패턴을 문자열의 시작으로 이동
- i - 대소문자 구분 없는 모드로 변경
- m - 다중 행 매칭
- s - 마침표를 개행을 포함하여 모든 문자와 매치
- x - 대부분의 공백을 무시
- U - non-greedy 매치를 수행
- i 변경자는 패턴을 대소문자 구분없이 매치를 시킴
- '/test/'의 표현문은 "Test"와는 매치가 되지 않지만, '/test/i'의 표현문은 "Test"와 매치가 된다.
- m 변경자는 패턴을 여러행에 걸쳐서 매치를 시킴
- 일반적으로 ^와 $는 주어진 문자열의 처음과 끝에 매치가 되지만, m 변경자는 주어진 문자열이 여러 행으로 나눠지는 경우 각 행의 처음과 끝에 ^와 $를 매치된다.
int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )
- 정규표현식 매치를 수행 (PHP 4, PHP 5)
- 첫번째 매치가 일어나면 실행을 중지(최대 매치횟수는 1회)
- 매치가 된 횟수를 반환하며, 0 또는 1을 반환하며, 오류시에는 FALSE를 반환
- 파라매터
- $pattern - 검색할 정규식 문자열
- $subject - 찾고자 하는 대상 문자열
- $matches - 검색결과를 반환받을 변수
- $flags - 'PREG_OFFSET_CAPTURE' 값을 지정하면 모든 매치에 대한 문자열 시작 위치를 반환
- $offset - 검색을 시작할 위치를 지정(바이트 단위), 생략시 처음부터 검색
- $matches 파라메터 변수
- 이 변수가 지정되면 검색된 결과를 배열로 저장함
- $matches[0]은 전체패턴 내용이 들어가고,
- $matches[1]은 괄호로 둘러싼 서브 패턴이 들어감
- 플래그 값이 'PREG_OFFSET_CAPTURE'가 지정되면,
- $matches[0]에는 매치한 문자열이,
- $matches[1]에는 매치된 문자열의 시작위치를 저장
소스:
<?php
$str = 'foobar: 2008';
preg_match('/(?<name>\w+): (?<digit>\d+/', $str, $matches);
print_r($matches);
?>
출력값:
Array ( [0] => foobar: 2008 [name] => foobar [1] => foobar [digit] => 2008 [2] => 2008 )
설명:
[0]에는 정규식에 매치된 전체패턴값인 'foobar: 2008'값이 저장이 되며, [1]에는 서브패턴의 값이 들어가는데, ()안에 매치된 값이 저장이 된다.
서브패턴이 두개가 존재하므로 [1][2]에 각각 매치된 값이 들어가며,
서브패턴 name이 지정되어 지정된 name으로 연관배열로 이용이 가능하다.
int preg_match_all ( string $pattern , string $subject, array &$matches [, int flags = PREG_PATTERN_ORDER [, int $offset = 0 ]] )
- 전역 정규표현식 매치를 수행 (PHP 4, PHP 5)
- 전체 매치된 횟수를 반환하며, 오류시 FALSE를 반환
- $matches 파라메터 변수와 $flags 파라메터 변수
- 이 변수가 지정되면 검색된 결과를 다차원 배열로 저장함
- $flags 값이 'PREG_PATTERN_ORDER'이 지정되면
- $matches[0]은 전체 패턴 내용이 들어가고,
- $matches[1]은 괄호로 둘러싼 서브 패턴이 들어감
- $flags 값이 'PREG_SET_ORDER'이 지정되면
- $matches[0]은 처음 매치의 배열을 가지고,
- $matches[1]은 두번째 매치의 배열이 들어감
- $flags 값이 'PREG_OFFSET_CAPTURE'이 지정되면 모든 발생한 매치와 함께 오프셋을 반환
- 플래그값이 지정되지 않으면, 'PREG_PATTERN_ORDER'로 지정됨
소스:
<?php
preg_match_all("|<[^>]+>(.*)</[^>]+>|U",
"<b>example: </b><div align=left>this is a test</div>",
$out, PREG_PATTERN_ORDER);
echo $out[0][0].", ".$out[0][1]."\n";
echo $out[1][0].", ".$out[1][1]."\n";
?>
결과:
<b>example: </b>, <div align=left>this is a test</div>
example: , this is a test
설명:
위 정규식은 총 2번이 매치가 되며, $out[0]에는 전체패턴내용이, $out[1]에는 서브패턴 매치값이 들어가는데,
전체패턴내용이 2개가 존재하므로 $out[0][0]과 $out[0][1]에 각각 첫번째, 두번째 매치된 전체패턴값이 들어간다.
서브패턴내용 역시 2개가 존재하므로 $out[1][0], $out[1][1]에 각각 첫번재, 두번째 매치된 서브패턴값이 들어간다.
소스:
<?php
preg_match_all("|<[^>]+>(.*)</[^>]+>|U",
"<b>example: </b><div align=\"left\">this is a test</div>",
$out, PREG_SET_ORDER);
echo $out[0][0].", ".$out[0][1]."\n";
echo $out[1][0].", ".$out[1][1]."\n";
?>
결과:
<b>example: </b>, example:
<div align="left">this is a test</div>, this is a test
설명:
이전 예제에서는 $out[0]에 전체패턴값이 들어갔지만 여기에서는 첫번째 매치된 배열, 즉 첫번째 전체패턴내용과 첫번재 서브패턴내용이 들어간다.
$out[1]에는 두번째 전체패턴내용과 두번째 서브패턴 내용이 $out[1][0], $out[1][1]에 각각 들어간다.
$matches[전체패턴:0][매치횟수:0]
:
$matches[전체패턴:0][매치횟수:n]
$matches[서브패턴:1][매치횟수:0]
:
$matches[서브패턴:1][매치횟수:n]
$matches[매치횟수:0][전체패턴:0]
$matches[매치횟수:0][서브패턴:1]
:
$matches[매치횟수:n][전체패턴:0]
$matches[매치횟수:n][서브패턴:1]
그리고 아래 정규식은 UTF-8 환경을 기준으로 합니다.
- 이름입력 - 한글 2~5자리 허용
"/^[\x{ac00}-\x{d7af}]{2,5}$/u"
- 이메일 - 워낙많은 정규식들이 있어서 가장 유용하다 싶은 정규식으로 만들어봤습니다.
"/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/"
- 집전화번호 - 지역번호가 들어간 전화번호를 확인할때 유용합니다.
"/^(070|02|031|032|033|041|042|043|051|052|053|054|055|061|062|063|064)-\d{3,4}-\d{4}$/u"
- 휴대폰번호 - 문자 발송등의 작업할경우 휴대폰 번호만 입력받을경우 유용합니다.
"/^(010|011|016|017|018|019)-\d{3,4}-\d{4}$/u"
- 우편번호 - 총6자리 숫자로 가운데 -(하이픈)이 있는경우와 없는경우 둘다 허용합니다.
"/^\d{3}-?\d{3}$/u"
- 아이디 - 아이디는 영문/숫자만 허용하며, 첫글자는 영문자로 시작하여야 하며, 3자리에서 8자리 이내로 입력받음
"/^[a-zA-Z]\w{2,7}$/u"
- 주민번호 - 숫자 13자리를 받으며, 가운데 -(하이픈)은 있어도 없어도 되며, 일부 자리수에 대하여 나올수 있는 숫자에 제한을 두었음
"/^\d{2}[0-1]\d[0-3]\d-?[1-6]\d{6}$/u"
- 날짜 - 일반 -(하이픈)형태의 날짜를 받으며, 자리수 별로 올수 없는 숫자의 경우 일부 제한을 두어 너무 엉뚱한 날짜 입력을 일부 막음
"/^[1-2][9|0]\d{2}-[0-1]\d-[0-3]\d/u"
//iframe 제거
$STRING = preg_replace("!<iframe(.*?)<\/iframe>!is","",$STRING);
//script 제거
$STRING = preg_replace("!<script(.*?)<\/script>!is","",$STRING);
//meta 제거
$STRING = preg_replace("!<meta(.*?)>!is","",$STRING);
//style 태그 제거
$STRING = preg_replace("!<style(.*?)<\/style>!is","",$STRING);
// 를 공백으로 변환
$STRING = str_replace(" "," ",$STRING);
//연속된 공백 1개로
$STRING = preg_replace("/\s{2,}/"," ",$STRING);
//태그안에 style= 속성 제거
$STRING = preg_replace("/ style=([^\"\']+) /"," ",$STRING); // style=border:0... 따옴표가 없을때
$STRING = preg_replace("/ style=(\"|\')?([^\"\']+)(\"|\')?/","",$STRING); // style="border:0..." 따옴표 있을때
//태그안의 width=, height= 속성 제거
$STRING = preg_replace("/ width=(\"|\')?\d+(\"|\')?/","",$STRING);
$STRING = preg_replace("/ height=(\"|\')?\d+(\"|\')?/","",$STRING);
//img 태그 추출 src 추출
preg_match("/<img[^>]*src="[\']?([^>\"']+)[\"']?[^>]*>/i",$STRING,$RESULT);
preg_match_all("/<img[^>]*src="[\']?([^>\"']+)[\"']?[^>]*>/i",$STRING,$RESULT);