아리의 iOS 탐구생활

[Swift] String Options에 대해서 알아보자. 본문

Swift/자료구조

[Swift] String Options에 대해서 알아보자.

Ari Lee 2021. 8. 24. 19:38
반응형

 

Apple Developer Documentation

 

developer.apple.com

 

 

🔍 CaseInsensitive Option

스위프트에서는 대소문자를 구분하는데, 해당 옵션을 추가하면 대소문자 구분을 없앨 수 있다.

"A" == "a" // false
"A".caseInsensitiveCompare("a") == .orderedSame // true
"A".compare("a", options: [.caseInsensitive]) == .orderedSame // true

/*
원래 해당 옵션의 풀네임은 NSString.CompareOptions.caseInsensitive 이건데,
스위프트는 타입추론이 가능하여 보다 짧게 입력하여 편리하게 사용할 수 있다.
*/

 

 

🔍 Literal Option

 

// 한이라는 글자의 완성형과 조합형을 저장.
let a = "\u{D55C}"
let b = "\u{1112}\u{1161}\u{11AB}"
a == b // true
a.compare(b) == .orderedSame // true
// 스위프트는 여러개의 코드 유닛을 조합했을때 얻게되는 최종 결과도 함께 비교한다.

그러나 objective-c에서는 코드 유닛을 조합했을 때 얻게되는 최종 결과는 비교하지 않는다. 따라서 위와 같은 코드의 결과도 반대로 나온다. 그래서 하나의 프로젝트에서 두개의 언어를 함께 사용하는 경우라면 조심해야 한다. 따라서 스위프트에서 문자코드를 직접 비교하고 싶다면 literal 옵션을 사용해주면 된다.

a.compare(b, options: [.literal]) == .orderedSame // false

이렇게 literal 옵션을 사용하여 코드를 비교하면 기존에 literal 옵션을 사용하지 않은 코드보다 더 빠른 속도로 결과를 비교한다. 왜냐하면 literal 옵션을 사용하지 않을때에는 코드 유닛으로 문자를 구성하여 얻게되는 최종 결과로 비교를 해야하기 때문이다. 반면 literal 옵션을 사용하게 되면 문자코드로 비교를 하기 때문에 코드가 다르다면 바로 false를 리턴하여 속도가 빠르다는 장점이 있다.

 

 

 

 

🔍 Backwards Option

문자열의 검색 방향을 바꾸는 옵션이다.

let korean = "행복하세요" // 왼쪽에서 오른쪽으로 읽는다
let english = "Be happy" // 영어도 왼쪽에서 오른쪽으로…
let arabic =  "كن سعيدا" // 반면에 아랍어는 오른쪽에서 왼쪽으로 읽는다.

보통 iOS에서는 문자열 시작부분과 끝부분을 왼쪽 오른쪽으로 나누지 않고 문자열 시작부분을 Leading이라 하고 끝부분을 Trailing 이라고 한다. 그리고 기본적으로 스위프트에서는 문자열을 검색할 때 Leading이 왼쪽이고 Trailing이 오른쪽이다. 만약 아랍어를 검색해야 한다면 backwards 옵션을 활용하여 거꾸로 검색해야 될 것 이다.

if let range = english.range(of: "p") { // 5
    english.distance(from: english.startIndex, to: range.lowerBound)
}
if let range = english.range(of: "p", options: [.backwards]) { // 6
    english.distance(from: english.startIndex, to: range.lowerBound)
}

 

 

 

 

🔍  Anchored Option

자열의 검색범위를 시작이나 끝으로 제한하는 옵션이다.

let str = "Hello, Programming"

if let result = str.range(of: "Hello") {
    print(str.distance(from: str.startIndex, to: result.lowerBound))
} else {
    print("not found")
}
// Hello가 검색되었고 첫번째 인덱스 '0'이 출력되었다.
if let result = str.range(of: "Hello", options: [.backwards]) {
    print(str.distance(from: str.startIndex, to: result.lowerBound))
} else {
    print("not found")
}
// 이번에도 마찬가지로 첫번째 인덱스 '0'이 출력되었다.

검색을 앞으로 하나 뒤로하나 Hello의 첫번째 인덱스는 0이다.

if let result = str.range(of: "Hello", options: [.anchored]) {
    print(str.distance(from: str.startIndex, to: result.lowerBound))
} else {
    print("not found")
}
// 시작부분에서 "Hello"를 검색할 수 있기 때문에 정상적으로 '0'이 출력된다.
if let result = str.range(of: "Hello", options: [.anchored, .backwards]) {
    print(str.distance(from: str.startIndex, to: result.lowerBound))
} else {
    print("not found")
}
// 끝부분에서는 "Hello"를 검색할 수 없기 때문에 not found가 출력된다.

이처럼 anchored 옵션은 문자열 전체를 검색하는 것이 아니라 문자열중에서 시작부분이나 마지막부분에서만 검색을 한다.

anchored 옵션을 backwards 옵션과 함께 사용한다면 접미어 비교에 활용할 수 있고, backwards옵션 없이 사용한다면 접두어 비교에 활용할 수 있겠다.

 

 

 

 

 

🔍  Numeric Option

스위프트는 문자열을 비교할 때 단순히 사전순서를 비교하는 것이 아니라 문자에 할당되어 있는 코드 크기를 비교한다.

"A" < "B" // true
"a" < "B" // false

 

numeric 옵션은 숫자를 문자가 아니라 숫자 자체로 비교하는 옵션이다.

let file9 = "file9.txt"
let file10 = "file10.txt"

file9 < file10 // false
file9.compare(file10) == .orderedAscending // false
file9.compare(file10, options: [.numeric]) == .orderedAscending // true

따라서 9가 10보다 작기 때문에 true가 리턴된다.

 

 

 

 

 

🔍  Diacritic Insensitive Option

발음 기호가 있는 문자와 발음 기호가 없는 문자를 비교하게 되면 어떤 결과가 나올까?

let cafe = "Cafe"
let cafe2 = "Cafè"

cafe == cafe2 // false
cafe.compare(cafe2) == .orderedSame // false

스위프트는 문자열을 비교할 때 눈으로 보이는 실제 모양을 비교한다. 따라서 모양이 다르기 때문에 false가 리턴된다.

하지만 diacriticInsensitive 옵션을 사용한다면 발음 기호를 무시하고 문자열을 비교할 수 있게 된다.

cafe.compare(cafe2, options: [.diacriticInsensitive]) == .orderedSame // true

 

 

 

 

 

🔍 Width Insenstive Option

아시안 국가에서 사용하는 문자들을 보면 전각문자나 반각문자로 표현할 수 있다.

전각문자는 영문자의 고정 폭의 두 배 정도의 넓이를 가지는 문자이고, 반각문자는 전각 문자 폭의 절반의 넓이를 가지는 문자를 뜻한다.

아래는 일본어의 가타카나 첫번째 문자를 전각문자와 반각문자로 구현한 것이다.

let a = "\u{30A1}" // ァ
let b = "\u{ff67}" // ァ
a == b // false
a.compare(b) == .orderedSame // false

같은 뜻을 가진 문자이지만 스위프트는 보이는 문자를 비교하기 때문에 false를 리턴한다. 따라서 전각문자와 반각문자 구분없이 비교하려면 widthInsensitive 옵션을 사용하여 비교해주면 된다.

a.compare(b, options: [.widthInsensitive]) == .orderedSame // true

 

 

 

 

🔍 Forced Ordering Option

아래와 같이 문자열의 대소문자 구분을 피하기 위해서는 옵션을 사용하여 비교해야 했었다.

let lower = "string"
let upper = "STRING"

lower == upper // false
lower.compare(upper, options: [.caseInsensitive]) == .orderedSame // true

forcedOrdering 옵션은 전체 옵션을 적용했을때 같은 문자열로 판단된다면 일부 옵션을 무시하고 최대한 문자열의 순서를 파악할 수 있는 값을 리턴해준다.

lower.compare(upper, options: [.caseInsensitive, .forcedOrdering]) == .orderedSame // false

이 경우에는 caseInsensitive 옵션을 무시한다.

 

 

 

 

 

🔍 Regular Expression Option

이건 정규식 옵션이다. 아주 자주 활용하는 옵션이다.

정규식을 사용하면 복잡한 패턴의 문자열을 쉽게 검색할 있다.

let regex = #"([0-9a-zA-Z_-]+)@([0-9a-zA-Z_-]+)(\.[0-9a-zA-Z_-]+){1,2}"#
let email = "lee_ari95@icloud.com🥰"

// 문자열중에 이메일만 검색하여 추출.
if let range = email.range(of: regex, options: [.regularExpression]) {
    print(email[range])
} else {
    print("이메일이 아닙니다.")
}

// 입력된 이메일이 정규식으로 뽑아낸 이메일과 같은지 비교.
if let range = email.range(of: regex, options: [.regularExpression]), (range.lowerBound, range.upperBound) == (email.startIndex, email.endIndex) {
    print("이메일이 맞습니다")
} else {
    print("이메일이 아닙니다.")
}
반응형
Comments