[Swift] Swift에서 정규표현식 사용하기
[Swift] Swift에서 정규표현식 사용하기
저는 지금까지 텍스트 필드 위에 입력되는 사용자의 입력이나 텍스트 덩어리에서 원하는 패턴의 값을 뽑아내거나 검증을 할 때 항상 모든 경우에 대해 if-else
와 같은 조건문을 이용하였습니다.
하지만 이렇게 조건문으로 모든 것을 해결하려하니 코드의 가독성, 효율성이 떨어질 뿐만 아니라 시간도 꽤나 소모되는 경우가 허다했습니다. 그러던 와중 매번 나랑은 관계없다고 생각한 정규표현식을 사용하고 느낀 편리함을 기록해보고자 이렇게 글을 작성하게 되었습니다. 그럼 바로 시작해보도록 하겠습니다.
NSRegularExpression
먼저 Swift에서 정규표현식을 사용하여 패턴을 검증하기 위해선 NSRegularExpression
을 사용해야 합니다. 앞에 NS-
가 붙어있다는 사실만으로도 NSRegularExpression
이 Objective-C로 작성되어 있다는 것을 알 수 있습니다.
먼저 이를 직접 사용해보면서 어떤 식으로 사용하는지에 대해 알아보도록 하겠습니다.
예제의 상황은 이렇습니다. 사용자가 입력한 다음의 텍스트로부터 #
가 접두어로 있는, 즉 해시태그에 해당하는 문자들을 뽑아보도록 하겠습니다.
"I made this wonderful pic last #christmas... #instagram #nofilter #snow #fun"
Pattern
우리가 뽑아낼 단어는 접두어로 #
를 갖는 단어들입니다. 이러한 단어들을 뽑아내기 위한 정규표현식은 #[a-z0-9]+
입니다. 이게 무엇을 의미할까요?
[]
안에 특정 패턴이 어떠한 종류의 값을 갖는지에 대해 값의 범위(range)를 표현해주어야 합니다. 해시태그로#
뒤에 알파벳과 숫자를 갖는 패턴으로는#[a-z0-9]
가 됩니다.- 그렇다면
+
는 무엇일까요? 이는 바로 특정 범위에 해당하는 문자들이 한개 혹은 그 이상 존재한다는 의미입니다. 만일+
가 붙지 않았다면#5
와 같이#
뒤 한개의 문자만 있는 해시태그만 찾아낼 것입니다.
NSRegularExpression
그럼 이제 본격적으로 NSRegularExpression
을 사용해보도록 하겠습니다. 위에서 정의한 #[a-z0-9]+
의 패턴을 갖는 인스턴스는 다음과 같이 생성할 수 있습니다.
let regex = try? NSRegularExpression(pattern: "#[a-z0-9]+", options: .caseInsensitive)
.caseInsenstive
란 단어 그대로 case, 즉 uppsercase, lowercase에 둔감하다는 의미로 대소문자를 구분하지 않는다는 옵션입니다.
이렇게 우리는 하나의 정규 표현식 패턴을 갖는 거름망을 만든 것이라고 보면 됩니다. 그럼 이제 텍스트를 이 거름망에 통과시켜 보도록 하겠습니다.
let text = "I made this wonderful pic last #christmas... #instagram #nofilter #snow #fun"
let textToNS = text as NSString
regex.matches(in: text, options: [], range: NSRange(location: 0, length: textToNS.length))
in:
에는 검사할 텍스트를 넣어줍니다.range:
에는 검사할 텍스트의 범위를 정해줍니다. 하지만 코드에서String
을NSString
으로 캐스팅하여 넣어준 것을 확인할 수 있습니다. 이는NSRegularExpression
이NSRange
를 인자로 받기 때문인데NSRange
를 받는 이유는 기본적으로 Objective-C와 Swift에서 문자열을 처리하는 방법이 다르기 때문입니다.
이렇게 matches
를 통해 우리는 거름망을 통과시킨 결과를 얻을 수 있는데 그 결과 타입은 [NSTextCheckingResult]
입니다. 그리고 NSTextCheckResult
는 검사를 원하는 텍스트에서 거름망의 패턴과 일치하는 부분 텍스트가 있다면 해당 부분 텍스트의 범위를 NSRange
의 형태로 반환하고 NSTextCheckResult
는 이를 range
프로퍼티로 갖고 있습니다.
regex.matches(in: self, options: [], range: NSRange(location: 0, length: string.length)).map {
string.substring(with: $0.range)
}
그렇다면 우리는 그렇게 나온 일치하는 부분 텍스트의 범위(NSRange
)를 통해 부분 텍스트들을 원본에서 뽑아낼 수 있습니다. 그렇게 결과로는 ["christmas", "instagram", "nofilter", "snow", "fun"]
가 나오게 됩니다.
이렇게 정규 표현식을 사용한다면 보다 쉽게 텍스트로부터 원하는 패턴의 값들을 뽑아낼 수 있습니다. 다음은 제가 사용하기 위해 공부해 본 정규 표현식입니다.
"[a-z0-9]+"(?=:)
: json 키-값 쌍에서 키를 찾아주는 정규 표현식입니다.(?, ... )
: 이는 전방 탐색 문법으로...
에 오는 패턴 앞을 검사합니다. 저는 이 부분에:
를 넣었으니. 모든 텍스트에서:
앞을 검사하게 됩니다."[a-z0-9]+"
::
앞에""
안에 들어있는 즉 문자나 숫자를 포함하는 문자열이 존재하는지 검사하기 위한 조건입니다. 이렇게 되면 우리는 json 키-값 쌍에서 키를 찾아낼 수 있습니다.NSRegularExpression
에서 사용할 때 주의할 점은""
안에 위의 표현식이 들어가기 때문에 반드시\"
처리를 해주어야 합니다.in: "\"[a-z0-9]+\"(?=)"
[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,20}
: 이메일의 형식 검사- 사용자가 이메일을 입력했을 때 유효한 이메일인지 검사하는 패턴입니다.
마무리
이외에도 우리는 수 많은 정규 표현식을 사용할 수 있습니다. 그 문법은 굉장히 무궁무진합니다. 그렇기 때문에 이들을 적절히 사용한다면 왠만한 패턴의 텍스트들을 모두 뽑아낼 수 있을 것입니다.
오늘은 이렇게 Swift에서 정규 표현식을 사용하는 방법에 대해 공부했습니다. 정규 표현식의 문법을 마음대로 사용할 수준은 아직은 아니지만 기회가 있을 때마다 적극적으로 사용하며 이를 익힐 수 있도록 해야겠습니다.
이런 정규 표현식은 구글에 검색해보면 일종의 치트 시트 형식으로 많이 사용하는 문법들을 정리해 놓은 pdf 파일이나 블로그 글들을 쉽게 접할 수 있습니다. 이들과 정규 표현식을 사용해 볼 수 있는 각종 사이트들을 활용한다면 왠만한 패턴들은 뽑아내실 수 있을 겁니다. 감사합니다.
참고자료