Swift/개념 & 응용

[Swift] 정규표현식 알아보기

유정주 2023. 7. 15. 21:22
반응형

서론

최근 정규표현식이 많이 부족하다는 걸 느꼈습니다.

이번 기회에 제대로 알아보자! 결심하고 정규표현식에 대해 공부해봤습니다.

정규표현식 개념보다는 예제 위주로 포스팅을 작성하였습니다.

 

 

정규표현식

정규표현식(regular expression, regex)이란 사용자가 규칙을 세워 패턴을 정의해둔 문자열입니다.

정규표현식은 문자열의 일부나 전체가 패턴이 일치하는지 알아볼 수 있는 편리한 방법입니다.

패턴이 일치하는 문자열만 추출할 때, 문자열이 패턴과 일치하는지 알고 싶을 때 등의 상황에서 유용하게 사용할 수 있습니다.

 

 

정규표현식 문법

문법 기능 설명
. 문자 일치 개행 문자를 제외한 문자 1개와 일치
[ ] 문자 집합 : 를 여러 번 쓴 것과 동일함. 사이에 들어온 문자를 선택하고 - 기호를 통해 범위를 지정함. [a-z]는 a부터 z까지 중 하나를 의미함
[^] 문자 집합 부정 문자 집합이 아닌 문자. [^a-z]는 알파벳 소문자를 제외한 모든 문자
^ 시작 문자열의 시작을 의미함
$ 문자열의 끝을 의미함
( ) 병합 여려 표현식을 하나로 묶을 때 사용함
a(b|c)d는 abd 또는 acd임
\n n번 째 패턴 일치하는 여러 패턴 중 n번 째를 의미함.
1 ~ 9까지의 자연수만 올 수 있음
* 0개 이상 포함 0개 이상의 문자를 포함함.
a*b는 b, ab, aab 등을 의미함
{m, n} m개 이상 n개 이하 m개 이상, n개 이하의 문자를 포함함
? 0~1개 0 ~ 1개 포함해야 함
+ 1개 이상 1개 이상
| or x | y인 경우, x 또는 y를 의미함
\w 영숫자, _ [A-Za-z0-9_]와 동일. 영어, 숫자, _ 문자
\W 영숫자, _ 부정 [^A-Za-z0-9_]와 동일. 영어, 숫자, _가 아닌 다른 문자
\d 숫자 [0-9]와 동일. 숫자를 의미함
\D 숫자 부정 [^0-9]와 동일. 숫자가 아닌 문자
\s 공백 공백 문자
\S 공백 부정 공백이 아닌 모든 문자

 

이외 다른 문법도 있지만 자주 사용되는 문법만 추렸습니다.

다른 문법은 https://developer.apple.com/documentation/foundation/nsregularexpression 에서 확인 가능합니다.

 

 

정규표현식 만들기

정규표현식 예제를 알아보기 전에 Swift에서 정규표현식을 어떻게 만드는지 알아보겠습니다.

let pattern1 = "[a-z]" //String
let pattern2 = /[a-z]/ //Regex<Substring>
let pattern3 = #"[a-z]"# //String

Swift에서는 세 가지 방법이 있습니다.

1과 3은 String 타입으로 만들어지고, pattern2는 Regex<Substring> 타입으로 만들어집니다.

String 타입은 try Regex(string)을 이용해 Regex 타입으로 만들 수 있답니다.

(이번 포스팅에서는 정규표현식 예제 위주로 작성되므로 타입들의 설명은 공식 문서를 참고해 주세요.)

 

2번 방법은 Regex로 바로 만드는 방법입니다.

1번과 3번 방법은 String이기 때문에 컴파일 타임에 정규표현식에 문제가 있는지 없는지 알 수 없습니다.

하지만 2번 방법은 Xcode에서 컴파일 에러로 정규표현식이 유효한지 알려줍니다.

 

또한, pattern1과 pattern3의 차이는 꽤나 중요합니다.

Swift에서 정규표현식을 만들 때 \ 는 \\로 작성해야하는데요.

Swift의 \는 이미 이스케이프((Escape delimiter)문자로 지정되어 있기 때문입니다.

예를 들어, \s 를 작성하고 싶다면 \\s로 작성해야 하는겁니다.

 

그러다보니 Swift만 다른 언어와 정규표현식 패턴이 달라지는 문제가 생기는데요.

(바로 아래에서 소개 드릴 정규표현식 해석 사이트에서도 제대로 해석이 안 됩니다 ㅠ)

이를 해결해주는게 pattern3 방법입니다.

문자열 양 옆에 #을 추가하면 String의 Raw String을 얻을 수 있기 때문에 \을 그대로 사용할 수 있습니다.

 

 

정규표현식 참고 사이트

정규표현식을 만들어볼 수 있는 사이트입니다.

 

RegExr: Learn, Build, & Test RegEx

RegExr is an online tool to learn, build, & test Regular Expressions (RegEx / RegExp).

regexr.com

 

 

아래는 정규표현식을 시각화 해주는 사이트입니다.

 

Regexper

 

regexper.com

 

 

예제로 알아보자

이제 예제를 살펴보면서 정규표현식과 익숙해져 봅시다.

정규표현식 검증은 위 사이트 중 Regexper에서 해보겠습니다.

 

한글 찾기

문자열에서 한글을 찾는 정규표현식을 생각해봅시다.

let pt1 = #"[가-힣ㄱ-ㅎㅏ-ㅣ]"#

한글은 가~힣, ㄱ~ㅎ, ㅏ~ㅣ세 가지 범위로 구성됩니다.

위 범위를 집합으로 구성해야 하므로 [ ]로 범위를 감싸면 되겠습니다.

 

영어 찾기

영어는 한글보다 쉽습니다.

a-z, A-Z를 범위로 지정하면 되겠죠.

let pt2 = #"[a-zA-Z]"#

 

한글 제외하기

이젠 제외 시키는 패턴을 만들어 봅시다.

문자열에서 한글을 지우려면 ^ 로 한글을 부정(?)하면 됩니다.

let pt3 = #"[^가-힣ㄱ-ㅎㅏ-ㅣ]"#

 

한글 자음, 모음 제외하기

그럼 한글에서 완성된 글자만 포함하고 싶다면 어떻게 하면 될까요?

처음에는 ㄱ-ㅎ, ㅏ-ㅣ를 제외해야 하나? 했는데 ㅋㅋ

굉장히 멍청한 생각이었구여;; 

let pt4 = #"[가-힣]"#

그냥 가-힣만 범위로 지정하면 되겠습니다.

 

 

전화번호 패턴

핸드폰 번호가 유효한지 체크하는 정규표현식을 알아봅시다.

다양한 케이스가 있겠지만 가장 간단한 방법은 숫자 3글자, 숫자 3~4글자, 숫자 4글자의 조합일 것입니다.

let pt5 = #"^\d{3}-\d{3,4}-\d{4}$"#

전화번호의 패턴은 시작과 끝이 중요하므로 ^ $를 사용하였습니다.

 

이제 조건을 추가하여 01로 시작하는 케이스를 표현해 봅시다.

let pt6 = #"^01[0-1]{1}-\d{3,4}-\d{4}$"#

01로 시작하고 01 뒤에 0 또는 1이 1글자 들어가는 패턴을 표현했습니다.

 

또 조건을 추가해봅시다.

이제는 - 가 있을 수도 있고, 없을 수도 있는 케이스를 표현해봅시다.

let pt7 = #"^01[0-1]{1}-?\d{3,4}-?\d{4}$"#

- 뒤에 ? 를 붙여서 0개 또는 1개가 들어갈 수 있는 패턴을 표현했습니다.

 

이메일 패턴

다음은 이메일 패턴입니다.

이메일은 중간에 @가 들어가야 하고, 그 뒤에 . 이 들어가야 합니다.

let pt8 = #"[A-Z0-9a-z]+@[A-Za-z0-9]+\.[A-Za-z]+"#

 

[A-Z0-9a-z]에 _를 추가로 붙인 패턴은 [A-Z0-9a-z_]로 표현할 수 있고, 이건 다시 \w로 표현할 수 있습니다.

let pt9 = #"\w+@\w+\.[A-Za-z]+"#

 

특정 문자 n번 연속 패턴

특정 문자가 n번 연속 반복되는지 확인하는 패턴입니다.

여기서 특정 문자를 직접 하드코딩할 수도 있지만 . 을 사용할 수도 있습니다.

let pt10 = #"(.)\1"#

특정 문자가 2번 반복하는 패턴입니다.

더 많은 횟수로 반복하길 원한다면 \1을 여러 번 쓰면 됩니다.

let pt10 = #"(.)\1"# //2번 반복
let pt11 = #"(.)\1\1"# //3번 반복
let pt12 = #"(.)\1\1\1"# //4번 반복

 

var, let 판단하기

이제 좀 특이한 예제를 봐볼까요?

var a: Int = 10
let b: Int = 20

위 코드를 입력했을 때 var인지 let인지 판단하는 정규표현식을 만들어 봅시다.

먼저 = 기호 전 까지만 잘라서 표현해 봅시다.

let pt13 = #"^var\s+(\w+)\s*:\s*(\w+)$"#

먼저 var로 시작을 하고 var와 문자열 사이에 space가 1개 이상 존재합니다.

문자열과 : 사이에는 space가 0개 이상 존재합니다.

:과 문자열 사이도 space가 0개 이상 존재하도록 표현했습니다.

 

이어서 = 까지 표현해봅시다.

Int형으로 가정하고 정수값이 대입되는 걸 표현해 볼게요.

let pt14 = #"^var\s+(\w+)\s*:\s*Int\s*=\s*(\d+)$"#

var + 1개 이상 공백 + 단어 + 0개 이상 공백 + : + 0개 이상 공백 + Int + 0개 이상 공백 + = + 0개 이상 공백 + 숫자 입니다.

굉장히 복잡해 보이지만 천천히 하나씩 뜯어보니 별거 없죠?

 

날짜

마지막으로 날짜를 표현하는 정규표현식을 알아봅시다.

let pt15 = #"19[0-9]{2}|20[0-9]{2}"# //연도
let pt16 = #"0[1-9]|1[0-2]"# //월
let pt17 = #"0[1-9]|1[0-9]|2[0-9]|3[0-1]"# //일

 

 

연도는 19 또는 20 이후에 0~9까지의 숫자 두 개가 들어갈 수 있습니다.

월은 0 또는 1로 시작하고 뒤에 숫자 하나가 들어갑니다.

일은 0, 1, 2, 3 뒤에 숫자가 하나 들어갑니다.

 

 

마무리

솔직히 쉽지 않습니다.

언제쯤 쉬워질지 모르겠습니다.

그래도 정규표현식을 사용한다면 문자열 처리가 확실히 짧아지고 센스있게 변합니다.

꾸준히 연습해서 익숙해지도록 노력해야겠습니다.

 

2편: 정규표현식 사용해보기

 

[Swift] 정규표현식 사용해보기

서론 정규표현식 알아보기에 이어 두 번째 정규표현식 포스팅입니다. 아마 3편은 Swift 5.7의 RegexBuilder(https://developer.apple.com/documentation/regexbuilder)가 될건데요. 이건 아마 많이 늦을듯... ㅎ 최소 한

jeong9216.tistory.com

 

 

감사합니다.

 

참고

https://borabong.tistory.com/32

https://ios-development.tistory.com/1087

https://ios-development.tistory.com/277

https://green1229.tistory.com/280

https://tngusmiso.tistory.com/62


아직은 초보 개발자입니다.

더 효율적인 코드 훈수 환영합니다!

공감 댓글 부탁드립니다.

 

 

반응형