정규표현식 (Regular Expressions) 이해하기

Tags
Published
Published May 23, 2022
Author
 
💡
"([a-zA-Z0-9\\_\\-\\.]+)@([a-zA-Z]+).(.+)”
 
프로그래밍을 하다 보면 위와 같은 이상한 기호를 한번쯤은 접해보았을 것이다. 데이터 분석을 하든, 크롤링을 하든, 파이썬이든, VBA이든, 자바스크립트든 자주 등장하는 것이 있는데,
 
바로 정규표현식 (Regular Expression, 줄여서 Regex) 이라고 하는 것이다.
 
이게 도대체 뭘까, 그리고 왜 알아야 하지? 하고 그냥 지나치다가 최근 프로젝트에서 정규표현식의 도움을 받은 일이 있었다.
정규표현식의 주요 개념과 작동방식에 대해서 정리한 내용을 다듬어서 글로 작성해 보았다.
 
 

정규표현식이란?

 
정규표현식은 한마디로 ‘특정 유형의 문자 조합을 지칭하는 표현’이다.
하나의 정규표현식이 있으면, 그 표현식과 대응되는 문자조합이 있다.
 
예를 들어, URL 링크와 대응되는 정규표현식은 아래와 같다.
https?:\/\/(www\.)?[-a-zA-Z0-9@:%.\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%\+.~#?&//=]*)
 
몇백 페이지나 되는 긴 텍스트에서 URL 링크만 찾아내고 싶으면 어떻게 할까?
위의 정규표현식을 쓰면 된다.
 
이처럼 정규표현식 하나는 텍스트에 등장하는 모든 URL 형태의 문장조합과 대응되는데,
정규표현식과 문장조합 간에는 1 대 多 관계가 성립한다고도 이해할 수 있다.
 
정규표현식을 테스트해볼 수 있는 사이트 (https://regexr.com/)
정규표현식을 테스트해볼 수 있는 사이트 (https://regexr.com/)
 
그래서 정규표현식을 실무적으로는 어떤 상황에서 사용할 수 있을까?
몇 가지 사례를 나열해보았는데, 아래 상황 뿐만 아니라 대량의 텍스트를 다루는 상황 속에서는 모두 정규표현식을 활용할 수 있다.
 
  • 트위터 텍스트에서 멘션(mention, @로 시작하는 부분) 부분만 따로 뽑아내고 싶은 경우
  • 웹페이지 크롤링을 하는데 내가 구해야 하는 값이 항상 A라는 문자조합과 B라는 문자 조합 사이에 있어서, 이 부분만 찾아내고 싶을 때
  • 방대한 텍스트 속에서 이메일, URL 링크, 휴대폰 번호 데이터만 뽑아내고 싶을 떄
  • 내가 원하는 파일 확장자 (XXX.png) 만 뽑아내고 싶을 때
 
 

정규식 표현을 꼭 이해해야 할까?

 
정규표현식의 개념, 그리고 어떤 상황에서 왜 필요한지를 이해하고 있는 분들은 많아도, 정규식 자체의 표현을 이해하지 않고 지나치는 경우가 많다.
정규표현식 자체가 복잡하고 쳐다보기 싫게 생겨서 그럴수도 있지만, 특정 상황에 맞는 정규표현식은 구글링하면 다 나오기 때문에 ‘그냥 구글링하면 되지, 굳이 이해해야 하나?’ 싶을 때가 많다.
 
예를 들어 URL 링크만 찾아주는 정규표현식이 필요한 상황이라도 그 표현식을 직접 작성하는 경우는 거의 없고 ‘URL Regex’라고 구글링해서 남들이 작성한 정규표현식을 그대로 사용한다.
그래서 정규표현식이 정확히 어떤 원리로 작성되어있는지 전혀 몰라도 정규표현식을 사용할 수 있긴 하다.
그런데 정규표현식을 하나도 이해하지 않고 모든 것을 100% 구글링하게 오히려 표현을 찾는데 시간이 더 소요되는 것 같다. 최근에는 ‘고정된 A문자와 B문자 사이의 모든 문자조합을 찾아내는 정규표현식’을 스택 오버플로우에서 검색해 보았는데, 답변만 14개다.
 
각각의 답변이 가지는 표현식의 진짜 의미를 모르니, 나온 답변을 하나씩 대입해가면서 되는지 안되는지 확인해볼 수 밖에 없다.
그런데 많은 경우 정규식이 정확하게 내가 필요한 부분만 찾아내지 못하니까, 다시 구글링을 하며 정규식을 하나씩 대입하는 것의 반복이다.
 
정규표현식의 가장 기본적인 문법과 주요 메타문자의 기능만 알아도 구글링으로 찾은 표현식에서 수정 및 응용이 가능해진다. 그래서 처음부터 정규표현식을 다 작성할 필요는 없지만, 다른 분들이 만들어둔 정규표현식의 문자의 의미와 내포되는 기능을 이해하는 것은 많은 도움이 되는 것 같다.
 
 

1) 메타문자 (Metacharacters)에 대한 이해

 
정규표현식을 이해하는 데 가장 중요한 개념을 뽑으라고 하면, 메타문자(Metacharacter)인 것 같다.
 
정규표현식을 이해하는 것이 어려운 이유는 일반 문자와 메타 문자가 혼재되어 있기 때문이다. 자주 나오는 메타문자가 무엇이고, 이 메타문자의 기능은 무엇인지만 알아도 정규표현식을 훨씬 쉽게 읽을 수 있다.
 
메타문자의 개념을 한마디로 정의하자면, 문자 본래대로 대응되지 않고 특별한 기능을 보유한 문자다.
정규식에서 메타문자를 제외한 일반 문자는 보통 문자 그대로와 대응된다. 예를 들어 위에서 나온 URL 링크 정규표현식에도 https, www 부분은 실제로 텍스트 속의 https, www와 같은 문자와 그대로 대응되는 것이다. 하지만 그 이외에 ?, * 같은 문자는 메타 문자이고, 실제로 텍스트에서 ?,*와 대응되는 것이 아니다.
 
 
자주 나오는 메타문자의 의미를 간단하게 정리하면 아래와 같고, 그 외 다양한 메타문자에 대한 상세 내용은 링크에서 확인할 수 있다.
  • . (온점) : 모든 문자와 대응되는 메타문자다.
    • hel.o : hello, helio, heloo 모두와 대응된다.
  • ?(물음표) : 바로 직전에 나온 문자 있어도 되고, 없어도 된다는 의미다.
    • https? : http, https 모두와 대응된다.
  • * (별표) : 바로 직전에 나온 문자의 개수가 0개여도 1개여도, 2개여도, n개여도 상관없다는 뜻이다.
    • wow* : wo, wow, woww, wowwwwwww 모두와 대응된다.
 
메타문자와 관련해서 2가지 문제가 발생할 수 있다.
 

1. 메타문자를 메타문자가 아닌 일반문자처럼 대응시키고 싶을 때

예를 들어 안녕? 자체를 맞추고 싶은 경우,
\(역슬래시)라는 메타문자를 이용해서 메타문자를 일반 문자로 바꿔주면 된다.
  • 안녕? : 안, 안녕과 대응되지만,
  • 안녕\? : 안녕? 과 대응된다.
 

2. 메타문자의 기능을 직전 1개 문자말고 문자조합에 적용하고 싶을 때

*(별표) 라는 메타문자를 wow라는 단어 자체에 적용하고 싶을 경우
메타문자 적용의 대상을 소괄호 ( ) 로 정해주면 된다.
  • wow* : wo, wow, woww, wowwwwwww 와 대응되지만,
  • (wow)* : 공백, wow, wowwow, wowwowwowwowwowwow 와 대응된다.
 
 

2) 전혀 다른 문법이 적용되는 캐릭터 클라스 (Character Class)

메타문자에 대해서 알게 되어도 명쾌하게 이해가 되지 않는 부분들이 있었다. 정규표현식을 이해하다 보면 아래와 같은 의문점들이 들게 된다.
  • 하이픈(-)은 메타 문자가 아니었던 것 같은데, [a-z]에서 하이픈은 무슨 의미일까?
  • ^hello[^u] 에서 ^는 왜 다른 기능을 하는 메타문자일까?
  • 분명히 .(온점)은 모든 문자를 맞추는 메타문자라서 온점 그대로를 맞추려면 \(백슬래시)를 이용해야 하는데, 왜 [.] 처럼 대괄호 안에서는 백슬래시가 필요없지?
 
정규표현식에서 캐릭터 클라스의 개념을 알게 되고, 캐릭터 클라스가 다른 정규표현식과는 전혀 다른 독자적인 문법으로 작동한다는 점을 알게 된 것만으로도 정규표현식을 읽고 이해하는 데 큰 도움이 되었다. 캐릭터 클라스의 개념을 이해하고 나서는 위의 의문들도 자연스럽게 해소가 되었다.
 

대괄호 [] 로 둘러싸인 캐릭터 클라스 (Character Class)

 
정규표현식에서 대괄호 [] 로 둘러싸인 문자조합도 자주 등장하는데 이를 캐릭터 클라스라고 한다.
캐릭터 클라스를 직관적으로 해석하면 ‘대괄호 안에 있는 이 문자들 중 어느 하나라도 있으면 대응이 된다’ 이다. 이는 문자를 해석하는 기존 정규표현식의 문법과는 결이 다르다.
 
정규표현식에서 컴퓨터가 각 각의 문자, 또는 문자 덩어리를 해석하는 가장 기본적인 방식은 그리고 (AND) 방식이다.
https? 라는 표현식을 ‘h라는 문자가 있고, 그리고(AND) t 라는 문자가 있고, 그리고(AND) … ‘ 와 같이 한 문자씩 확인해서 모든 조건을 동시에 충족하는 문자조합을 찾아낸다.
그리고(AND)의 논리로 문자를 조합하는 것이 원칙이고, 일부 메타문자(?나 |)로 또는(OR)의 논리를 활요할 때도 있다.
 
반면에 캐릭터의 클라스에 각 문자들은 또는(OR) 의 관계에 있다.
gr[ea]y 에서 컴퓨터는 ‘g, 그리고 r, 그리고 (e 또는 a), 그리고 y’ 에 대응되는 문자조합을 찾는다.
이처럼 캐릭터 클라스 안에서는 각 문자간의 관계 뿐만 아니라 메타문자의 기능도 완전히 달라진다.
원래 정규표현식에서는 메타문자였던 문자들이 캐릭터 클라스에서는 일반 문자가 되는 경우도 있고, 메타문자의 의미가 전혀 달라지는 경우도 있다.
그래서 캐릭터 클라스에서 자주 나오는 메타문자인 하이픈 (-)도 캐릭터 클라스에서만 통용되는 메타문자이다.
[a-f][abcdef]와 같은 의미이다.
 
캐릭터 클라스 안에서만 적용되는 메타문자는 대표적으로 2가지밖에 없고, 이를 제외한 문자들은 모두 일반문자로 이해하면 된다.
  • -(하이픈) : 문자/숫자 범위 (문자나 숫자 사이에 있을 때만 메타문자로 적용하고, 단독으로 있을 떄는 일반 문자)
  • ^ : 바로 뒤에 나오는 문자를 제외한 모든 문자
    • [^u] 는 u를 제외한 모든 알파벳 소문자를 의미함
 
 
 

글을 마치며

 
정규표현식은 그 자체로 굉장히 방대한 분야이고, 이번 글에서 소개하지 못한 개념들도 많다.
하지만 이번 글을 통해서 앞으로 정규표현식을 접하게 되더라도 그 표현의 개략적인 구조와 의미를 이해할 수 있게 되면 좋을 것 같다. 다른 고급 개념들은 그 과정에서 조금씩 쌓아나가도 괜찮을 것 같다.
 
 

참고 자료

 

Loading Comments...