Regular Expression : Swift 에서 정규표현식 사용 - NSRegularExpression
10 Jun 2019 |
Regular Expression (정규표현식)
a string or a sequence of characters that specifies a pattern 특정한 패턴을 정의하는 string 혹은 일련의 character
Regex 는 주로 문자열에서 특정 패턴에 맞는 문자열만 추출하고 싶을 때, 사용된다.
특정 패턴, 규칙을 나타내기 위해서 약속된 문법을 사용한다.
살면서 regex 를 써야될 상황이 많았지만, 그때마다 그냥 구글링하거나 대략 넘어갔었다. 그래서 이번에 제대로 익혀보기 전부터 덜컥 겁부터 났었다. 하지만 알고나서 내가 직접 적용해보니 생각보다 너무 쉬웠다. 물론 막힌 부분도 있었지만 내가 원하는 패턴을 매칭시키는 regex 를 만들 수 있어서 뿌듯했다.
- 반복
n+
: 앞의 문자가 0번 이상 반복n*
: 앞의 문자가 1번 이상 반복
^n
: ~로 시작n$
: ~로 끝난다- whitespace
\s
==[ \t\r\n\f]
- space, tabe, line break, form feed..
- 숫자
\d
==[0-9]
- word like character
\w
== 숫자, 글자, _(underscore) (x|y|x)
: OR operation()
capturing group
json value 각 타입별로 정규표현식 생각해보기
-
괄호, 기호, value 사이사이에 공백 - 공백은 0개 이상 있을 수 있다
\s*
-
json value
- bool :
true
orfalse
- number :
\d
, 1개이상+
. 반복 ⇢[\d]+
- string : double quotation 안에 문자, 숫자, 공백, 0개이상
*
⇢"[\w\s]*"
- or 로 묶음 ⇢
(true|false|[\d]+|"[\w\s]*")
- key 에 들어가는 string은 1개 이상
+
//string ""안에 \w(문자,숫자),\s(공백) 들어갈 수 있음. key는 ""(emptystring) 안되게 함(1개 이상) "[\w\s]+"
- bool :
-
object :
{ string : jsonvalue (, string : jsonvalue) }
형태(, string : jsonvalue)
0개 이상 반복*
- non-capturing 사용 (?: ~~~)
- ((반복되는 부분)*) 다시 감싸줘야 됨 (참조: Repeating a Capturing Group vs. Capturing a Repeated Group)
{\s*"[\w\s]+"\s*:\s*(true|false|"[\w\s]*"|[\d]+)\s*((?:,\s*"[\w\s]+"\s*:\s*(true|false|"[\w\s]*"|[\d]+))*)\s*}
특수 기호 in swift
- swift 에서는 특수기호 앞에
\
붙어야 됨. - regex 에서
\
와 같이 쓰이는 기호는 두개 붙여야 됨.. - Swift == regex
\.
==.
\\.
==\.
유의할 점
- 정규표현식에서 사용되는 문자 이외에는 모두 앞에
\\
를 붙여줘야 함 (\\{
) - 원래
\
랑 같이 쓰이는건\\
로 바꿔야 함 - double quotation 은
\"
// swift pattern for json object
"\\{\\s*\"[\\w\\s]+\"\\s*\\:\\s*(true|false|\"[\\w\\s]*\"|[\\d]+)\\s*((?:,\\s*\"[\\w\\s]+\"\\s*\\:\\s*(true|false|\"[\\w\\s]*\"|[\\d]+))*)\\s*\\}"
// swift pattern for json array
"\\[\\s*(true|false|\"[\\w\\s]*\"|[\\d]+)\\s*((?:,\\s*(true|false|\"[\\w\\s]*\"|[\\d]+))*)\\s*\\]"
// array element 에 jsonobject 추가
"\\[\\s*(true|false|\"[\\w\\s]*\"|[\\d]+|\\{\\s*\"[\\w\\s]+\"\\s*\\:\\s*(true|false|\"[\\w\\s]*\"|[\\d]+)\\s*((?:,\\s*\"[\\w\\s]+\"\\s*\\:\\s*(true|false|\"[\\w\\s]*\"|[\\d]+))*)\\s*\\})\\s*((?:,\\s*(true|false|\"[\\w\\s]*\"|[\\d]+|\\{\\s*\"[\\w\\s]+\"\\s*\\:\\s*(true|false|\"[\\w\\s]*\"|[\\d]+)\\s*((?:,\\s*\"[\\w\\s]+\"\\s*\\:\\s*(true|false|\"[\\w\\s]*\"|[\\d]+))*)\\s*\\}))*)\\s*\\]"
// object element 에 array 추가
"\\{\\s*\"[\\w\\s]+\"\\s*\\:\\s*(true|false|\"[\\w\\s]*\"|[\\d]+|\\[\\s*(true|false|\"[\\w\\s]*\"|[\\d]+)\\s*((?:,\\s*(true|false|\"[\\w\\s]*\"|[\\d]+))*)\\s*\\])\\s*((?:,\\s*\"[\\w\\s]+\"\\s*\\:\\s*(true|false|\"[\\w\\s]*\"|[\\d]+|\\[\\s*(true|false|\"[\\w\\s]*\"|[\\d]+)\\s*((?:,\\s*(true|false|\"[\\w\\s]*\"|[\\d]+))*)\\s*\\]))*)\\s*\\}"
(참조) JSON String
NSRegularExpression 사용하기
regex pattern 에 매치되는지 확인할 때 사용
-
init : pattern과 option 설정
-
matches
method- input : pattern 검사될 string, 검사될 string의 range(
NSRange
) - output : 매치된 문자열들 -
[NSTextCheckingResult]
- input : pattern 검사될 string, 검사될 string의 range(
-
NSTextCheckingResult
An occurrence of textual content found during the analysis of a block of text, such as when matching a regular expression.
-
var range: NSRange
: Returns the range of the result that the receiver represents.받은 표현(input string)에서 매치된 부분의 범위!
-
NSRange
→Range
로 변경해서 input의 substring 을 구하면 됨String(input[range])
-
요구사항
- 사용자가 입력한 JSON 데이터 문자열 문법 검사를 담당하는 GrammarChecker 구조체를 추가한다.
- JSON 표준 문법에 맞는지 검사한다.
- 현재 지원하는 JSON 형식 외에 다른 구조에 대해서도 판단하도록 구현한다.
- 예를 들어, JSON 객체 내에 배열이나 객체가 중첩해서 포함된 경우는 걸러낸다.
- 스위프트 파운데이션에 포함된 정규 표현식 처리 클래스를 적극 활용한다. NSRegularExpression
-
object - value : string, number, bool
"^\\{\\s*\"[\\w\\s]+\"\\s*\\:\\s*(true|false|\"[\\w\\s]*\"|[\\d]+)\\s*((?:,\\s*\"[\\w\\s]+\"\\s*\\:\\s*(true|false|\"[\\w\\s]*\"|[\\d]+))*)\\s*\\}$"
-
array element 로 object 는 허용 (string, number, bool, object)
"^\\[\\s*(true|false|\"[\\w\\s]*\"|[\\d]+|\\{\\s*\"[\\w\\s]+\"\\s*\\:\\s*(true|false|\"[\\w\\s]*\"|[\\d]+)\\s*((?:,\\s*\"[\\w\\s]+\"\\s*\\:\\s*(true|false|\"[\\w\\s]*\"|[\\d]+))*)\\s*\\})\\s*((?:,\\s*(true|false|\"[\\w\\s]*\"|[\\d]+|\\{\\s*\"[\\w\\s]+\"\\s*\\:\\s*(true|false|\"[\\w\\s]*\"|[\\d]+)\\s*((?:,\\s*\"[\\w\\s]+\"\\s*\\:\\s*(true|false|\"[\\w\\s]*\"|[\\d]+))*)\\s*\\}))*)\\s*\\]$"
입력받은 string 을 넘겨서 JSON 패턴인지 체크하는 struct GrammarChecker
struct GrammarChecker {
static private let arrayPattern = "^\\[\\s*(true|false|\"[\\w\\s]*\"|[\\d]+|\\{\\s*\"[\\w\\s]+\"\\s*\\:\\s*(true|false|\"[\\w\\s]*\"|[\\d]+)\\s*((?:,\\s*\"[\\w\\s]+\"\\s*\\:\\s*(true|false|\"[\\w\\s]*\"|[\\d]+))*)\\s*\\})\\s*((?:,\\s*(true|false|\"[\\w\\s]*\"|[\\d]+|\\{\\s*\"[\\w\\s]+\"\\s*\\:\\s*(true|false|\"[\\w\\s]*\"|[\\d]+)\\s*((?:,\\s*\"[\\w\\s]+\"\\s*\\:\\s*(true|false|\"[\\w\\s]*\"|[\\d]+))*)\\s*\\}))*)\\s*\\]$"
static private let objectPattern = "^\\{\\s*\"[\\w\\s]+\"\\s*\\:\\s*(true|false|\"[\\w\\s]*\"|[\\d]+)\\s*((?:,\\s*\"[\\w\\s]+\"\\s*\\:\\s*(true|false|\"[\\w\\s]*\"|[\\d]+))*)\\s*\\}$"
static func check(input: String) throws {
let isJSONArray = try match(for: arrayPattern, input: input)
let isJSONObject = try match(for: objectPattern, input: input)
if isJSONArray || isJSONObject {
return
}
throw GrammarCheckerError.matchNoPattern
}
static private func match(for pattern: String, input: String) throws -> Bool {
guard let regex = try? NSRegularExpression(pattern: pattern, options: .caseInsensitive) else {
throw GrammarCheckerError.invalidRegexPattern
}
let range = NSRange(input.startIndex..., in: input)
let matches = regex.matches(in: input, options: [], range: range)
let matchedString = matches.map { match -> String in
let range = Range(match.range, in: input)!
return String(input[range])
}
return matchedString.count == 1 && matchedString[0] == input
}
}
유용한 사이트
- https://regex101.com/
- 요소별로 컬러링, 파싱, 설명도 같이 나옴. 패턴 체크 가능
- https://regexper.com/
- 다이어그램으로 보여줌
- https://www.regular-expressions.info/
- 배울 수 있는 곳
- https://www.raywenderlich.com/5767-an-introduction-to-regular-expressions
- introduction
- https://www.raywenderlich.com/5765-regular-expressions-tutorial-getting-started
- NSRegularExpresion tutorial