= 정규식 해석 엔진 =
정규식 아시져?? 헤헤
가끔씩 정규식 보믄 , 무슨 외계어 같은거고 잘 모르겠고
뭔가 좋은거 같은데 막상 쓰려니 막막하고 그러지 않나여??
흠
현재의 정규식들은
기능이 굉장히 많이 확대되서
심지어는 정규식이 아닌 수준임 ( 나중에 설명하꼐요)
그렇지만 본래 제시된 정규식은
다음의 세가지 요소와 괄호 개념으로만 이뤄졌어요
(a) : 괄호 정규식을 묶어버리죠, 사칙연산 수식에서 괄호처럼 생각하면 댐,
a|b : 유니온(union) , 이건 OR 관계 처럼 보면 되요, a 아니면 b
ab : concatenation , 어떤 기호가 없이 그냥 문자만 있지만 그 사이사이가 연결된 거에요, ab 이렇게 붙어서 나오는거죠
a* : star-closure , 그냥 클로져 라고 해요, 왜 이름이 Closure 일까요? 이거슨 정수론에서 \"정수집합에서 + 연산은 닫혀있다\" 라는 말이랑
비슷한 개념인 거에요, 근데 좀 받아들이기 힘들죠?? 수학적인 개념은 때려치우고
그냥 앞에 있는 대상을 0번 이상 반복 한다고 생각하세요
이 세가지를 가지고 지지고 볶으면, finite automata 가 인식할 수 있는 모든 스트링을 \"인식\" 할 수 있다고 해요
위 세가지 연산자들도 , 사칙연산과 같이 우선순위가 있어요
[공식적인 정규식 연산자 우선순위]
closure > concatenation > union
주의할점은 concatenation이 어떤 기호가 없다고 연산이 없다고 생각하시면 안됨,
두개의 스트링을 연결시키는 연산인 거임 ㅇㅇ
세가지 연산자를 지지고 볶아보죠
예를 들면요
RE: l(ik|ov)e~*
가 있어요, 정규식에 있어서 아주 고전이죠
우선 스트링들 \"like\", \"love\" 인식 할 수 있겠죠? 가운데 두 글자가 union 으로 묶여서 앞에놈 아니면 뒤엣놈 하나 선택이라서요
\"like~\", \"like~~\", \"like~~~\", .....
\"love~\",\"love~~\", \"love~~~\", .....
클로져가 ~ 문자를 0번 이상 반복 시키죠
흔히 보던 정규식보다 너무 간단해 보이죠??
근데, 저 \"공식적\" 인 정규식은
현재 가장 활용성 짱??이라는 펄 정규식하고 비교를 하면....
파워는 똑같아요 !! 레알임
다만 사용하기 빡치는거죠
몇가지 빡치는 예를 들면요
스트링이 주어졌을때
이게 숫자로만 이뤄졌는지 판단하려고 해요
최소한 숫자 하나라도 있는가 알아보는 정규식은
RE: (0|1|2|3|4|5|6|7|8|9)(0|1|2|3|4|5|6|7|8|9)*
ㅋㅋㅋㅋㅋㅋ 존내 구리죠??
그럼 이런건 어떤가요
\'영문자 알파벳으로만 이루어진 스트링\'
\'영문자 대소문자 알파벳 혹은 언더바하나 혹은 숫자 로만 이루어진 스트링\'
(a|b|c|d.......
어휴 쓰기 빡쳐서 원
다 쓰기도 짜증나고 그렇죠?
이제 지금부터는 확장 정규식 개념이 들어감
위 빡치는 예를 해결하기 위해서
확장 정규식에서
문자클래스 라는 개념을 도입했어요
다 아실듯, 심지어 C언어 scanf 에서도 어설프게 쓰여요
[0-9] , [a-z], [A-Z], [a-zA-Z0-9_]
뭐 이런식으로 쓰고 어떤 의미인지 알겠죠??
위와 같이 주로 \"범위\" 의 개념을 나타내지만
본래 문자클래스의 역할은..
RE: [ahz] , a 나 h나 z 중에 하나 선택
이런거에요
무조건 \"문자 한개\" 에만 대응되요
여러개 대응되는가 보려면 클로져를 달아주면 되겠죠??
RE: [^aeiou]
위와 같은 경우는 문자 클래스 맨 앞에 \'hat\' 이 쓰였죠?? 이 정규식의 의미는?
a,e,i,o,u, 를 제외한 다른 문자들이 가능 한 거에요, 즉
맨앞에 \'hat\' 이 붙으면 부정의 의미를 지니는 거죠...
어 그럼 \'^\' 문자 자체를 문자클래스 안에서는 못쓰는 것인가?? 하는 의문이 생길수도 있는데
\'^\' 를 쓰려면 그냥 맨앞에 안써주기만 하면 되요
RE: [a^] 이것 처럼요
quantifier 확장
위에 기본 정규식에서 클로져 있자나요??
이놈을 quantifier 라고 불러요, 수량자?? 라고 불르죠
근데 0번 이상 반복, 말고도
1번 이상 반복도 하고 싶고 그렇단 말이죠
그래서
a+ , 플러스가 붙으면 앞 대상을 1번 이상 반복한다 생각하시믄 대여
a? , 앞 대상이 있을 수도 있고 없을 수도 있는 거에요
동일한 효과가 날법한 정규식 써보면
RE: (a|) 이건 불가능해요 , 근데 되는 정규식 엔진도 있대요
+ 가 수량자임은 그럴싸해도
? 가 수량자라고 하기엔 좀 빈약한거 같죠??
근데 실제 내부적으로 비슷하게 동작해요...
Escape
정규식을 잘 보면 이런 경우가 생길수도 있음을 알수 있죠
\"어 난 \'(\' 문자 쓰고 싶은데 어뜩하지?? , 난 * 문자 쓰고 싶은데 이건 클로져를 의미해서 못쓰는데...\"
할 수 있죠
이런 특수기능을 하는 문자 자체를 쓰고 싶은 경우가 생기는데
이때 이 문자를 가지고 이런 특수기능에서 문자를 escape \"탈출\" 시켜 그냥 그대로의 문자로 인식하게 할 수 있어요
방법은 ...
앞에 \\ 문자를 붙이는 거죠...
그래서 저 문자는 \"원(윈도우기준)\" 도 아니고 \"역슬래쉬\" 라고 부르지 않고 그냥
escape문자라고 불러요
RE: \\(\\)ab\\* 근데 이건 정규식 엔진마다 달라요, VIM은 \\ 를 붙여야 특수기능이 살아나더라고요
그외 몇가지 특수 escape
escape라고 보기엔 뭣하지만
escape 문자와 결합하여
특수기능을 오히려 살리는 경우가 있어요
주로
RE: \\n \\t
같이 공백을 나타낼때 주로 씀 ㅇㅇ
그외 여러가지 많은데요 진짜
확장하기 나름이에요
다음엔
이 확장 정규식을
Strong LL(0) 이라는 파싱방법을 사용하여
인식하게 만들어 볼꺼에연
이거 따라서 배우면 컴파일러 만들수있나연?
공지로~~~~~~~~~~~~~!
음.. 내가 예전에 as에서 정규식만 써서 as파서 만들면서 궁금했던 게 특정 구문을 제외한 구문만 찾는거였어... 예를 들어서 abcde cde란 문장이 있을때 모든 cde를 찾는데 만약 앞에 ab와 이어지면 그건 제외하는거지... 이건 정규식으로 안 되는거 맞죠? 그게 유일하게 걸렸던 문제인데 답이 없어서 좀 편법을 썼었던듯
정규식이 인식하죠
정규식이 인식 못하는 예는, \" 양끝으로 짝이 맞는 스트링\", \"뒤집으면 똑같은 스트링\"..... 과 같이 이전에 \"기록\" 이 되어야만 하는 경우는 불가능 한데 위의 경우는 ab 로 시작하면 제외하면 되잖아요
[^a][^b][a-b]* 이런식으로 쓰면 최소 2글자, 맨앞에 a가 오지 않고 그 다음에 b가 오지 않는 스트링의 집합 을 나타내겠죠
아 LALR이니 LL이니 하던거 다 까먹었네 시밤ㅋ shift 랑 reduce밖에 기억이 안낰ㅋㅋㅋㅋㅋ
[^a][^b].* <- 이게 더 정확할 듯 \'.\' 문자는 \'모든문자\' 를 의미해요 위 댓글은 ab가 앞에 오지 않는 소문자로 이루어진 스트링, 이 되겠구요
좀 더 정확히 말하자면 1203=52103$1203abc555 이런식으로 숫자와 글자가 섞인 문장이 있을 때 $+숫자로 된 경우를 제외한 모든 숫자(하나의 수로 볼 수 있는)들만을 찾아야만 했지. [^$0-9][0-9]+로 찾으면 찾을 수 있겠지만 문제는 숫자가 아닌 문자까지 같이 딸려서 들어간다는거였고. 정규식만으로는 처리가 안 되는거 같은데 이건. 즉 순수하게 특정한 대상만 찾고자 하면서 동시에 그 대상이 특정 문자와 이어지면 안된다는 것
어려운거 하네 고생이십니다.ㅋㅋ
t 횽 의 예는 그냥 간단하게 떠오른 생각은 DFA 를 써서 $ + 숫자들 을 인식하는 정규식을 사용해서 인식시킨뒤 그냥 스킵하는 방식인데 엄밀하게는 인식한다고 보긴 어렵겠네요, 근데 제가 생각할땐 정규식으로 가능한데, 말도 안되는 식,,, 그러니까 다 써줘야 될거 같아요
NFA 에선 capture 를 쓸수 있으니가요 쉽게 되고..
음... 그렇군요. NFA와 캡쳐가 뭔진 모르겠는데 캡쳐는 actionscript에서도 지원이 되는것 같기도... 내가 잘 몰라서 그렇지. 아무튼 그땐 아무래도 정규식으로는 어렵다고 느껴서 결국 모든 종류의 $+숫자를 제거했었제. 좋은 글인데 뻘질문으로 주제를 벗어난 댓글을 늘려버렸네요 답변 고맙습니다.
스크립트언어가 대부분 NFA 엔진이고 캡쳐를 쓸수 있어요, 대단한건 아니고 괄호로 싸면 [^$0-9]([0-9]+) 괄호로 둘러싸인 영역은 $1 처럼 쉽게 가져올수 있어요