정규식 예제들

Language/PHP 2010. 9. 27. 19:31

 

local get get_path


get = au3.ControlGetText("Total C", "", "TMyPanel2")

 

regex.match( get, ?#(.+)\\#, ?#\1#, "get_Path")

 

win.debugshow( get_Path)

 

 

 

local get get_path


get = au3.ControlGetText("Total C", "", "TMyPanel2")

 

regex.replace( get, ?#(.+)\\#, ?#\1#, "get_Path")

 

win.debugshow( get_Path)

 

 

 

위의 식에서 사용되는 것은

정규표현식 이라고 하는 것이죠. Regular Expression

 

이것도 알아두면 편리할 때가 많습니다.

카페에서 정규표현 또는 Regular Expression 으로 검색하면, 여러 게시물들이 있을 겁니다.

 

이런 내용도 대충만 알면..

그것이 정확히 어떻게 동작하는지는 몰라도,,  알아먹을 수는 있습니다.

 

이게 대충 이렇게 되는 것 아닐까 .. ㅎㅎㅎ 하는 수준.. 사실 그 정도만 해도 됩니다.

마찬가지로.. 필요할 때, 이것을 정규표현 식으로 할 수 있을까.. 라는 생각만 할 정도면 됩니다.

 

PP 는 유틸리티 이므로..

무슨 필요가 있어야만 사용하는 프로그램이죠..

따라서, 어떤 필요... 반복작업, 귀찮음, ....  이런 필요에 의해서 PP를 찾게 되는데..

그 해결방법의 하나로 정규표현 이라는 개념을 알면..  또 더 쉽게 해결할 수 있을지도 모르니까요.

 

 

 

일단.. 기본적인 것들은 .. 사용할 줄은 몰라도.. 대충 알고 있으면, 정작 필요할 때, 정말 도움이 됩니다.

 

 

정규표현 식을 배울려면.. ㅎㅎㅎ 무지무지 한가 보더군요.

이것 역시 책 한 권으로 끝낼 분량이 아닌 모양입니다. ㅎㅎㅎ

 

허지만, 우리가 전문가는 아니고.. 대충 사용할 수 있을 정도면.. 그리 많은 분량은 아닙니다.

http://xpg.in/totalcmd/forum/viewtopic.php?t=329  에 있는 정도.. 그것도 대충만 알아도 큰 도움이 됩니다.

 

 

 

 

일단.. 위에 표현된 정규식 만 생각해 보자면요..

 

?#(.+)\\#, ?#\1#,

 

이것이죠..

 

. (점) 임의의 한 문자

. 은. 점은..

모든 문자 라는 의미입니다. 어떤 글자라도.. 한글, 영문, 숫자.. 기호.. 모든 문자 입니다. 단 하나의 글자이죠.

 

 

 

 

\^     ^  

\[     [  

\(     (  

\|    |  

\+    +  

\{     {  

\.     .

\$    $

\)     )

\*     *

\?     ?

\\    \

\n    줄넘김 문자  

\w    알파벳과 _ (언더바)  

\s    빈 공간(space)  

\d    숫자  

\b    단어와 단어 사이의 경계  

\t     Tab 문자

\r     리턴 문자

\W    알파벳과 _ 가 아닌 것

\S    빈 공간이 아닌 것

\D    숫자가 아닌 것

\B    단어 사이의 경계가 아닌 것

\xnn  16진수 nn에 해당하는 문자

 

(?:pattern)

 

pattern 을 찾지만 검색한 문자열을 캡처하지 않는다. 즉, 검색한 문자열을 나중에 사용할 수 있도록 저장하지 않는 비캡처 검색이다. 이것은 패턴의 일부를 "or" 문자(|)로 묶을 때 유용하다. 예를 들어, 'industr(?:y|ies) 는 'industry|industries' 보다 더 경제적인 식이다.

 

 

 

에효.. 그냥 복사해 왔습니다. ㅎㅎㅎ

 

 

 

 

*, +, ?는 각각 {0,}, {1,}, {0,1}과 같습니다.

 

 

 

\n은 ( ) 하부식 중에서 n번째 하부식을 가리킵니다. 

 

예제) (.+)([ㄱ-ㅎ가-핳]+)([a-z]+)\1+

 

\1로 되어 있으니까 첫번째 부분식 (.+)를 가리킵니다. 위 내용을 해석하자면, 일단 (.+)가 있으니까 이에 해당되는 내용을 찾고, \1+이 있으니까 첫번째 부분식 (.+)와 똑같은 내용이 그 뒤에 1번 이상( + 때문에) 있는 문자열을 찾습니다.

 

이 상황에서

 

\3

은... ([a-z]+) 를 가리킵니다.

 

\2

([ㄱ-ㅎ가-핳]+)  를 가리킬테죠..

 

 

 

우리나라 abcd 1234

 

이런 표현이 있다면..  이 표현을 찾기 위해선..

([가-핳]+) ([a-z]+) ([0-9]+)

이런 패턴이 필요할 겁니다. 띄어쓰기로. 공백을 살려주구요..

 

이 상황에서.

 

\1

은 ([가-핳]+) 이 되겠구요. 그 값은..  우리나라

 

\2

는 ([a-z]+) 이 되겠구요.. 그 값은..   abcd

 

\3

은 ([0-9]+) 이 되겠구요.  그 값은..   1234

 

그러면..

\0

은.. 일단 찾은 모든 것입니다.

그러므로..   우리나라 abcd 1234 이 될 겁니다.

 

 

 

 

 

 

 

자 이제.. 제대로 살펴보죠.. 위의 표를 기준으로..

 

?#(.+)\\#

 

라는 것은..

 

어떤 임의의 문자가 1 개 이상 있다는 뜻입니다.

 

\\  은.. \ 를 가리키는 것이겠죠. 특수문자이므로.. \ 를 앞에 붙여서 \\ 라는 방식으로  \ 를 표현하는 것이죠.

 

따라서 위 문장은..

 

임의의 문자가 한 개 이상 있고. 그 다음에 \ 이 있는 표현..   이라는 뜻일 겁니다.

또 그것을 한 묶음으로 (  ) 본다는 뜻이구요.

 

 

 

 

?#\1#

 

이 표현은 앞 뒤의 # 은 " 따옴표를 대신하는 것이구요.

즉, ?"    "  의 표현입니다. http://cafe.naver.com/powerpro/636  참고..

 

 

\1  이라는 표현은.. 위에서 보면.

 

하부식 중에서 n번째 하부식을 가리킵니다 라고 나오네요..

여기에서는 (  ) 괄호로 묶여있는 것이 1 개 밖에 없으므로.. 당연히

괄호로 묶여 있는 부분을 바로 가리킵니다.

괄호가 여러개 묶여있는 표현에서는.. 첫번째 괄호를 나타내겠죠.

두번째 괄호는 \2  세번째 괄호는 \3 ....  이런 순서일 겁니다.

 

 

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 

 

대충 간단한 표현 몇가지만 일면.. 대충 모든 스크립트가 이해될 겁니다. 다 알필요도 없습니다. ㅎㅎ 항상 말하지만..

 

숫자를 나타낼 때는..

[0-9]  라고 하시면 됩니다.

 

여기서 [  ]  라는 표현은.. 그 안에 들어있는 것 중의 하나를 고른다는 뜻입니다.

즉, 0 에서부터 9 까지의 숫자중에서 하나를 고른다.. 이런 뜻이죠.

 

[0-9]{3}

이것은.. 숫자를 3 개를 고르겠다는 뜻이죠. 즉, 3 자리 정수를 표현하는 방식입니다.

 

그냥 숫자이기만 하면 된다면..

[0-9]+

이렇게 나타내면 되죠.. 몇 자리 수인지는 모르나.. 숫자가 1 개 이상..

 

 

영어를 나타내는 방식은..

[a-zA-Z]

입니다. 마찬가지로. [a-zA-Z]+  해 버리면.. 영어 단어가 되겠죠.

 

한글을 나타내는 방식은..

[ㄱ-ㅎ가-핳] 

이렇게 나타낸다고 하네요. 이론적으로는 맞죠. ㅎㅎㅎ  [ㄱ-ㅎ가-핳ㅏ-ㅣ] 도 맞지 싶네요.

 

 

 

 

 

 

아래의 표현은.. 어디선가 복사해 놓은 것인데요. ㅎㅎㅎ 죄송하고,, 또한 감사.. ^ .^

 

 

^[1-9][0-9]* 

이 표현은.. ^ 이 앞에 있으므로. [ ] 밖에 있는 ^ 기호는 앞에 오는 것이란 뜻입니다.

^The The로 시작하는 문자열

따라서.

0 아닌 숫자가 앞에 오고. 그 다음에는 어떤 숫자라도 몇자리 숫자라도 온다는 뜻이겠죠. * 는 0 이상이므로..

결론적으로... 1 자리 숫자 이상의 숫자라는 의미..

 

 

^(0|[1-9][0-9]*)

이 표현은 ( | ) 를 사용했는데요. | 의 의미는 OR 입니다. 앞이거나 뒤..

따라서,, 0 이거나.. 앞에서 생각한 숫자..

즉, 0 이어도 되고, 숫자여도 되고.. 정도겠죠.

 

 

^(0|-?[1-9][0-9]*) 

이 표현은. 

-? 라는 것은.. - 이 1 개 또는 0 개..

 

*, +, ?는 각각 {0,}, {1,}, {0,1}과 같습니다.

 

? 이 0 또는 1 개 이므로..

앞의 마이너스 - 이 있어도 되고 없어도 되고..

따라서,

0 또는 양수 또는 음수  정도가 되겠네요..

 

 

^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2}) 

그러면.. 이 표현은 무슨 뜻일까요??

 

이렇게 나름 재밌는 것이지만.. ㅎㅎㅎ

실제로 적용할려고하면. 무수한 삽질이 필요한 것 같더군요. ㅎㅎㅎ

수족이 고생한다는..

 

또 그래서 그런 면에서.. 뭔가 하는 것 같기도 하고.. ㅎㅎㅎ

뭐 거창한 것 다루는 느낌도 들구요. ㅎㅎ

 

그런 재미가 있습니다. 이것에도요..

 

 

-------------------------------------------------------------------------------------------------

 

 

 

우리나라 만세(萬歲)

 

라는 표현이 있다고 하죠..

 

그런데..

이 문서에서. (  ) 를 몽땅 지우고 싶습니다. 어떻게 해야 할까요?

한글이라고 가정하면. 이렇게 하면 될 겁니다.

 

 

RegEx.replace(input,?#([가-핳]+)\(.*\)#,?"\1","output")

 

즉..

한글이 몇 글자이든 하나의 묶음으로 보고, 그 다음에 ( 이 오고.. .* 어떤 글자라도 오며, 그 다음에 ) 이 오는 형태

 

그런 형태를 찾아서..

첫번째 묶음 \1 로 바꿔라..

 

첫번째 묶음은.. 괄호 앞에 오는 한글이죠..

따라서,, 괄호와 한문은 몽땅 없어지게 되는 것이죠.

 

 

생각해 보면.

알아두면 편리할 때가 많을 것 같습니다.

 

 

ㄴㅇㄻㄴㅇㄹ

 

 

http://www.egocube.pe.kr/asp_0003.asp 

 

비교적 간단한 경우인 핸드폰 번호를 정규 표현식 패턴으로 만들어 보도록 한다. 핸드폰 번호는 일반적으로 이통사의 고유 번호 3 자리, 국번 3 자리, 끝 번호 4 자리로 이루어진다. 여기에서 각 번호간의 구분은 '-' 로 한다고 임의로 정하도록 하겠다. 즉, '123-456-7890' 과 같은 형태가 된다고 가정하는 것이다.

\d    숫자  

 

\d    숫자 


 

위의 표를 살펴보면 메타 문자 '\d' 가 숫자 문자 한 문자를 나타낸다는 것을 알 수 있다. 따라서 다음과 같은 정규 표현식 패턴을 만들 수 있다.


    \d{3}-\d{3}-\d{4}



여기까지는 매우 쉽게 이해될 것이다. 즉 이 정규 표현식 패턴이 의미하는 바는 숫자 3 글자 다음에 '-' 기호가 나오고, 그 다음에 또 다시 숫자 3 글자가 나오고 그 다음에 또 '-' 기호가 나오고 마지막으로 숫자 4 글자가 나온다는 의미인 것이다. 그런데 요즘은 핸드폰이 워낙 많이 보급되다 보니 국번의 경우 3 자리 번호만 가지고서는 숫자가 많이 부족하게 되었다. 그래서 이젠 국번이 4 자리인 핸드폰 번호도 주변에서 심심치 않게 접할 수 있는 것으로 알고 있다. 그렇다면 이와 같이 4 자리 국번을 가진 핸드폰 번호를 수용할 수 있도록 하기 위해서는 위의 정규 표현식 패턴을 어떻게 바꾸는 것이 좋을까? 아마 다음과 같은 방법도 있을 수 있을 것이다.


    \d{3}-(\d{3}|\d{4})-\d{4}



폰트 때문에 보기가 좀 힘들겠지만 파이프 문자 (|) 는 마치 OR 연산자와 같은 역활을 한다. 따라서 위와 같이 파이프 문자와 소괄호를 함께 사용하면 지금과 같은 문제를 쉽게 해결할 수 있다. 그런데 이와 같이 변형된 정규 표현식 패턴은 비록 틀렸다고 말할 수는 없겠지만 아직 해결해야 할 문제점들을 몇 가지 가지고 있다.


그 중 한 가지 문제점은 소괄호 때문에 발생하는데, 이는 정규 표현식 패턴상에서 소괄호가 매우 특이한 기능을 한 가지 가지고 있기 때문이다. 이에 대한 더욱 자세한 내용은 Replace() 메소드에 관하여 설명하면서 다시 언급하겠지만 바로 '역참조' 라는 기능 때문인데, 대상 문자열이 정규 표현식 패턴과 일치할 경우 소괄호 안에 감싸인 문자열 부분은 메모리상에 미리 지정된 이름의 변수로 저장이 된다. 따라서 지금과 같이 저장된 내부 변수를 재사용하지 않는 단순한 예에서는 쓸모없이 메모리만 낭비하는 셈이다. 결국 이 정규 표현식 패턴은 다시 다음과 같이 수정된다.


    \d{3}-(?:\d{3}|\d{4})-\d{4}



이와 같이 수정하고 나면 비로서 메모리에 아무런 변수도 생기지 않는 효율적인 정규 표현식 패턴이 만들어진다. 그러나 아직도 또 다른 문제점이 하나 남아있는데 현재 상태와 같은 정규 표현식 패턴은 대상 문자열 내부에 패턴과 일치하는 문자열이 존재하기만 하면 무조건 그 조건이 만족된다. 따라서 만약 실무에서 원하는 작업이 사용자들로부터 정확한 핸드폰 번호를 입력받기를 원하는 것이라면 완벽한 해결책은 되지 못하는 셈이 된다.


구체적으로 말해서 우리가 원하는 '123-456-7890' 또는 '123-4567-8901' 과 같은 형태의 핸드폰 번호 뿐만이 아니라 전혀 쓸모없는 문자가 포함된 ' 123-456-7890' 라든가 '123-456-7890 ABC' 와 같은 형태의 문자열까지도 조건을 만족하게 되는 것이다. 따라서 순수한 핸드폰 번호 그 자체만을 만족시키려면 또 다시 다음과 같이 수정되어야 한다.


    ^\d{3}-(?:\d{3}|\d{4})-\d{4}$



위의 표에서 찾아보면 알 수 있듯이 '^' 은 문자열의 맨 처음을, '$' 는 문자열의 맨 마지막을 의미한다. 따라서 이와 같이 수정된 정규 표현식 패턴은 핸드폰 번호 그 자체 외에는 어떠한 문자열도 조건을 만족시키지 않게 되고, 이제서야 비로서 어느 정도 만족할만 하게 작성되었다고 말할 수 있을 것이다.


그러나 한 가지 유의해야 할 점은 정규 표현식의 패턴에는 정답이 없다는 것이다. 그 단적인 예로 이 정규 표현식 패턴은 실무적인 요구 조건에 대하여 좀 더 명확한 유효성을 보장받기 위해서 또 다시 다음과 같이 수정될 수도 있다.


    ^0(?:11|16|17|18|19)-(?:\d{3}|\d{4})-\d{4}$



이 정규 표현식 패턴은 현실 세계에 실제로 존재하는 이통사의 번호만을 만족한다. 이처럼 정규 표현식 패턴은 좀 더 효율적인 패턴과 좀 더 비효율적인 패턴으로 구분될 수 있을 지는 모르겠지만 사지선다형 문제에서와 같은 확실한 정답은 없다는 것이 필자의 개인적인 의견이다.

'Language > PHP' 카테고리의 다른 글

inconv, 인코딩  (0) 2010.10.19
php 파일처리 관련함수  (0) 2010.09.28
[PHP] 세션 만료 시간  (0) 2010.09.15
timestamp  (0) 2010.08.31
substr  (0) 2010.08.19
: