정규표현식이란?

  • 특정한 규칙을 가진 문자열의 집합을 표현하는 형식 언어이며, 정규 표현식은 문자열의 검색과 치환을 위해 사용이 된다.
  • 정규표현식에는 POSIX확장 형식(ereg함수)과 펄호환 형식(pcre함수)이 있는데 빠르고, 기능도 좋고 많이 사용하는 PCRE를 알아본다.
  • 정규식을 사용하려면 우선 찾고자 하는 문자열의 패턴을 찾아 표현식으로 작성을 해야 한다.

패턴 정의에 이용되는 문자들

  1. 리터럴
  2. 메타문자
  3. 수량자
  4. 문자클래스
  5. 패턴변경자

패턴 검색에 주로 이용되는 함수들

  1. preg_match
  2. preg_match_all
  3. preg_replace
  4. preg_replace_callback
  5. preg_quote
  6. 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 메뉴얼 발췌)
소스:
<?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'로 지정됨

예제) 플래그가 'PREG_PATTERN_ORDER'로 지정되었을때, $matches값의 변화
소스: 
<?php
preg_match_all
("|<[^>]+>(.*)</[^>]+>|U",
"<b>example: </b><div align=left>this is a test</div>",
$outPREG_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]에 각각 첫번재, 두번째 매치된 서브패턴값이 들어간다.

예제) 플래그가 'PREG_SET_ORDER'로 지정되었을때, $matches값의 변화
소스:
<?php
preg_match_all
("|<[^>]+>(.*)</[^>]+>|U",
"<b>example: </b><div align=\"left\">this is a test</div>",
$outPREG_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]에 각각 들어간다.


정리) 위 2가지 예제의 차이점은 도식화 하면 아래와 같다.
$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"

스타일제거
$test = preg_replace("/<link[^>]*>(.*?)/", '', $test);
$test = preg_replace("/(<style [^>]*>)(.*?)(<\/style>)/i", '', $test);




 //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); 

 


 //&nbsp;를 공백으로 변환


 $STRING = str_replace("&nbsp;"," ",$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);