all white cheat sheet Dana’s Swifty Life

Regular Expression : Swift 에서 정규표현식 사용 - NSRegularExpression

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 or false
    • 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]+"
    
  • object : { string : jsonvalue (, string : jsonvalue) } 형태

    {\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

JSON String

 

NSRegularExpression 사용하기

regex pattern 에 매치되는지 확인할 때 사용

  • init : pattern과 option 설정

  • matches method

    • input : pattern 검사될 string, 검사될 string의 range(NSRange)
    • output : 매치된 문자열들 - [NSTextCheckingResult]
  • 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)에서 매치된 부분의 범위!

    • NSRangeRange 로 변경해서 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
    }
}

 

유용한 사이트