본문 바로가기
IT

정규식(regular expression) 사용 예시들 - 실무에 사용 후 기억하기 위해

by 엘리후 2021. 6. 28.

1. 역참조(backreference)
Notepad++ 에서는 문자열 검색 시 정규식을 지원해 줍니다.




다양한 사용법 중 강력한 기능은 "역참조" (backreference) 입니다.

특정 문자열을 찾은 다음 그 문자열을 재 참조하여 사용할 수 있다는 의미 입니다.

예를 들어

92983/예시1 ;;Example200001
65453//예시2 ;Example400002

라는 문자가 있을 경우 여러가지 방법으로 정보를 추출하고 싶어 집니다.

숫자들(92983, 65453) 만 뽑거나
예시의 번호(1, 2)만 뽑는 것
혹은 Example 의 번호(200001, 400002) 를 뽑을 수도 있고
그 외에도 다른 여러가지 방법으로 뽑고 싶은 상황이 생깁니다.

치환은 이 때 사용할 수 있는데

아래 형태로 검색하면 위 내용이 한줄 씩 검색이 됩니다.

([0-9]+)[\/]*(예시[0-9 ]+)[\;]*(Example[0-9]+)


만약 마지막의 내용(Example 관련)만 뽑고 싶다면
바꾸기 에서 \3 을 입력하면 됩니다.

\3은 ( 과 ) 으로 감싸져 있는 3번째 항목 나타내는 말 입니다.

matching 시 개수를 지정하려면
[정규식]{번호}

2. 함수들 만을 남기기 위한
^((?!\([ a-zA-Z0-9\,\_]*\)).)*$
설명: 함수 선언의 필수인 ( 와 ) 를 가지고 있지 않은 줄을 찾기 위한 정규식

3. 특정 캐릭터가 없는 것
(?!\()
\( 가 없는 조건을 만들기 위하여 이 것을 "(?!" 과 ")" 를 감싼다.
?! 의 의미 ? 의 의미 ! 의 의미를 따로 알아야 한다.

4. 특정 캐릭터로 끝나는 것 (Link)

^.*(?<!to)$

5. 최소 몇개의 캐릭터가 있어야 하는 것
([0-9\:]{1,9})( )([0-9\:]{1,9}) ([A-Za-z\_0-9\,\?]*)
보통 * 만 쓰면 없을때도 있기 때문에{1, 9} 처럼 최소 1개 에서 9개 까지 를 명시해 주면 직관적으로 이해할 수 있다.

6. Visual Studio 에서 특정 함수를 print 하려고 할때

찾을 문자열: ([0-9a-zA-Z \=\_\-\*\,\(\)\;\:\" ]*cv[a-zA-Z0-9]*\([0-9a-zA-Z \=\_\-\*\,\(\)\;\:\" ]*;)
변경할 문자열: \1\n\#ifdef _DEBUG\n_cprintf\(\"\1\"\);\n\#endif
추가: \" 에 대한 고려

 

 

유독 머리에 제 자리를 잡지 못하는 것들 중에 하나인 정규 표현식 (Reqular Expression) 을 또 써야할 상황이 발생해서 다시 한번 정리를 해 놓는다. (언젠가 또 멍청하게 까먹고 다시 정리한다고 하겠지만… 쩝)

확장자 검증하기 (샘플)

우선  사용하려고 하는 실제 사례에 대한 의미를 확인해 보도록 하자. 실제 적용하여야 하는 부분은 특정한 문자열 (URL, File Path 등…) 에서 이미지 확장자를 제거하는 부분이다. 쉽게 사용할 수 있는 정규식은 다음과 같이 적용이 가능하다.
([^\s]+(\.(?i)(jpg|png|gif|bmp))$)

위의 정규식을 이해하기 위해서 하나씩 끌어내 보면 다음과 같이 해석할 수 있다.

( # 그룹 1의 시작 [^\s]+ # 공백을 제외한 하나 또는 그 이상의 문자열이 존재하여야 한다는 조건 ( # 그룹 2의 시작 \. # '.' 문자 (?i) # 이후의 문자들에 대해서 대/소문자를 무시 ( # 그룹 3의 시작 jpg # 'jpg' 문자 포함 | # 또는 png # 'png' 문자 포함 | # 또는 gif # 'gif' 문자 포함 | # 또는 bmp # 'bmp' 문자 포함 ) # 그룹 3의 종료 ) # 그룹 2의 종료 $ # 문자열 종료 ) # 그룹 1의 종료

위의 내용은 “공백이 아닌 최소한 하나 이상의 문자열을 대상으로 ‘.’ 문자 이후에 ‘jpg’, ‘png’, ‘gif’, ‘bmp’ 문자가 포함된 것들을 대/소문자 구분 없이 찾는다” 라는 것이다. 더 많은 조건을 넣으려면 ‘|’ 문자와 대상으로 할 문자를 더 추가하면 된다.

실제 코드에서 사용하는 방법은 아래의 예제와 같다.

package com.msfl.study.regex;   import java.util.regex.Matcher; import java.util.regex.Pattern;   public class ExtensionsValidator { private Pattern pattern; private Matcher matcher;   private static final String EXTENSION_PATTERN = "([^\\s]+(\\.(?i)(jpg|png|gif|bmp))$)";   public ExtensionsValidator (){ this.pattern = Pattern.compile(EXTENSION_PATTERN); }   /** * 파라미터로 전달된 문자열을 정규표현식을 통해서 검사하고 * 지정한 확장자 패턴에 맞으면 true, 아니면 false 를 반환한다. */ public boolean validate(final String target){   matcher = pattern.matcher(target); return matcher.matches();  } }

위의 자바 코드는 정규표현식으로 확장자를 검사하는 아주 간단한 클래스로 validate 메서드를 호출해서 지정한 확장자가 포함되었는지를 검사하는 것이다. 이 반환 결과를 통해서 필요한 로직을 처리하면 된다.

정규 표현식?

정규 표현식이 필요한 이유는 너무나 많다. 어떤 규칙성을 가지는 문자열에 대한 검증이 필요하다면 거의 대부분 적용이 필요하다고 생각하면 된다. 데이터 검증 뿐만 아니라 필요한 포맷에 맞도록 입력을 유도하는 경우에도 사용하면 쉽게 구현이 가능하다.

정규 표현식은 사전적인 의미로 정의를 하면 “특정한 규칙을 가진 문자열의 집합을 표현하는데 사용하는 형식 언어” 가 된다. 주로 프로그래밍 언어나 텍스트 에디터 등에서 문자열의 치환이나 검색등의 용도로 많이 사용되고 있다. 그런데 쉽게 접근을 허용하지 않는 도도함은 바로 지랄맞게 가독성이 떨어지는 표현식과 의미라고 할 수 있다.

정규 표현식의 표준은 POSIX 표현식과 이를 기반으로 확장된 Perl 방식의 PCRE 가 존재한다. 물론 더 많은 표현식들이 존재하지만 실제 약간의 차이점만 존재할 뿐  실제 사용하는 규칙들은 거의 비슷하다고 생각하면 된다.

정규 표현식의 용어들

정규 표현식에서 사용되는 기호를 Meta문자라고  표현한다. 표현식에서 내부적으로 특정 의미를 가지는 문자를 말하며 간단하게 정리하면 아래의 표와 같다.

 

 표현식 의미 
 ^x  문자열의 시작을 표현하며 x 문자로 시작됨을 의미한다.
x$  문자열의 종료를 표현하며 x 문자로 종료됨을 의미한다.
 .x  임의의 한 문자의 자리수를 표현하며 문자열이 x 로 끝난다는 것을 의미한다.
 x+  반복을 표현하며 x 문자가 한번 이상 반복됨을 의미한다.
 x?  존재여부를 표현하며 x 문자가 존재할 수도, 존재하지 않을 수도 있음을 의미한다.
 x*  반복여부를 표현하며 x 문자가 0번 또는 그 이상 반복됨을 의미한다.
 x|y  or 를 표현하며 x 또는 y 문자가 존재함을 의미한다.
 (x) 그룹을 표현하며 x 를 그룹으로 처리함을 의미한다.
 (x)(y) 그룹들의 집합을 표현하며 앞에서 부터 순서대로 번호를 부여하여 관리하고 x, y 는 각 그룹의 데이터로 관리된다.
 (x)(?:y) 그룹들의 집합에 대한 예외를 표현하며 그룹 집합으로 관리되지 않음을 의미한다. 
 x{n}  반복을 표현하며 x 문자가 n번 반복됨을 의미한다.
 x{n,}  반복을 표현하며 x 문자가 n번 이상 반복됨을 의미한다.
 x{n,m}  반복을 표현하며 x 문자가 최소 n번 이상 최대 m 번 이하로 반복됨을 의미한다.


Meta 문자들 중에서 좀 더 특수하게 사용되는 문자들이 존재한다. '[]' 는 내부에 지정된 문자열의 범위 중에서 한 문자만을 선택하다는 특수한 의미를 가진다. 그리고 내부에서 Meta문자를 사용하면 다른 의미를 가지고 동작할 수 있으므로 잘 확인하고 사용해야 한다. 좀 더 특별한 용도로 사용되는 것들은 아래의 표와 같다. 



 표현식 의미 
[xy] 문자 선택을 표현하며 x 와 y 중에 하나를 의미한다.
 [^xy] not 을 표현하며  x 및 y 를 제외한 문자를 의미한다.
 [x-z] range를 표현하며 x ~ z 사이의 문자를 의미한다. 
 \^ escape 를 표현하며 ^ 를 문자로 사용함을 의미한다.
 \b word boundary를 표현하며 문자와 공백사이의 문자를 의미한다.
 \B non word boundary를 표현하며 문자와 공백사이가 아닌 문자를 의미한다.
 \d digit 를 표현하며 숫자를 의미한다. 
 \D non digit 를 표현하며 숫자가 아닌 것을 의미한다. 
 \s space 를 표현하며 공백 문자를 의미한다. 
 \S non space를 표현하며 공백 문자가 아닌 것을 의미한다.
 \t tab 을 표현하며 탭 문자를 의미한다.
 \v vertical tab을 표현하며 수직 탭(?) 문자를 의미한다.
 \w word 를 표현하며 알파벳 + 숫자 + _ 중의 한 문자임을 의미한다. 
 \W non word를 표현하며 알파벳 + 숫자 + _ 가 아닌 문자를 의미한다. 


정규표현식을 사용할 때 Flag 라는 것이 존재하는데 Flag를 사용하지 않으면 문자열에 대해서 검색을 한번만 처리하고 종료하게 된다. Flag는 다음과 같은 것들이 존재한다.



 Flag 의미 
 g Global 의 표현하며 대상 문자열내에 모든 패턴들을 검색하는 것을 의미한다. 
 i Ignore case 를 표현하며 대상 문자열에 대해서 대/소문자를 식별하지 않는 것을 의미한다.
 m Multi line을 표현하며 대상 문자열이 다중 라인의 문자열인 경우에도 검색하는 것을 의미한다. 


몇 가지 사례들

  • 한글 코드 (단순) - /[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/ 로 구성이 가능하다. 단, 한글 문제는 단순하지 않으므로 좀 더 좋은 방법을 찾는 것이 좋다.
  • 숫자 - /[0-9]/g
  • 이메일 - /^[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*\.[a-zA-Z]{2,3}$/i
  • 모든 공백 - /\s/g
  • 전화번호 - /^\d{3}-\d{3,4}-\d{4}$/
  • 핸드폰 번호 - /^01([0|1|6|7|8|9]?)-?([0-9]{3,4})-?([0-9]{4})$/
  • URL - ^(https?):\/\/([^:\/\s]+)(:([^\/]*))?((\/[^\s/\/]+)*)?\/?([^#\s\?]*)(\?([^#\s]*))?(#(\w*))?$


위의 사례들이 정답이라고 할 수는 없다. 상황에 따라서 위의 기본적인 정규식에 필요한 부분들을 첨삭하여 사용하면 될 듯 하다.

참고사항

정리는 하기는 했지만 실제로 사용하기 위해서는 여러 가지로 변경해 가며 테스트를 해 봐야 한다. 그런데 딱히 정규식을 테스트할만한 도구가 없다. 유용하게 사용할 수 있는 툴들이 제공되는 사이트로 많이 사용하는 것들은 다음과 같다.


그 외에도 상당히 많은 사이트들이 정규 표현식을 정리하여 소개하고 있다.

댓글