728x90
반응형

찾고 바꾸기를 할 때 이런 고민을 해보신적이 있는가?

 

"아이.. '대두족장'이나 공백이 들어간 '대두 족장'이나 한꺼번에 찾으면 좋을텐데...귀찮게 꼭 두번 일하네..."

 

패턴인식할때 경우의 수가 자주 생긴다.

 

그러니까...

 

패턴 인식: 대두족장 또는(or) 대두 족장

 

이 경우의 수를 컴퓨터에게 가르쳐 줄 수 있냐는 거다.

 

정규식이라면 가능하다. 바로 저 or 에 해당하는 정규식 기호가 | (영어로 pipe character라고 한다. backslash, 즉 한글 키보드 자판에서 원화 표시 있는 키를 shift 누르고 칠때 나오는 문자) 이다.

 

찾기 패턴: 대두족장|대두 족장

 

정규식 처음 배우는 분들이 자주 하는 실수가 있다. 바로 공백( )을 헷갈리는 경우다. 저 찾기 패턴 역시 다음처럼 실수하기 쉽다.

 

잘못된 찾기 패턴: 대두족장 | 대두 족장

 

| 기호 전후로 공백이 들어가 있다. 이렇게 하면 대두족장이나 대두 족장에 공백이 하나 붙어 있는 경우를 찾는다. 공백도 엄연한 문자라는 사실을 잊어서는 안된다. 까먹지 말자. 공백 실수 무지 많이한다.

 

 

원본 텍스트가 다음과 같다고 할 때 대두족장대두 족장 모두를 찾는다.

 

나는 대두족장이라고 합니다.

가끔 대두 족장이라고 하는 사람들이 있는데 잘못된 표기입니다. 대두 족장이 아니라 대두족장입니다.

그러니 앞으로는 대두 족장이 아닌 대두족장이라 불러 주세요.

대두족장 드림

 

 

 

찾기 패턴에 다른 기호 및 문자까지 합쳐 쓰고 경우의 수가 많아지면 어디까지가 경우의 수를 말하는 지 컴퓨터가 오해할 수 있다 그럴때는 괄호로 경우의 수 부분만 감싸줘야 한다. 다시 말해 앞에 나온 찾기 패턴은 다음처럼 해도 된다는 말이다.

 

찾기 패턴: (대두족장|대두 족장)

 

다른 문자열이나 기호화 함께 쓸 때 헷갈린다는 게 어떤 의미인지 예를 들어 보자.

 

http://blog.naver.com - 네이버 블로그

 

http://naver.com - http://www.naver.com 와 같은 의미

 

http://cafe.naver.com - 네이버 카페

 

http://news.naver.com - 네이버 뉴스

 

http://100.naver.com - 네이버 백과 사전

 

네이버에서 자주 쓰는 URL이다. 이외에도 많지만 이 정도만 하자.

 

자, URL이 수백개 들어 있는 텍스트 문서에서 네이버 관련 URL만 모두 찾아서 어떤 작업을 하고 싶다고 생각해 보자.

 

가장 간단한 삽질은 저걸 일일이 다 찾는거다. 정규식 안쓰고 걍 단순 찾고 바꾸기로...

 

정규식을 쓰면 요런게 가능하다.

 

찾기 패턴: http://(blog|cafe|news|100)\.naver\.com

 

이렇게 해주면 http:// 로 시작해서 .naver.com 이란 패턴이 나오기 전에 blog cafe news 100 이란 단어가 들어간 모든 URL을 찾아준다는 말이다. 그러니까 blog cafe news 100 요걸 괄호로 감싸고 각 경우의 수를 파이프 문자 | 로 구분해주면 그 중 하나에 해당하는 단어가 발견될 경우 찾아주고 어느 경우에도 해당되지 않으면 넘어간다.

 

따라서, 앞에 나온 URL은 다 찾아도 다음 URL은 개무시를 하게 된다.

 

http://item.naver.com

 

 

(blog|cafe|news|100) 요 정규식 패턴 안에  item 이 없기 때문이다.

 

지난회 머리 긁적거리다 그냥 넘어온 분을 위해 다시 잔소리를 하면... 마침표(.) 기호는 정규식에서 어떤 한개의 문자와도 일치한다는 특별한 의미로 사용된다고 했다. 따라서, URL에서 우리가 흔히 '쩜'이라고 하는 부분을 일치시키려면 \. 으로 써줘야 정규식 기호의 특별한 의미를 탈출해서 쩜의 의미를 갖는다. 그래서 찾기 패턴 뒷부분이 이렇게 생긴거다.

 

\.naver\.com

 

실제로 '대두족장 편집기'에서 한번 찾아보자.

 

 

역시 네이버 아이템 골짜기 URL과 .naver.com 앞에 아무것도 없는 경우만 제낀다.

 

파이프 문자가 바로 '대두족장 편집기'에 매크로로도 저장돼 있는 관사 찾기 패턴의 비밀이다.

 

영어 관사 찾기 패턴: (A |An |The | a | an | the )

 

짱구를 굴려 보시라. 관사 찾기 패턴의 경우 공백이 유용하게 쓰이고 있다는 점 주의하시고...

 

영어 관사는 세가지다. 부정관사 a, 모음으로 시작하는 단어 앞에 나오는 부정관사 an, 그리고 정관사 the.

 

요걸 다 찾으려면 일단 america 식으로 단어에 포함된 a는 찾지 말아야 한다. 그래서 a an the 의 경우 앞 뒤로 공백이 있어야 관사라고 인정할 수 있다. 물론, 컴퓨터는 패턴만 보고 찾는거지 실제로 a 가 관사가 아닐 수도 있다. 관사 패턴을 찾는 것 뿐이다.

 

또, 관사는 문장 첫부분에 올 수도 있다. 게다가 줄시작 부분에 오는 경우는 관사 앞에 공백이 없을 수도 있고...

 

그래서 대문자 관사의 경우는 앞에 공백을 붙이지 않았다. 100% 완벽한 관사 찾기 패턴은 아니지만 90% 이상 관사를 잡아낸다.

 

패턴을 적용할 때 또 한가지 주의할점은 대소문자 구별이다. 분명 a 와 A의 패턴이 대소문자로 다르기 때문에 대소문자 구별을 해줘야 한다는 거다. '대두족장 정규식 편집기'에서 대소문자 구별 체크 상자를 클릭하고 찾기를 눌러야 제대로 적용된다.

 

 

괄호는 경우의 수를 묶어주는 의미도 있지만 바꾸기 패턴에서 활용할 패턴 부분을 지정하는 역할도 한다고 했다. 여기서는 관사를 찾아 그 부분을 기억하라는 의미이고 괄호가 하나 뿐이기 때문에 바꾸기 패턴에서 \1 로 바꾸기 패턴에서 찾아 기억한 관사 부분을 활용할 수 있다.

 

\ 는 문자의 기본적인 의미를 탈출시키는 거라고 했다. 그러니 \1는 1이라는 숫자의 의미를 탈출시켜 찾기 패턴에서 괄호로 감싸준 부분을 의미하게 된다. 괄호가 두개였으면 \2 로 두번째 괄호 부분을 지정해 주는거다. 세개면 \3, 네개면 \4 가 된다.

 

역시 헷갈릴지 모르니 다시 잔소리한다. 괄호 부분을 기억한다는 건 (A |An |The | a | an | the ) 요걸 기억한다는 게 아니라 괄호 패턴으로 찾아낸 a an the A An 을 기억한다는 거다. (A |An |The | a | an | the )패턴에 어떤 문자가 걸릴지는 컴퓨터도 찾기를 실행해 봐야 알 수 있다. 예를 들어 컴퓨터가 다음 문장을 읽어나가며 찾기를 실행한다고 생각해 보자.

 

She's a girl.

 

 

 a 부분이 앞뒤로 공백이 있으므로 (A |An |The | a | an | the )패턴의 경우의 수에서  에 해당한다. 요걸 \1 로 나중에 써먹을 수 있다는 말이다. 만약 바꾸기 패턴이 다음과 같다면...

 

바꾸기 패턴: <b>\1</b>

 

찾기 패턴으로 찾아낸 관사를 <b></b> (웹페이지에서 굵은 글씨를 나타내는 HTML 태그)로 감싸주라는 말이다. 그래서 결과적으로 요렇게 된다.

 

She's<b> a </b>girl.

 

정규식의 진정한 빠우어~ 는 바꾸기에 있다고 했다. 찾기로 별의별걸 다 찾아서 그걸 바꾸기 패턴에서 조물딱 거리며 역시 별의별 짓을 다할 수 있기 때문이다.

 

| 기호 이외에 아주 자주쓰는 정규식 골라 골라~ 형식이 있다. 이른바 문자 집합을 지정하는 경우인데 []  안에 원하는 문자 집합을 나열해 그 중 하나만 일치하면 된다는 걸 컴퓨터한테 가르쳐 줄 수 있다.

 

찾기 패턴: [abc03]

 

요따구로 정규식을 지정해주면 a b c 중 문자 한개 또는 0이나 3 이라는 숫자 한개와 일치하면 오케이다.

 

그래서...

 

찾기 패턴: [abc03]00

 

요렇게 찾으면 이런 패턴이 검색된다는 말이다.

 

패턴 인식: a00 b00 c00 000 300

 

| 파이프 기호와 다른 점은 문자 한개만 경우의 수로 지정할 수 있다는 거다. 파이프는 대두족장|대두 족장 이딴게 되지만 [] 는 한자릿수 문자 집합을 가리키기 때문에 문자 한개만 지정할 수 있다.

 

[] 의 또 한가지 특징은 범위 지정이 가능하다는 거다. 앞에서도 한번 언급했다. 일정한 범위가 있는 알파벳이나 숫자는 다음처럼 지정할 수 있다.

 

영문 소문자 알파벳 찾기 패턴: [a-z]

 

영문 대문자 알파벳 찾기 패턴: [A-Z]

 

숫자 찾기 패턴: [0-9]

 

영문 대소문자와 숫자를 몽땅 찾으려면 이렇게 하면 된다.

 

영문 소문자 알파벳 찾기 패턴: [a-zA-Z0-9]

 

또 헷갈릴까봐 잔소리 한다. [a-zA-Z0-9] 이건 ab0 ac0 이딴 걸 찾으라는게 아니고 한자릿수 문자만 찾돼 그게 영문 알파벳 소문자, 대문자, 숫자랑 일치하면 오케이라는 말이다. [] 안에 들어가면 무조건 그 중 문자 한개와만 일치하는 거니 헷갈리지 말자. 괜히 제목이 '골라 골라~' 겠는가^^

 

고르는게 있으면 안고르는 것도 가능하다. 부정이 가능하다는 말이다. [] 문자 집합에 들어가지 않는 놈만 골라라~ 이딴 것도 된다. 부정을 의미할때는 [] 에 문자 집합을 나열하기 전에 맨앞에 ^ 기호 를 써주면 된다. [] 밖에서 ^ 는 지난회에서 설명했듯이 줄의 시작을 가리키지만 []  안에서는 문자 집합을 부정하는 의미로 쓰인다.

 

영문 소문자 알파벳을 제외한 모든 문자 차기 패턴: [^a-zA-Z0-9]

 

이러면 뭔 짓을 하냐고?

 

요딴 거 찾을 수 있다.

 

 

 

그렇다. 안타까운 일이지만... 정규식은 외넘들이 만든 장난감이다. 아니, 컴퓨터라는 게 외넘들이 만든거라... 한글은 언제나 골치를 썩는다.

 

위 찾기 패턴은 영문과 숫자만 남기고 그 이외의 모든 문자를 찾으라는 말이니, 한글, 문장부호, 공백을 모두 찾는다.

 

요거 어디 응용하느냐고?

 

잘 생각해보시라. 한글과 영어가 짬뽕돼 있는 통합 자막이라는 게 있다. 여기서 영어만 남기고 한글 날리고 싶으면 어떻게 하면 되겠는가? 문장부호는 있어야 할테니 한글 부분만 없애야 한다면...

 

한글 날리기 찾기 패턴 1: [^ a-zA-Z0-9!?.']

 

대소문자를 구별 안할거면 a-zA-Z 는 그냥 a-z라고만 써도 된다.

 

한가지 주의하자. 공백! 공백! 공백도 문자라고 했다. 문자 집합에 한글 이외의 모든 문자를 지정하려면 공백도 지정해줘야 한다. 안그러고 날려버리면 공백까지 찾아 모두 지워버리는 불상사가 생긴다. 앞 패턴을 잘보면 ^ 와 a 사이에 공백이 들어가 있다. 빨간색으로 된 공백이 눈에 보일거다.

 

 

조따구로 해주고 바꾸기 입력창에 아무것도 넣지 않고 바꾸기를 하면 한글을 몽창 날려버린다.

 

문자 집합 특징 하나 더 있다. 까먹을뻔 했다. 문자 집합에서는 ^ 를 제외한 모든 문자가 문자 고유의 의미로만 쓰인다. 그러니까 escape를 해줄 필요가 없다. 원래 생겨먹은대로 쓴다는 말이다.

 

문자 집합: [a-zA-Z0-9.,'?!]

 

마침표나 물음표 등은 정규식에서 특별한 의미로 쓰이기 때문에 패턴에 적용할때 \ 로 이스케이프를 해줘야 하지만 문자 집합에서는 어차피 문자 하나로 쓰이는 걸 알기 때문에 안해줘도 된다는 거다. 물론, 해줘도 상관없다. 의미가 없을 뿐이란 말이다.

 

어떤 분 질문한다. 그럼 ^ 가 문자 집합에서 특별한 의미라면 문자 집합에 ^ 문자도 선택할 수 있도록 집어넣으려면 어떻게 하느냐고...

 

별 문제 없다. ^가 문자 집합에서 문자 집합을 부정하는 기능을 하는 건 가장 처음에 쓸 때 뿐이다. 문자집합속에 집어넣어버리거나 \로 이스케이프시켜주면 그 기능이 사라진다.

 

^를 포함한 문자 집합: [a-zA-Z0-9.,'?!^] 또는 [\^a-zA-Z0-9.,'?!]

 

 

 

근데...

 

아뿔싸... 한글을 글자단위로 날리면 이딴 문제가 생긴다. 한글 문장에 담겨 있던 문장부호와 숫자 등이 남아 문서가 뒤죽박죽 된다.

 

그러니 좀더 짱구를 굴려 '한글이 포함된 줄은 한글 자막줄'이라고 여겨 해당줄을 몽땅 날리는게 낫다.

 

이런 통합 자막이 있다고 하자. 통합 자막이 뭔지 모르는 분은 그냥 한글 자막과 영어 자막이 섞여 있는 또는 해석이 나와 있는 영문자막 문서라고 여기면 된다.

 

니가 튜니티냐?
Are you Trinity?
넌 누군데?
Who's asking?
묻는 말에 대답이나해 짜샤!
Just answer my question, shithead!

Trinity가 내 이름이긴 한데...

Trinity is my name, okay.

 

여기서 한글 줄 다 날리고 영어 자막 부분만 남겨놓아 영어 대본으로 쓰고 싶다는 말이다. 정규식 패턴을 만들때는 사람이 패턴인식하는 순서대로 짱구를 굴려나가야 한다.

 

1. 한글 문장은 한글로 시작한다. -> ^[^a-zA-z0-9]

 

2. 그런데 마지막 문장을 보니 한글 문장도 영어로 시작할 수 있다ㅡ.ㅡ 그러므로 1번 패턴은 적용 불가.

 

3. 공통적인 패턴은 어떤 문자로 시작했건 (1-2번 절충) 중간에 한글이 나온다는 거다. -> ^.*[^a-zA-Z0-9]+$

 

찾기 패턴: ^.*[^a-zA-Z0-9]+$

 

패턴을 분석해 보면

 

^ : 줄의 시작이...

 

.* : 어떤 문자가 0번 이상 반복되고... (.* 은 이른바 정규식 이디엄이다. '어떤 문자가 0번 이상 반복되고...'의 의미다.)

 

[^a-zA-Z0-9]+ : 알파벳대소문자나 숫자가 아닌 문자가 1번 이상 반복되고...

 

$ : 줄이 끝난다.

 

사람이 알아듣는 말로 풀이하면...

 

"줄이 시작되고 어떤 문자가 나오건 안나오건, 몇번이 나오건 상관없고 그 다음에 알파벳대소문자나 숫자가 아닌 문자가 1개 이상 반복된다음 줄이 끝나는 패턴을 찾아라."가 된다.

 

근데...

 

설명은 그럴듯하지만... 실제로 찾아보면 이따위로 찾는다.

 

 

다시 말해 모든 줄을 찾는다는 거다. 사람이 굴리는 짱구와 컴퓨터가 알아듣는 말이 달라서 그런다.

 

^.*[^a-zA-Z0-9]+$

 

요기서 컴퓨터는  [^a-zA-Z0-9]+ 요 부분이 문장부호나 공백도 포함하기 때문에 알파벳대소문자와 숫자의 1번 이상 반복이라는 걸 한글뿐만이 아닌 모든 기호가 1번 이상 반복되는 걸로 알아듣는다. 그래서 문장부호나 기호가 들어간 줄도 몽땅 찾는다.

 

물론, 문장부호나 기호를 문자셋([])내에 몽땅 써주는 무식한 방법도 있지만 그것도 삽질이다.

 

한글이 포함된 줄을 날리는 건 두가지 경우라고 했지 않는가. 한글로 시작하는 경우와 영문이나 숫자로 시작해서 한글이 뒤따라오는 경우...

 

그럼 파이프 문자 써서 두가지 패턴 중 골라 골라~ 하면 그만이다.

 

한글 포함 줄 날리기 찾기 수정 패턴: ^[^a-zA-Z0-9]+$|^[a-zA-Z0-9]+[^a-zA-Z0-9]+$

 

가운데 골라 골라~ 파이프 기호를 유심히 봐야 한다. 그 앞뒤로 '한글로 시작해서(알파벳대소문자와 숫자가가 아닌 문자)가 1개 이상 반복되고 줄이 끝나는 패턴' 또는 (|) '알파벳이나 숫자로 시작한 다음 한글이 1개 이상 나오고 줄이 끝나는 패턴'을 지정해주고 있다.

 

요놈을 집어넣으면 한글 줄만 제대로 찾는다.

 

 

 

물론, 이것도 정답은 아니다. 정규식에 정답이란 없다. 한글 자막줄이 느낌표 등 기호로 시작하지 말라는 법 없고 (느낌표도 알파벳대소문자나 숫자 문자 집합에 포함되지 않는다) 분명 생각지 못한 패턴의 한글 문장이 등장할 수 있다.

 

그럴때는 패턴을 수정해나가야 한다. 가장 최적의 패턴이 만들어질때까지.

 

잘 보면 알겠지만 정규식 패턴은 조금만 길어져도 눈이 돌아갈 정도로 헷갈리기 시작한다.

 

'대두족장 정규식 편집기'에 괜히 매크로 저장기능 만들어 놓은게 아니다^^

 

정규식의 달인이라는 사람들도 정규식 패턴이 조금 길어지면 앞에 설명한 것처럼 스스로 주석(comment)이라는 걸 달아서 따로 메모해둔다. 안그러면 오랜 시간 지난다음에 그 패턴의 부분 부분이 무슨 의미인지 까먹기 때문에 다시 이해하려면 골치아프니까.

 

정규식 패턴을 쉽게 만들고 메모까지 쉽게 하려면 일단 사람한테 설명하듯 패턴을 말로 풀어놓은다음 그걸로 패턴을 만들고, 패턴이 잘못됐을 경우 말을 다시 수정하고 다시 패턴을 만들고...를 반복해야 한다.

 

어려워진다고 희망버리지 마시고 짱구 많이 굴리시라.

 

정규식은 짱구 많이 굴려야 제대로 배울 수 있고 활용할 수 있다.

 

개인적으로... 정규식으로 짱구굴리고 살면 평생 치매 걸릴일 없다고 믿는다.

 

오늘 짱구 너무 굴려 오바히트됐을테니 쓸만하고 간단한 정규식 패턴 하나 알려주고 끝내련다.

 

패턴 인식: "이렇게 인용부호 안에 들어간 말들만 골라내려면 어떻게 해야할까?"


 

 

답부터 보지 말고 짱구 1분이라도 굴려봤으면 좋겠다^^

 

영문 뉴스 기사에서 인용부호로 된 부분만 뽑아내 보자.

 


 

일단 잘 찾는지 확인해본다.

 

찾기 패턴: "[^"]*"

 

패턴 아주 간단하다. 근데 처음에는 이해 안갈 수 있다. 사람이 알아들을 말로 바꾸면 이런 말이다.

 

패턴 인식: 인용부호 "로 시작해서 "로 끝나는 패턴을 찾는데 인용 부호 안에 "가 나오면 안된다.

 

요말이다. "[^"]*" 에서 [^"] 요 부분이 언뜻 어려울 뿐인데 문자집합에 달랑 " 하나 들어있고 그걸 부정(^)했다. 그러니까 인용부호 안에서 인용부호만 안나오면 어떤 문자가 반복돼도 상관없다는 말이 된다. 그럼 인용부호로 감싸져 있는 모든 패턴을 찾는다.

 

물론, ".*" 요따구로 해도 찾는다. 문제는 .가 모든 문자를 가리키기 때문에 인용부호마저 포함이 된다. 그래서 이런 것도 찾는다.

 

원하지 않는 패턴: "오케오이~" "

 

인용부호 안에 인용부호가 있는 경우는 제끼자는 말이다. 또, 인용부호 안에 아무것도 없는 "" 를 제끼고 싶으면 *+ 로 바꿔주면 된다. 이정도는.... 이제 이해하시겠지?^^

 

또, 인용부호 안에 있는 말만 지워서 문제를 만든다거나... 뭐 이럴땐 찾고 바꾸기 패턴을 이정도 해주면 된다.

 

찾기 패턴: "([^"]*)"

 

바꾸기 패턴: "\1 : 이 자리에 해석하세요!"

 

 

인용부호 부분을 그대로 살리면서 해당 위치에 ": 이 자리에 해석하세요." 식의 퀴즈를 낼 수도 있다... 뭐 그런 말이다.

 

'대두족장 정규식 편집기'를 사용해서 해당 부분만 추출할 수도 있다.

 

 

조금 더 짱구 굴려보자. 정규식의 빠우어~ 어디까지일까...

 

- 소설에서 대사만 뽑아낼 수 있다. (인용부호를 사용한 경우)

 

- 한글나오고 괄호 치고 영문으로 단어 설명이 돼 있을 경우 단어장을 만들 수 있다. (괄호를 사용한 경우)

 

... 짱구 굴리기 나름이라는 거다. 인용부호 얘기했다고 인용부호에서 상상력이 끝나면 ape다.

 

 

이런 패턴이 나오면 여기서 한발 더 나아가 "괄호 등 뭐든지 기호로 감싸준 패턴을 추출할 수 있겠구나" 짱구굴려야 호모 사피엔스다.

 

골라 골라~ 는 이쯤하련다.

728x90
반응형
블로그 이미지

nineDeveloper

안녕하세요 현직 개발자 입니다 ~ 빠르게 변화하는 세상에 뒤쳐지지 않도록 우리모두 열심히 공부합시다 ~! 개발공부는 넘나 재미있는 것~!

,