티스토리 뷰

Swift

Swift ) NSString.CompareOptions종류

Zedd0202 2018. 3. 24. 21:31
반응형

안녕하세요 :) Zedd입니다.

<일치하는 모든 문자열의 Attribute 바꾸고 싶을 >글을 쓰다가 NSString.CompareOptions에는 어떤것이 있는지..궁금해졌습니다.

저는..........caseInsensitive밖에 써보질 않아서..


NSString.CompareOptions종류



 caseInsensitive

● literal

● backwards

● anchored

● numeric

● diacriticInsensitive

● widthInsensitive

● forcedOrdering

● regularExpression


이만큼이 있는데요..!!
하나하나 보겠습니다. 예제는 음...뭘로 할지는 모르겠지만, 걍 하겠음 ㅎ

 caseInsensitive
가장 많이 쓰는 옵션이 아닌가 싶은데...많이들 써보셨나요?
혹시 case-sensitive는 들어보셨나요? case-sensitive는 대소문자를 구분하여 취급하는 것을 의미해요.
근데 caseInsensitive이니까 대소문자를 구분하지 않겠다!!!!!!!!라는 의미죠.

<일치하는 모든 문자열의 Attribute 바꾸고 싶을 >글에서도 caseInsensitive를 사용했었는데요, 

range = (attrStr.string as NSString).range(of: searchString, options: .caseInsensitive, range: range)
cs


바로 이 코드. 야 ㅇㅇ나는 "zedd"를 찾을건데, "Zedd"든 "zeDD"든 암튼 걍 제드인거는 다 찾아줘 ㅇㅇ


그래서 나는 searchString으로 비록 "zedd"를 줬지만, "Zedd"도 포함되었기 때문에 (caseInsensitive니까!!!) Zedd도 폰트색상이 바뀌게 된 것입니다. 


●  literal

정의는 "Exact character-by-character equivalence."

정확한 문자(character) 대등성.....?

.......


이걸 몇개 예제로 해봤는데, 딱히......뭐가 다른건지 모르겠어요...뭐지..? 

정말 문자 대 문자로 일치하는 것만 하는건가..?



ㅎㅎ알겠습니다...

여러분 compare메소드를 아시나요? 말그대로 "비교"해주는 메소드인데요, ComparisonResult타입의 enum을 리턴했었죠.


아 글 날라갔음ㄴ;ㅣ안아ㅏㄴ안ㅁ'라라베다ㅔㅂ[ㅈㅏㅇ'ㅔ망';ㅁㄴ티스토리 왜 임시저장기능이 왜 얼마전부터 갑자기 안되는 거죠? 왜...왜...........암ㄴ아ㅏㅏㅠㅠㅠ아 후...아......진짜아ㅏㅏ


후.........

자..여러분 compare메소드를 사용해봅시다. 아래 내용 막 rawValue가 0, 1, -1이런소리가 나올건데, 이걸 이해하려면 <ComparisonResult살펴보기>글을 읽고오시면 됩니다...글 날라가서....엄청 힘빠짐..

..이 많더라도 이해좀


자..시작할게요


저는 이걸보고..아니..literal을 줘도..똑같고......아니 애초에 "비교"라는게 문자 대 문자로 비교해야하는게 정상 아냐?;;라고 생각했죠. 

그러다가 NSString의 isEqualToString의 설명을 보게되었어요.



문자열 비교에 적용 할 때 "리터럴"은 다양한 유니 코드 분해 규칙이 적용되지 않고 UTF-16 코드 단위가 개별적으로 비교된다는 것을 의미합니다. 예를 들어 구성된 문자 시퀀스 "O"(U + 004F LATIN CAPITAL LETTER O)와 결합 분음 부호 "¨"(U + 0308 COMBINING DIAERESIS)로 표현되는 "Ö"는 다음과 같이 표현 된 "Ö" 단일 유니 코드 문자 (U + 00D6 대문자, 대문자로 된 대문자)는 같지 않습니다.


ㅋㅋ..이게 뭔소리여...

자 여러분 Ö를 나타내는 방법은 2가지가 있어요. 딱 Ö 그자체와, O와 “¨”를 합한 Ö.

뭔소린지 아직도 모르겠죠? 예제로 봅시다. 예제는 é로 해볼게요.



정말 신기하게도 위 3개가 똑같은 é를 나타냅니다. 그쵸?

맨 위에 str1은 é는 e와 '를 합성한 é고, str2는 é그 자체를 나타내는 é입니다. 밑에 é는 나중에 보도록 하죠.

그럼 str1과 str2를 비교하면 어떻게 될까요? 옵션을 아무것도 주지 않고 해볼게요 :)



0. 즉 같다고 나왔네요. 

그럼 지금의 주제.. literal옵션을 넣어보겠습니다. 



...!!0이 아니네요. -1이 나왔습니다. 왼쪽 피연산자가 오른쪽 피연산자보다 작다라는 의미인데, 이게 중요한게 아니라, 아니 뭐 중요할 수도 있지만..!! 제가 지금 강조하고싶은건, literal이라는 옵션을 추가함으로써 결과가 달라졌다는 것이죠. 그것도 "같지않다"라고요. 둘다 é인데 말이죠...


literal은 결과 문자열을 보는 것이 아니라, 안?..그 해당 문자열이 어떻게 합성되어있는지를 보는 옵션 같아요.



é를 주면, 분해가 되는게 아니라, é그자체로 저장이 되나 보네요. 같다고 나오죠?

literal이 뭔지 아시겠나요 :)?

다음으로 고고


●  backwards

정의는 Search from end of source string.입니다. 문자열의 끝에서부터 탐색하겠다 ㅇㅇ 라는 것이죠.

<일치하는 모든 문자열의 Attribute 바꾸고 싶을 >글에 있던 예제를 이용하면 좋겠네요. 옵션을 주지 않고, 


 let range = (text as NSString).range(of: "zedd", options: [])

 self.myLabelChangeColor(text, range: range)


텍스트의 색상을 바꾸는 메소드를 호출해볼게요. 

range는 <일치하는 모든 문자열의 Attribute 바꾸고 싶을 >글에서도 말했다시피, 앞에서부터 source문자열을 탐색하면서, 찾으려는 문자열을 가장 처음으로 만나게되는 range를 리턴한다고 그랬어요. 지금 이렇게 range를 주고 빌드해보면,


이렇게 앞에 딱 하나만 색상이 바뀌게 됩니다. 

하지만 backwards를 옵션을 주게 되면..?



let range = (text as NSString).range(of: "zedd", options: [.backwards])

self.myLabelChangeColor(text, range: range)


예상이 가죠? 뒤에서부터 탐색하겠다니까..

이렇게 되겠네요.

쉽죠XD


●  anchored

정의는 Search is limited to start (or end, if NSBackwardsSearch) of source string.

탐색은 소스 문자열의 시작 (또는 끝, NSBackwardsSearch 인 경우)으로 제한됩니다.


??..


let range = ("hello, zedd. Zedd hava a zeddyzedd!" as NSString).range(of: "zedd", options: [.anchored])

print(range)//NSNotFound


????????

저는 그냥 옵션으로 anchored만 줬을 뿐인데.......NSNotFound...왜..?저기에 zedd가 얼마나 많은데...

라고 했죠..애초에 정의도.."탐색은 소스 문자열의 시작 (또는 끝, NSBackwardsSearch 인 경우)으로 제한됩니다." 아니 그럼 탐색을 문자열의 시작부터 하지 어디서부터 하나; 라고 생각했죠.


근데 말그대로...."시작"이었어..

여러분, "hello, zedd. Zedd hava a zeddyzedd!"의 "시작"이 뭐죠? h든, he든 hello든 일단 zedd는 아니죠. 그래서 NSNotFound가 나온것입니다..!!!!

 

let range = ("zeddhello, zedd. Zedd hava a zeddyzedd!" as NSString).range(of: "zedd", options: [.anchored])

print(range)//{0,4}


.....네...그렇습니다...바로 이해가 가죠? 


let range = ("zeddhello, zedd. Zedd hava a zeddyzedd" as NSString).range(of: "zedd", options: [.anchored,.backwards])

print(range)//{34,4}


anchoredbackwards를 옵션으로 같이주게 되면, 맨끝에 있는 zedd가 걸리게 되겠죠?


 numeric

이름부터 숫자의 냄새가..
"Numbers within strings are compared using numeric value."
문자열 내의 숫자는 숫자 값을 사용하여 비교됩니다. 예를들어, 
Name2.txt < Name7.txt < Name25.txt이죠. 
숫자 비교는 문자열의 숫자에만 적용되며 음수 기호, 쉼표 또는 소수점과 같은 숫자 표현에서 의미가있는 다른 문자에는 적용되지 않습니다.
이 옵션은 비교(compare) 방법에만 적용되며 찾기(find)에는 적용되지 않습니다.

오....해봅시다. 일단 compare에서만 된다니, 아까 써본 compare을 다시 써봅시다.

var str1 = "Zedd1"

var str2 = "Zedd100"

str1.compare(str2, options: [.numeric]).rawValue//-1



자.. "왼쪽 피연산자가 오른쪽 피연산자보다 작습니다"를 의미하는 -1이 나왔네요. 
ㅇㅇ야 나는 이 문자열안에 들어있는 숫자로 얘네를 비교하고싶어. 라고 하게 되면, 이런 결과가 나오는 것이죠.
왜냐면 str1은 1이고,  str2는 100이니까, 즉 str1. 왼쪽이 더 작죠.

근데 여기서 주의해야할 점이 있습니다...<>글에서도 말했다시피...이 compare는 문자열의 아스키코드값으로 크기를 판별하기 때문에...


아무리 str2가 큰 값을 가지고 있어도...h로 시작해서.........1에게 지게 됩니다.

rawValue가 1이 나왔으니, "왼쪽이 더 크다"라는 결과니까요.

아니 이런건 좀 어케 해줘야 하는거 아닌가?...;

아무튼 주의하세요. numeric은 다른건 다 같고, 숫자만 다를 때, 진짜 Apple이 들어준 예제인

"Name2.txt < Name7.txt < Name25.txt" 이럴경우에는 사용하면 좋겠네요 :)



 diacriticInsensitive


저는 diacritic을 처음...들어봐서..찾아봤더니


아 아까 
é같은거?...아하아하 
그럼 diacriticInsensitive니까 é나 e나 구별하지 않겠다는 의미같네요. 
그렇다면 바로 실험 ㄱㄱ

var str1 = "é"

var str2 = "e"

str1.compare(str2, options: .diacriticInsensitive).rawValue//0


역시나!!!!!!!! 원래같으면 rawValue로 1이나오는데, 아 나는 é나 e나 똑같이 볼게 ㅇㅇ했으니 둘이 같다!!라는 결과가 나오는 것이죠. 오옹

 widthInsensitive

너비..?
탐색은 동아시아 문자 집합에서 발생하는 것과 같이 전폭 및 반자 형태의 문자에서 폭 차이를 무시합니다.
ㅇㅎㅇㅎ
아니 이거 무슨소리인진 알겠는데, 예제를....Apple이 다행히도 간단한 예를 하나 들어줬는데, 

"For example, with this option, the full-width Latin small letter 'a' (U+FF41) is equal to the basic Latin small letter 'a' (U+0061)."


자..보면..둘다..a긴한데..너비가 다릅니다. str1이 조금 더 너비가 더 넓은거 보이시나요? 

아니 근데 이걸 왜;;너비를 왜 다르게 한지는 모르겠지만..뭔 쓰임이 다른가보네요..아무튼 얘네 두개는 둘다 a긴 하지만..너비가 달라서 다른 문자입니다.




옵션을 하나도 안주게 되면, 왼쪽(str1)이 더 크네 ㅎ 라고 말해줍니다.
하지만..우리에겐 방금 배운 옵션이 하나가 있죠. 바로 widthInsensitive. 너비를 신경 안쓰겠다!!라는 옵션이죠.



두 문자열이 똑같다고 나오죠? XD



  forcedOrdering


정의는, NSOrderedAscending 또는 NSOrderedDescending 중 하나라도 문자열이 동등하지만 엄격하게 같지(strictly equal) 않으면 비교가 강제로 반환됩니다.

이건 또 무슨소리여..
자..이것도 Apple이 예제를 하나 들어줬습니다. 
"This option ensures reliable, reproducible results when sorting. For example, “aaa” is greater than "AAA” if caseInsensitive is specified."

var str1 = "aaa"

var str2 = "AAA"

str1.compare(str2, options: [.caseInsensitive]).rawValue//0


자. 이건 당연한 결과죠? caseInsensitive가 옵션으로 주어져있으니, 둘다 소문자든 대문자든 상관 안하겠다!!라는 거죠? 그래서 두개가 같다는 결과가 나오게 됩니다. 하지만, forcedOrdering옵션을 주게 된다면?

var str1 = "aaa"

var str2 = "AAA"

str1.compare(str2, options: [.forcedOrdering, .caseInsensitive]).rawValue//1


결과가 달라지게 됩니다. 왼쪽이 오른쪽보다 더 크다!!라는 결과가 나왔네요. 즉 aaa > AAA가 나오게 되었습니다..

아스키코드로 따지면, 소문자가 더 값이 크죠? 그래서 caseInsensitive임에도 불구하고....aaa를 바로 크다고 하고 리턴해버리는 거죠. 

"엄격하게 같지(strictly equal) 않으면 비교가 강제로 반환됩니다."라는 말이 진짜네요...


  regularExpression


탐색 문자열은 ICU 호환 정규 표현식으로 처리됩니다. 이 옵션을 설정하면 caseInsensitive 및 anchored를 제외한 다른 옵션을 적용 할 수 없습니다. 이 옵션은 rangeOfString : ... 메소드와 replacementOccurrences (of : with : with : options : range :)에서만 사용할 수 있습니다.


아하..!!  이 예제는 나중에 넣도록 할게요!


NSString.CompareOptions옵션을 하나하나 봤는데, 진짜 공부가 많이 됐어요..!  XD 알아두어서 나쁠 것 없으니까..한번 쯤 읽어보면 좋다고 생각합니다. :)

도움이 되었길 바래요 XD 주말 잘 보내세요!!

반응형

'Swift' 카테고리의 다른 글

Swift ) Key decoding strategy  (0) 2018.04.08
Swift 4.1 Released! - 1  (0) 2018.04.07
Swift ) ComparisonResult살펴보기  (0) 2018.03.24
Swift4.1 ) flatMap -> compactMap  (2) 2018.03.11
Swift ) API Design Guidelines  (0) 2018.01.25