[php] 정규식 (Regular Expression)
Php 정규식 패턴(Regular Expression)
패턴 구분 문자
정규식의 시작과 끝을 알릴때는 통상 /(슬래쉬)을 사용하나 PHP에서는 | (파이프) 혹은 @ 등을 사용합니다.(기타 다양한 특수문자 #, &, !, ~,등 정규식 패턴등에 사용하지 않는 문자는 적용가능.)
동일하게 사용되지만 가장 큰 차이점은 / 가 문장중에 나올때, 가령 url을 정규식으로 처리할때 역슬래쉬()를 넣어주어서 정규식가 다르다는 것을 인식 시켜주어야 하지만
|(파이프 혹은 기타 특수문자)를 사용하면 그러지 않아도 된다는 장접이 있습니다.(다른 언어의 정규식 패턴과의 호환을 생각하면 / 을 사용하는 것을 추천드림)
$pattern = '|<[^>]+>(.*)</[^>]+>|U';
$pattern = '/<[^>]+>(.*)<\/[^>]+>/U'; // '/' 로 정규식을 표현할때는 </[ 을 <\/[ 이렇게 역슬래쉬를 추가하여야 정상적으로 동작합니다.
정규식 패턴(Regular Expression) 기호
위치지정
-
^
: 문자열의 시작 -
$
: 문자열의 끝
단일문자
-
.
: 임의 한 문자 (줄바꿈 문자를 제외한 모든 단일 문자)
반복성
-
?
: 0 또는 1회 만 매치 (아예 없거나 1회 만 나타남, 최대 1회) -
*
: 선행 패턴을 만족하는 문자(열)가 최소 0회 이상 반복 매치 -
+
: 선행 패턴을 만족하는 문자(열)가 최소 1회 이상 -
{n}
: 정확히 n개 존재 -
{n,m}
: n개이상 m개 이하 존재 -
{n, }
: 적어도 n개 이상 존재
그룹으로 식 ()
-
(a|b)
: a 이거나 b 임 -
(.*)
: 어떤 문자든, 몇개든 올수 있슴(0개 혹은 그 이상의 어떤 글자) -
(.*?)
: 어떤 문자든, 몇개든 올수 있슴(0개 혹은 그 이상의 어떤 글자)
문자 클래스 []
-
[\d]
또는 [0-9] : 모든 숫자 -
[\D]
또는 [^0-9] : 숫자가 아닌 모든 문자 -
[\w]
: 모든 일반 문자 -
[\W]
: 일반 문자가 아닌 모든 문자 -
[a-z]
: a부터 z까지 문자중 한 문자와 맞는 패턴 -
[^패터]
: 문자 클래스 내의 ^은 부정을 뜻합니다. -
[^a-z]
: 소문자 a 에서 z 사이의 어떤 문자도 없슴 -
[a-zA-Z]
: a부터 z까지, A부터 Z까지 중 한 문자와 맞는 패턴 -
[^0-9]
: 숫자가 아닌 다른 패턴 -
[_a-zA-Z]
: _(언더바) 이거나 혹은 대,소문자의 어떤 문자 -
[_4^a-zA-Z]
: 언더바이거나 숫자사이거나 혹은 ^ 이거나 a에서 z의 소문자이거나 A에서 Z의 대문자 -
[abc]
: a, b, c 중 어느 한 문자와 맞는 패턴 -
[1-6]
: 1에서 6사이의 숫자 -
[\w]{3}
: 일반 문자가 세 번 이상 연속으로 있는 패턴 -
[\d]{1,5}
: 숫자가 1번 이상 5번 이하 연속으로 있는 패턴 -
[\W]{3,}
: 일반 문자가 아닌 문자가 3번 이상 연속으로 있는 패턴 -
[c-h]
: 소문자 c 에서 h 사이의 문자 -
[D-M]
: 대문자 D에서 M 사이의 문자
패턴 변경자(Pattern Modifiers)
패턴 구분 문자인 슬래시(/ or |) 뒤에서 지정 참조
-
i
: 대소문자 구분 안함 -
m
: 줄 단위 매칭 -
s
:.
을 줄바꿈 문자에도 매칭 -
x
: 이스케이프 또는 문자 클래스 내부를 제외하고, 패턴의 공백문자를 무시 -
e
: preg_replace() 만 사용하는 변경자로 변경할 문자열을 PHP 코드로 처리하고, 그 결과를 검색된 문자열의 이용하여 일반적인 치환을 합니다. -
A
: 이 변경자를 지정하면, 패턴을 강제적으로 "고정"합니다 -
D
: 이 변경자가 설정되면, 패턴의 달러($) 메타문자는 주어진 문자열의 마지막에만 대응합니다 -
S
: 이 변경자를 지정하면, 추가 분석을 행합니다. 현 시점에서, 패턴의 분석은 하나의 고정된 시작 문자를 가지지 않는 비고정 패턴에만 유용합니다 -
U
: 이 변경자는 수량 지시의 "greediness"를 뒤집습니다. 그리하여 기본값으로 not greedy하게 합니다. 하지만 "?"가 붙으면 greedy하게 됩니다. -
X
: 이 변경자는 펄과 호환되지 않는 PCRE의 추가 기능을 사용하게 합니다. 패턴의 문자와 결합된 백슬래시가 특별한 의미를 지니지 않을 경우에 에러를 발생시켜서, 차후에 추가 기능을 위해 예약해둡니다. -
J
: 내부 옵션 (?J) 설정은 영역의 PCRE_DUPNAMES 옵션을 변경합니다. 서브패턴에 동일한 이름을 허용합니다. -
u
: 정규표현식(패턴 문자열)을 UTF-8 인코딩으로 취급
- /ims 를 사용할 경우 광범위하게 패턴을 적용할 수 있다(대소문자 구분안하고 줄바꿈까지 매칭)
U
$str = '<b>w</b><b>h</b><b>o</b>';
preg_match_all('/<b>(.*)<\/b>/', $str, $matches1);
preg_match_all('/<b>(.*)<\/b>/U', $str, $matches2);
- 결과
# U를 사용하지 않은 경우
Array
(
[0] => Array
(
[0] => <b>w</b><b>h</b><b>o</b>
)
[1] => Array
(
[0] => w</b><b>h</b><b>o
)
)
# U를 사용한 경우
Array
(
[0] => Array
(
[0] => <b>w</b>
[1] => <b>h</b>
[2] => <b>o</b>
)
[1] => Array
(
[0] => w
[1] => h
[2] => o
)
)
특수문자 이스케이프
- 특수문자 :
.
,,
,?
,*
,+
,^
,$
,[
,]
,(
,)
- 이스케이프 처리 : 특수문자 앞에 역슬래시
\
를 붙임 - 만일, 단일 역슬래시와의 매치하려면, 역슬래시를 4번 씀(
\\\\
) - 특수 문자 이스케이프 전용 함수 : preg_quote()
Word Boundaries
word boundaries는 /b 로 표시되며 워드로만 표시되는 것에 한정된다. 즉 특수문자등을 제외하고 하나의 워드와 매치되는 것이다.
$str = 'PHP is awesome. How is CakePHP?';
$pattern = '/PHP/';
preg_match_all($pattern, $str, $matches);
$pattern = '/\bPHP\b/';
preg_match_all($pattern, $str, $matches);
$str = 'PHP is awesome. How is Cake PHP?';
$pattern = '/\bPHP\b/';
preg_match_all($pattern, $str, $matches);
- 결과
// 모든 PHP를 가져온다.
Array
(
[0] => Array
(
[0] => PHP
[1] => PHP
)
)
// 워드 중에 PHP만 있는 것을 가져온다.
Array
(
[0] => Array
(
[0] => PHP
)
)
// ? 와 같은 것은 제외하고 결과값을 가져온다.
Array
(
[0] => Array
(
[0] => PHP
[1] => PHP
)
)
예제
^
$string = 'https://www.onstory.fun/index.php';
$pattern1 = '|^(https?://)?([^/]+)|'; // ^ 가 있을 경우
$pattern2 = '|(https?://)?([^/]+)|'; // ^ 가 없을 경우
- 결과
# ^ 가 있을 경우
[[0] => https://www.onstory.fun]
# ^ 가 없을 경우
[
[0] => https://www.onstory.fun
[1] => index.php
]
^.{2}[a-z]{1,2}_?[0-9]*([1-6]|[a-f])[^1-9]{2}a+$
^.{2}: 어떤 두자의 문자로 시작하고
[a-z]{1,2} : 소문자a에서 z중 어떤 문자가 1자 내지 2자이고
_?: 언더바가 있거나 없을 수 있고
[0-9]* : 0에서 9까지의 숫자가 0개 혹은 그 이상개 존재하며
([1-6]|[a-f]): 1에서 6사이의 어떤 숫자 혹은 a에서 f 사이의 어떤 소문자가 오며
[^1-9]{2}: 1에서 9사이의 어떤 숫자가 아닌 2자의 글자가오며
a+: a가 한개 혹은 그 이상개 존재한다.
^[1-9]{1}[0-9]*[.]{1}[0-9]{2}$
^[1-9]{1}: 1에서 9사이의 어떤 1개의 숫자로 시작하고
[0-9]*: 0에서 9까지의 숫자가 0개 혹은 그 이상개 존재하며
[.]{1}: 어떤 특정문자가 1개 오고
[0-9]{2}: 0에서 9까지의 숫자가 2개존재
정규표현식 관련 PHP 함수
ereg(), eregi()
PHP 5.3.0 이후로 ereg(), eregi() 는 사라졌다(Deprecated).
대신 preg_match 를 이용하여 값의 존재 여부를 확인할 수 있다.
$pattern = 'abcd';
$str = 'abcdtest';
ereg($pattern, $str); // Bad
preg_match('/'.$pattern.'/', $str) // Good
eregi($pattern, $str); // Bad
preg_match('/'.$pattern.'/i', $str) // Good
ereg_replace()와 eregi_replace()
PHP 5.3.0 이후로 ereg_replace(), eregi_replace() 는 사라졌다(Deprecated).
대신 preg_replace 를 이용하여 처리할 수 있다
$subject = "abcdef";
$pattern = '/^ABC/i';
$subject = preg_replace($pattern, '', $subject);
preg_match vs preg_match_all
두 함수의 사용법은 동일하다. 단 결과에서 preg_match_all 이 모든 결과를 출력하는 반면 preg_match 는 최조 매치된 결과만을 출력한다.
preg_match
'/'문장의 시작과 끝에'/' 를 사용한다.
/i 는 대소문자 구분을 하지 않는 경우 사용한다.
\b 는 단어의 바운드리를 지정한다.
if (preg_match("/\bweb\b/i", "PHP is the web scripting language of choice.")) {
echo "A match was found."; // result
} else {
echo "A match was not found.";
}
if (preg_match("/\bweb\b/i", "PHP is the website scripting language of choice.")) {
echo "A match was found.";
} else {
echo "A match was not found."; // result -> website는 존재하지만 web 이라는 특정단어가 존재 하지 않는다.
}
url 분리하기
url을 분리하여 프로토콜 및 호스트를 찾는다.
// 시작인 http:// 이고 /이 아닌것이 계속되고 대소문자를 구별하지 않는다.
preg_match("/^(http:\/\/)?([^\/]+)/i", "http://www.onstory.fun/index.html", $matches);
print_r($matches);
Array (
[0] => http://www.onstory.fun
[1] => http:// <-- 프로토콜
[2] => www.onstory.fun <!-- host
)
$host = $matches[2]; // www.onstory.fun
preg_match("/[^\.\/]+\.[^\.\/]+$/", $host, $matches);
echo "도메인은 {$matches[0]}\n"; // 도메인은 onstory.fun
검색엔진의 특정 검색어를 찾아내기
preg_match("/^.*?query=(.*)&/i",
"http://search.naver.com/search.naver?where=nexearch&query=홈페이지제작&hw=1...", $matches);
print_r($matches);
Array
(
[0] => http://search.naver.com/search.naver?where=nexearch&query=홈페이지제작&
[1] => 홈페이지제작
)
// 모든 문자로 시작하고 "query=" 이 있으며 &로 끝나는 값, 여기서는 "()"안의 값이 검색어가 됩니다.
태그안의 text 가져오기
$pattern = '/<a(.*?)>(.*?)<\/a>/i';
preg_match($pattern, $value, $tmpTitle);
preg_match_all
preg_match_all(pattern, subject, matches)
정규식에의해 검색된 모든 내용을 반환합니다.
결과의 첫번째 배열은 전체 패턴에 매치되는 내용을 나열하고 두번째 부터는 () 로 묶인 첫번째 하위 패턴과 일치하는 문자열 배열입니다.
예제 1
matches[0] 에서는 pattern 에 일치하는 모든 것이 나열되고 matches[1]에서는 () 안의 내용(서브패턴)이 출력됩니다.
만약 위의 pattern 에 () 이 여러개가 있으면 matches[2].... 로 나오겠죠.
subpattern 에 관한 상세설명
$string = '<b>example: </b><div align=left>this is a test</div>';
$pattern = '|<[^>]+>(.*)</[^>]+>|U';
preg_match_all($pattern, $string, $matches);
- 결과
Array
(
[0] => Array
(
[0] => <b>example: </b>
[1] => <div align=left>this is a test</div>
)
[1] => Array
(
[0] => example:
[1] => this is a test
)
)
subpattern이 출력되면 보기가 좀 번거럽습니다.
이때는 (?:패턴) 처럼 사용하여 subpattern의 출력을 막습니다.
$pattern = '|<[^>]+>(?:.*)</[^>]+>|U';
- 결과
Array
(
[0] => Array
(
[0] => <b>example: </b>
[1] => <div align=left>this is a test</div>
)
)
숫자만 찾기
문자에 포함된 숫자만을 찾는 간단한 예제입니다.
$str = '나는 3학년 5반이고 나이는 17세입니다.';
$pattern = '/\d+/'; //숫자로 시작하고 취소 1회이상 매치
$counts = preg_match_all($pattern, $str, $matches);
- 결과
$counts: 3
$matches
Array
(
[0] => Array
(
[0] => 3
[1] => 5
[2] => 17
)
)
이메일 찾기
$str = '문의는 [email protected] 또는 [email protected]으로 연락 주시기 바랍니다.';
$pattern = '/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}/';
preg_match_all($pattern, $str, $matches);
- 결과
Array
(
[0] => Array
(
[0] => [email protected]
[1] => [email protected]
)
)
핸드폰번호 검사
$string = '문의는 010-1111-2222 또는 02-333-4444 연락 주세요.';
$pattern = '/\d{2,3}-\d{3,4}-\d{4}/';
preg_match_all($pattern, $string, $matches);
- 결과
Array
(
[0] => Array
(
[0] => 010-1111-2222
[1] => 02-333-4444
)
)
URL 검사
$string = '더 많은 정보는 https://www.onstory.fun에서 확인하세요.';
$pattern = '|(https?://)?([-\w]+\\.[-\w.]+)+\w(:\d+)?(/([-\w/_\.]*(\?\S+)?)?)*|'; // 아래 3가지 패턴은 모두 유사한 패턴을 가진다.
$pattern = '|(https?://)?(www\.)?[a-zA-Z0-9-]+(\.[a-z]{2,})+(/[^\s]*)?|';
$pattern = '/(?:https?:\/\/)?(?:www\.)?[a-zA-Z0-9-]+(?:\.[a-z]{2,})+(?:\/[^\s]*)?/'; // 서브패튼을 출력안함
preg_match_all($pattern, $string, $matches);
- 결과
Array
(
[0] => Array
(
[0] => https://www.onstory.fun
)
)
a 태그에서 href 추출
$string = '더 많은 정보는 <a href="https://www.onstory.fun">온스토리</a>에서 확인하세요.';
$pattern ='/href=(\'|\")?([^<>\s\'\"]*)(\'|\"|\s|)/i';
preg_match_all($pattern, $string, $matches);
- 결과
Array
(
[0] => Array
(
[0] => href="https://www.onstory.fun"
)
[1] => Array
(
[0] => "
)
[2] => Array
(
[0] => https://www.onstory.fun
)
[3] => Array
(
[0] => "
)
)
img 태그 추출 src 추출
$string = '아름다운 이미지 <img src="https://www.onstory.fun/image.png">를 보셔요';
$pattern ='/<img[^>]*src=["\']?([^>"\']+)["\']?[^>]*>/i';
preg_match_all($pattern, $string, $matches);
- 결과
Array
(
[0] => Array
(
[0] => <img src="https://www.onstory.fun/image.png">
)
[1] => Array
(
[0] => https://www.onstory.fun/image.png
)
)
태그 및 태그내용 추출
$string = '<b>bold text</b><a href=onstory.html>click me</a>';
$pattern = '/(<([\w]+)[^>]*>)(.*)(<\/\\2>)/';
preg_match_all($pattern, $string, $matches);
- 결과
Array
(
[0] => Array
(
[0] => <b>bold text</b>
[1] => <a href=onstory.html>click me</a>
)
[1] => Array
(
[0] => <b>
[1] => <a href=onstory.html>
)
[2] => Array
(
[0] => b
[1] => a
)
[3] => Array
(
[0] => bold text
[1] => click me
)
[4] => Array
(
[0] => </b>
[1] => </a>
)
)
태그내용 추출
$string = "<b>bold text</b><a href=onstory.html>click me</a>";
$pattern = '|<[^>]+>(.*)<[^>]+>|U';
preg_match_all($pattern, $string, $matches);
- 결과
Array
(
[0] => Array
(
[0] => <b>bold text</b>
[1] => <a href=onstory.html>click me</a>
)
[1] => Array
(
[0] => bold text
[1] => click me
)
)
날짜 추출
$string = "오늘은 20230517일 입니다.";
$pattern = '/([0-9]{4})([0-9]{2})([0-9]{2})/';
preg_match_all($pattern, $string, $matches);
- 결과
Array
(
[0] => Array
(
[0] => 20230517
)
[1] => Array
(
[0] => 2023
)
[2] => Array
(
[0] => 05
)
[3] => Array
(
[0] => 17
)
)
preg_replace
preg_replace 는 패턴으로 찾은 문자를 치환할때 자주 사용한다.
ereg_replace()
php5.3부터 ereg_replace라는 함수가 deprecated 되었다.
Replacement 표기법
replacement를 표기할때는 아래처럼 3가지 모두 가능하다.
${num} $num \num
$string = 'April 15, 2023';
$pattern = '/(\w+) (\d+), (\d+)/i';
$replacement = '${1}, \\2, $3';
echo preg_replace($pattern, $replacement, $string);// April, 15, 2023
영문자, 숫자, _, . 이외 모든 문자 제거
preg_replace("/[^a-zA-Z0-9_\.]/", "", string);
연속된 날짜를 '-' 로 구분하기
$yyyymmdd = '20230517';
$date = preg_replace("/([0-9]{4})([0-9]{2})([0-9]{2})$/", "\\1-\\2-\\3", $yyyymmdd);
echo $date; // 2023-05-17
특정 태그 제거 정규식
tag 만제거
$string = preg_replace("/<tag[^>]*>/ims", '', $string);
$string = preg_replace("/<\/tag>/ims", '', $string);
$string = '나는 <a href="https://onstory.fun">프로그래머</a> 입니다.';
$string = preg_replace("/<a[^>]*>/i", '', $string);
$string = preg_replace("/<\/a>/i", '', $string); // 나는 프로그래머 입니다.
tag 및 tag 안의 내용 제거
$string = preg_replace("/<tag(.*?)<\/tag>/ims", '', $string);
$string = '나는 <a href="https://onstory.fun">프로그래머</a> 입니다.';
$string = preg_replace("/<a(.*?)<\/a>/is", '', $string); // 나는 입니다.
tag 중 닫힘없는 테그 제거
$string = preg_replace("|<tag[^>]*>(.*?)|ims", "", $string);
$string = '이름 : <input type="text" name="adf">';
$string = preg_replace("|<input[^>]*>(.*?)|ims", "", $string); // 이름 :
attribute 제거
$string = preg_replace("|attribute=([^\s^>]+)|ims", '', $string);
$string = '나는 <div onclick="javascript:abc()" class="none"> 프로그래머</div> 입니다.';
$string = preg_replace("|onclick=([^\s^>]+)|ims", '', $string); // 나는 <div class="none"> 프로그래머</div> 입니다.
특정 attribute 를 가진 태그 및 내용제거
$str = preg_replace('/(<div class="my-class"\>.*?<\/div>)/ims', '', $str); // 특정클래스(my-class) 가 있으면 안의 내용 까지 제거
$str = preg_replace('~<a([^>]*)(class\\s*=\\s*["\']my-class["\'])([^>]*)>(.*?)</a>~i', '', $str); // 특정클래스(my-class) 가 있으면 안의 내용 까지 제거
$str = preg_replace('!<center>-(.*?)\/center>!is', "", $str); // 특정 태그 제거
$str = preg_replace('/\[[^]]*\]/','',$str); //[] 삭제및 안의 내용 삭제
모든 개행문자 제거
$str = preg_replace('/\v+/', ' ', $str); // 모든 개행문자를 ' ' 로 변경
연속된 공백 1개로
$str=preg_replace("/\s{2,}/"," ",$str);
태그안에 style= 속성 제거
$str=preg_replace("/ zzstyle=([^\"\']+) /"," ", $str); // style=border:0... 따옴표가 없을때
$str=preg_replace("/ style=(\"|\')?([^\"\']+)(\"|\')?/","", $str); // style="border:0..." 따옴표 있을때
태그안의 width=, height= 속성 제거
$str=preg_replace("/ width=(\"|\')?\d+(\"|\')?/", "", $str);
$str=preg_replace("/ height=(\"|\')?\d+(\"|\')?/", "", $str);
a 태그에서 title 추출
$pattern ="/<a[^>]*title=[\"']?([^>\"']+)[\"']?[^>]*>/i";
html tag 제거 정규식
$content = preg_replace("(\<(/?[^\>]+)\>)", "", $content);
특정 엘리멘트 밑에 추출 정규식
preg_match('/<div id="my2">(.*?)<\/div>/is', $contents, $html);
preg_match("/\<span id=\"moonseller\"\>[^>]\<\/span\>/", $contents, $html);
Table of contents 목차
- Php 정규식 패턴(Regular Expression)
- 패턴 변경자(Pattern Modifiers)
- 특수문자 이스케이프
- Word Boundaries
- 예제
- 정규표현식 관련 PHP 함수