Apple 제공 Swift 프로그래밍 가이드(4.2)의 Strings and Characters 부분을 공부하며 정리한 글입니다. 개인적인 생각, 이해를 돕기 위한 예제도 조금 들어가있습니다.
들어가며
String 은 문자열을, Character 는 문자를 저장할 수 있는 타입입니다. Swift 의 String 은 단순한 문법으로 다룰 수 있으며, 그럼에도 불구하고 빠릅니다. 특히 String 두 개를 연결할 때 + 연산자만 사용하면 되는데, 이 부분은 Objective-C 에 비하면 참 편해졌습니다.
String 에 특정 상수/변수 등을 포함해야 할 때는 Objective-C 와 다르게 String Literal 안에 \(변수이름)을 넣어야 합니다. 이게 무슨 말인지는 String Interpolation 부분에서 자세히 알려드리겠습니다.
Swift 에서의 모든 String 은 encoding-independent Unicode character 로 구성되어 있으며, 유니코드 호환도 잘 됩니다.
NOTE
Swift’s String type is bridged with Foundation’s NSString class. Foundation 모듈이 String 의 extension 을 구현해놓았기 때문에, 현재는 Foundation 만 import 하면 String 으로도 NSString 의 메서드들을 사용할 수 있습니다.
Foundation 과 Cocoa 사이에서의 String 사용 방법에 대한 더 자세한 정보는 Bridging Between String and NSString 을 참고하세요.
String Literals
String Literal 이란 double quotes( " )로 둘러싸인 문자열을 말합니다. 이것을 통해 미리 String 값을 define 해놓고, String 상수/변수에 그 값을 할당할 수 있습니다.
let someString = "Some string literal value" // String Literal로 초기화된 변수는 String 타입 (타입유추됨) let lenghtOneString = "a" // 이 경우도 변수는 String 타입. Character 타입이라고 명시하면 Character 타입이 된다. | cs |
Multiline String Literals
만약 여러 라인으로 나눠서 입력할 String Literal 이 필요하다면 그 시작과 끝을 three double quotation marks( """ )로 감싸세요.
let quotation = """ The White Rabbit put on his spectacles. "Where shall I begin, please your Majesty?" he asked. "Begin at the beginning," the King said gravely, "and go on till you come to the end; then stop." """ let singleLineString = "These are the same." let multilineString = """ These are the same. """ // backslash (\) 를 써주면 String 값에서는 그 라인에서 자동 줄바꿈되지 않습니다 let softWrappedQuotation = """ The White Rabbit put on his spectacles. "Where shall I begin, \ please your Majesty?" he asked. "Begin at the beginning," the King said gravely, "and go on \ till you come to the end; then stop." """ // 이 경우 앞뒤로 \n(라인 피드)가 들어갑니다 let lineBreaks = """ This string starts with a line break. It also ends with a line break. """ | cs |
멀티라인 String 은 들여쓰를 할 수 있습니다. 들여쓰기를 하려면 마침큰따옴표(closing quotation marks, """ )전에 공백(whitespace)을 넣으세요. 그러면 다른 라인들도 그만큼의 공백은 String 값에 포함되지 않고 그냥 무시됩니다.
Special Characters in String Literals
String literal 은 다음의 특별한 문자를 포함할 수 있습니다:
escaped special characters: \0 (null character), \\ (backslash), \t (horizontal tab), \n (line feed), \r (carriage return), \" (double quotation mark) and \' (single quotation mark)
arbitrary Unicode scalar: \u{n}, where n is a 1–8 digit hexadecimal number with a value equal to a valid Unicode code point
예제를 봅시다.
let wiseWords = "\"Imagination is more important than knowledge\" - Einstein" // "Imagination is more important than knowledge" - Einstein let dollarSign = "\u{24}" // $, Unicode scalar U+0024 let blackHeart = "\u{2665}" // ♥, Unicode scalar U+2665 let sparklingHeart = "\u{1F496}" // 💖, Unicode scalar U+1F496 let threeDoubleQuotationMarks = """ Escaping the first quotation mark \""" Escaping all three quotation marks \"\"\" """ | cs |
Initializing an Empty String
빈 문자열이 들어있는 String 타입 변수를 만드는 방법을 알아봅시다:
var emptyString = "" // empty string literal을 할당하거나 var anotherEmptyString = String() // 초기화 문법을 사용하거나 // 두 String 모두 똑같이 비어있다. | cs |
String 값이 비어있는지 확인하려면 Boolean 타입인 isEmpty 프로퍼티를 체크해보세요:
if emptyString.isEmpty { print("Nothing to see here") } // Prints "Nothing to see here" | cs |
String Mutability
변수는 값 변경 가능, 상수는 값 변경 불가의 룰이 똑같이 적용됩니다:
var variableString = "Horse" variableString += " and carriage" // variableString is now "Horse and carriage" let constantString = "Highlander" constantString += " and another Highlander" // this reports a compile-time error - a constant string cannot be modified | cs |
Swift 에서는 이처럼 String 이라는 타입이 하나 있고, 그 타입을 상수로 만들지 변수로 만들지에 따라 Mutability가 결정됩니다. 이것은 NSString / NSMutableString 등 변수의 타입 자체로 Mutability를 결정했던 Objective-C & Cocoa 와는 다른 방식입니다.
Strings Are Value Types
Swift 의 String 은 Value type 입니다. 따라서 함수나 메서드로 전달되거나 새로운 상수나 변수로 할당될 때에 그 String 값은 복사 됩니다. 이 경우 String 의 참조가 아닌 그 안에 들어있는 값만 새로 복사되어 전달되는 것이기 때문에, 복사된 값을 변경해도 원본은 영향받지 않습니다. 이 Value type 이라는 것은 Structures and Enumerations Are Value Types 에서 자세히 다루게 될 텐데, 값 복사본이 전달된다는 특성을 이해하고 있어야 앞으로 원하는 코드를 작성할 수 있을 것입니다. (NSString 의 경우에는 참조가 전달되기 때문에, 기존에 Objective-C 개발을 했던 경우 참조 전달과 착각하여 실수를 하기 쉽습니다.)
<추가설명1 - Value type 의 복사에 대해> Value type 의 할당을 할 때는 값 복사가 일어난다고 했습니다. 그러나 엄밀히 말하면 할당을 하는 시점마다 항상 복사가 일어나는 것은 아닙니다. 일단 복사는 하지않고 같은 곳만 바라보고 있다가, 값이 변경될 때에 복사를 하게 됩니다. 이것은 Swift 의 컴파일러가 최적화를 해주기 때문인데요. 왜 이런 식으로 동작하는 것일까요? 예를들어 Value type 중 하나인 Array 를 생각해보겠습니다. 만약 용량이 상당히 큰 Array 가 있는데, 이것을 함수 파라미터로 넘기거나 할 때마다 항상 Array 전체 복사가 일어난다면 성능이 많이 떨어질 것입니다.
<추가설명2 - Value type 과 Reference type 의 차이점 한 가지> Value type 은 var 로 선언될 경우에만 내부값 변경이 가능하고, Reference type 은 var 와 let 어느 것으로 선언되든지 내부값 변경이 가능합니다. 예를 들어 다음과 같은 Struct 하나를 떠올려봅시다: 이 Struct 에는 Name 이라는 내부 프로퍼티가 하나 있고 Name 은 var 로 선언되어 있습니다. 단순히 생각해보면 Name 을 언제든 바꿀 수 있을 것 같은 생각이 듭니다. 그러나 Struct 는 Value type 입니다. 따라서 이 Struct 가 만약 let 으로 선언되었다면 Name 프로퍼티는 변경이 불가능합니다. (반면 Reference type 의 경우에는 var 와 let 어느 것으로 선언되더라도 내부값을 변경할 수 있습니다. 참고로 NSObject 를 상속받은 객체, 기타 Class로 선언된 객체들이 Reference type 에 속합니다.)
Working with Characters
String 의 characters 프로퍼티를 사용하면 String 값의 각각의 문자(Character)에 접근할 수 있습니다다. for-in loop 를 이용하여 iterating 해봅시다:
for character in "Dog!🐶" { print(character) } // D // o // g // ! // 🐶 | cs |
for-in loop 에 대해서는 For-In Loops 에 자세히 기술되어 있습니다.
상수/변수를 생성할 때 Character 타입임을 명시하고 single-character string literal 을 할당하면 Character 타입을 만들 수 있습니다:
let exclamationMark: Character = "!" | cs |
Character 값들로 구성된 array 를 이니셜라이저에 넘겨서 String 타입을 만들 수 있습니다:
let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"] let catString = String(catCharacters) print(catString) // Prints "Cat!🐱" | cs |
Concatenating Strings and Characters
Swift 의 String 값들은 +, += 연산자를 통해 서로 더할 수 있습니다. Character 값을 String 값에 더하려면 append() 메서드를 사용해야 합니다. 예제로 알아보겠습니다:
let string1 = "hello" let string2 = " there" var welcome = string1 + string2 // welcome now equals "hello there" var instruction = "look over" instruction += string2 // instruction now equals "look over there" let exclamationMark: Character = "!" welcome.append(exclamationMark) // welcome now equals "hello there!" // <주의> welcome += exclamationMark 는 서로 타입이 달라서 Compile error | cs |
Character 타입은 오직 하나의 문자만 그 안에 담을 수 있습니다. 따라서 Character 타입의 변수에 다른 String 이나 Character 값을 더하는 것은 불가능합니다.
var str: String = "str" var char: Character = "c" let str_str = str + str let char_char = char + char // compile error let str_char = str + char // compile error let str_append_char = str.append(char) let str_let: String = "str_let" let str_let_append_char = str_let.append(char) //compile error | cs |
여러 줄의 string literal 을 더하는 경우에는 마지막 라인에 line break (\n) 가 포함되어 있느냐 없느냐에 따라 결과가 달라지는 경우가 있습니다. 예제로 알아봅시다:
let badStart = """ one two """ let end = """ three """ print(badStart + end) // Prints two lines: // one // twothree let goodStart = """ one two """ print(goodStart + end) // Prints three lines: // one // two // three | cs |
String Interpolation
상수, 변수, String literal 을 조합하여 String 을 만들 수 있습니다. 넣고 싶은 아이템을 괄호 + 백슬러시( \ )로 묶습니다. 예를 들어 변수를 String literal 에 포함시키고 싶다면 \(변수이름) 형태로 String literal 내의 적절한 위치에 넣습니다.
let multiplier = 3 let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)" // message is "3 times 2.5 is 7.5" | cs |
Note
String literal 괄호 안의 수식에는 unescaped backslash( \ ), carriage return, line feed 등을 포함시킬 수 없습니다. 그러나 다른 String literal 을 포함시킬 수는 있습니다.
Unicode
String 은 사실 유니코드 스칼라(Unicode scalar) 값들로 이루어져 있습니다. 유니코드 스칼라는 Character 하나하나를 위한 유니크한 21-bit Number 입니다. 예를 들어 U+0061 for LATIN SMALL LETTER A ("a"), or U+1F425 for FRONT-FACING BABY CHICK ("🐥").
Swift 의 모든 Character 인스턴스는 하나의 extended grapheme cluster 를 가집니다. Extended grapheme cluster 란, 유니코드 스칼라의 sequence 인데, combine 되면 사람이 읽을 수 있는 하나의 문자가 됩니다. 다음 예제를 봅시다:
let eAcute: Character = "\u{E9}" // é let combinedEAcute: Character = "\u{65}\u{301}" // e followed by ́ // eAcute is é (유니코드 스칼라 1개), combinedEAcute is é (유니코드 스칼라 2개) // 두 개는 같은 문자! let precomposed: Character = "\u{D55C}" // 한 let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ // precomposed is 한, decomposed is 한 let enclosedEAcute: Character = "\u{E9}\u{20DD}" // enclosedEAcute is é⃝ let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}" // regionalIndicatorForUS is 🇺🇸 | cs |
Counting Characters
String 을 구성하는 Character 개수를 알고 싶으면 String 의 count 프로퍼티를 사용합니다:
let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪" print("unusualMenagerie has \(unusualMenagerie.count) characters") // Prints "unusualMenagerie has 40 characters" | cs |
참고로 Character 하나에 포함된 유니코드 스칼라가 2개 이상이라도 그와 관계없이 Character 하나 당 count 는 하나로 간주됩니다. count 프로퍼티는 Character 의 개수를 세는 것이지 유니코드 스칼라의 개수를 세는 것이 아닙니다.
var word = "cafe" print("the number of characters in \(word) is \(word.count)") // Prints "the number of characters in cafe is 4" word += "\u{301}" // COMBINING ACUTE ACCENT, U+0301 print("the number of characters in \(word) is \(word.count)") // Prints "the number of characters in café is 4" | cs |
위 예제에서 볼 수 있는 것처럼 두 String 이 눈에는 같은 String 처럼 보일지 몰라도 그것을 구성하는 유니코드 스칼라의 개수와 종류는 다를 수도 있습니다. 따라서 똑같은 것처럼 보이는(same string's representation) 두 String 이 서로 다른 양의 메모리를 차지하고 있는 경우도 있습니다.
Accessing and Modifying a String
String 의 값에 접근하거나 변경하는 방법을 알아봅시다. String 의 메서드, 프로퍼티, 서브스크립트 문법 등을 통해 가능합니다.
String Indices
String 값을 구성하는 Character 들 각각이 String 의 어느 위치에 있는지 가리키기 위하여 index type 인 String.Index 가 사용됩니다.
왜 Int 값으로 Character 의 위치에 접근하지 못하고 굳이 index type 을 써야할까요? 그 이유는 위에서 설명한 유니코스 스칼라에 있습니다. Character 마다 차지하는 메모리가 다를 수 있으며, 유니코드 스칼라를 몇 개씩 건너뛰어야 다음 Character 가 나올지 미리 알 수 없기 때문에 그 역할을 해주는 index type 을 사용하는 것입니다.
String 에는 index 를 위한 다음 프로퍼티가 있습니다.
- startIndex : 첫 번째 Character 를 가리키는 index
- endIndex : 마지막 Character의 한 칸 뒤 index. 따라서 endIndex 에서 한 칸 앞으로 와야 마지막 Character 를 가리키게 됩니다.
String 에는 Index 를 위한 다음 메서드가 있습니다.
- index(before:) : 바로 전
- index(after:) : 바로 뒤
- index(_:offsetBy:) : 오른쪽 방향으로 N만큼 떨어져있는 곳(음수면 왼쪽으로 N만큼)
let greeting = "Guten Tag!" greeting[greeting.startIndex] // G greeting[greeting.index(before: greeting.endIndex)] // ! greeting[greeting.index(after: greeting.startIndex)] // u let index = greeting.index(greeting.startIndex, offsetBy: 7) greeting[index] // a | cs |
greeting[greeting.endIndex] // Error greeting.index(after: greeting.endIndex) // Error | cs |
for index in greeting.indices { print("\(greeting[index]) ", terminator: "") } // Prints "G u t e n T a g ! "
// 다시 한 번 강조하지만, 위 코드에서의 index 는 0, 1 등의 number type 이 아니라 index type! | cs |
Inserting and Removing
String 의 특정 인덱스에 Character 하나를 삽입하려면 insert(_:at:) 메서드를 사용하세요. 그리고 특정 인덱스에 다른 String 을 삽입하려면 insert(contentsOf:at:) 메서드를 사용하세요.
// String 특정 위치에 Character 삽입하기 var welcome = "hello" welcome.insert("!", at: welcome.endIndex) // welcome now equals "hello!" // String 특정 위치에 다른 String 삽입하기 welcome.insert(contentsOf: " there", at: welcome.index(before: welcome.endIndex)) // welcome now equals "hello there!" | cs |
반대로 특정 Character, String 을 제거하는 경우에는 remove(at:) 와 removeSubrange(_:) 메서드를 사용하세요.
// String에서 특정 위치의 Character 지우기 welcome.remove(at: welcome.index(before: welcome.endIndex)) // welcome now equals "hello there" // String에서 sub string 지우기 let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex welcome.removeSubrange(range) // welcome now equals "hello" | cs |
NOTE
RangeReplaceableCollection 프로토콜을 따르는 어떤 타입이건 insert(_:at:), insert(contentsOf:at:), remove(at:), removeSubrange(_:) 메서드를 사용할 수 있습니다. String, Array, Dictionary, Set 등 모두 포함됩니다.
Substrings
String 의 서브 스트링을 가져올 때—예를 들어, 서브스크립트를 사용하거나 prefix(_:) 같은 메서드를 사용해서—그 결과는 Substring 인스턴스입니다. 또 다른 String 이 아니라요. Swift 의 Substring 은 String 의 메서드와 똑같은 메서드들을 많이 가지고 있습니다. 즉 String 을 다룰 때와 같은 방식으로 Substring 을 다룰 수 있습니다. 그러나 Substring 은 String 을 가지고 특정 액션을 수행하는 짧은 시간에서만 사용하도록 하세요. 만약 긴 시간동안 Substring 을 저장하고 사용해야 한다면 Substring 을 String 의 인스턴스로 변환한 다음 그렇게 하세요. 예제를 보겠습니다:
let greeting = "Hello, world!" let index = greeting.firstIndex(of: ",") ?? greeting.endIndex let beginning = greeting[..<index] // beginning is "Hello" // Convert the result to a String for long-term storage. let newString = String(beginning) | cs |
Substring 도 String 과 마찬가지로 자신을 구성하는 문자열들이 저장되는 메모리를 참조하고 있습니다. 그러나 String 과 Substring 은 성능 최적화 측면에서 달라지는데요, Substring 은 Original String 을 저장하기 위해 사용되는 메모리의 일부를 재사용할 수 있습니다. 또한 다른 Substring 을 저장하기 위해 사용되는 메모리의 일부를 재사용할 수도 있습니다. (String 역시 비슷한 최적화가 이루어지지만, String 의 경우에는 두 개의 String 이 같은 메모리를 공유한다면 이 두 개의 String 은 서로 동일합니다(equal 관계에 놓여 있습니다).) 이런 성능 최적화의 효과로, String 이나 Substring 의 값을 수정하기 전까지는 메모리 복사가 이루어지지 않습니다. 즉 메모리 복사에 대한 자원을 절약할 수 있습니다. 앞서 언급했던 것처럼 Substring 은 긴 시간 사용하기에는 적절하지 않습니다(not suitable for long-term storage). 왜냐하면 Substring 은 Original String 의 메모리를 재사용하기 때문에 Substring 이 사용되는 동안에는 이 Original String 이 통째로 메모리에 남아 있어야 하기 때문입니다.
위 예제에서 greeting 은 String 입니다. 따라서 greeting 은 자신을 구성하는 문자열들이 저장되는 메모리를 참조하고 있습니다. beginning 이 greeting 의 Substring 이기 때문에, beginning 은 greeting 이 사용하는 메모리를 재사용합니다. 그와 다르게 newString 은 String 입니다. 따라서 newString 은 자신만의 메모리를 할당받습니다. 아래 그림은 이런 관계들을 보여주고 있습니다:
NOTE
String 과 Substring 둘 다 StringProtocol 을 따르고 있습니다. 그러니 String 값을 조작하는 함수에 이 타입들을 편리하게 사용할 수 있습니다.
Comparing Strings
String 비교에는 세 가지 종류가 있습니다.
- String and Character Equality : 문자열 전체 비교. 참고로 두 Character의 유니코드 스칼라의 조합에 차이가 나더라도 결과적으로 외관과 의미가 동일한 Character라면 두 Character는 같다고 취급.
- prefix equality : 앞이 일치하는지
- suffix equality : 뒤가 일치하는지
let quotation = "We're a lot alike, you and I." let sameQuotation = "We're a lot alike, you and I." if quotation == sameQuotation { print("These two strings are considered equal") } if quotation.hasPrefix("We") { print("quotation start with We") } if quotation.hasSuffix("I.") { print("quotation end with I.") } | cs |
앞서 살펴보았듯이 String은 Character(문자열)로 구성되고, Character는 Unicode Scalar로 구성됩니다.
Unicode String 을 텍스트 파일이나 다른 저장소에 쓰게될 때, String 을 구성하는 유니코드 스칼라들은 다음 encoding forms 중 하나로 인코딩됩니다.
- UTF-8 encoding form (인코딩을 위한 codeUnit이 8-bit)
- UTF-16 encoding form (인코딩을 위한 codeUnit이 16-bit)
- UTF-32 encoding form (인코딩을 위한 codeUnit이 32-bit)
앞에서는 String을 for-in loop 로 돌면서, String 을 구성하는 각각의 Character 값에 접근하는 법을 알아보았습니다. (엄밀히 말하면 Unicode extended grapheme cluster를 하나씩 for문으로 도는 것입니다.)
지금부터는 String의 값을 유니코드 표현법으로 접근하는 법을 살펴봅시다. 종류는 다음 세 가지가 있습니다.
- UTF-8 code units의 collection (String의 utf8 프로퍼티를 통해 접근)
- UTF-16 code units의 collection (String의 utf16 프로퍼티를 통해 접근)
- UTF-32 code units의 collection (String의 unicodeScalars 프로퍼티를 통해 접근)
예제를 통해 하나씩 살펴봅시다.
let dogString = "Dog‼🐶" | cs |
위 String 은 다음과 같은 Character 들로 구성되어 있습니다.
- D
- o
- g
- !! (DOUBLE EXCLAMATION MARK or 유니코드 스칼라 U+203C)
- 🐶 (DOG FACE or 유니코드 스칼라 U+1F436)
이제 이 String의 값에 유니코드 표현법으로 접근해봅시다.
UTF-8 Representation
String 의 utf8 프로퍼티를 사용하세요.
- Type: String.UTF8View
- collection of unsigned 8-bit (UInt8) values
for codeUnit in dogString.utf8 { print("\(codeUnit) ", terminator: "") } print("") // Prints "68 111 103 226 128 188 240 159 144 182 " | cs |
처음 3개 codeUnit 값 (68, 111, 103) 은 각각 D, o, g 를 표현합니다. 1 byte 만으로 표현할 수 있는 이런 문자들은 ASCII 로 표기했을 때도 동일한 코드를 가집니다. 그 다음 3개 codeUnit 값 (226, 128, 188) 은 3 byte UTF-8 이고 DOUBLE EXCLAMATION MARK 문자를 표현합니다. 마지막 4개 codeUnit 값 (240, 159, 144, 182) 는 4 byte UTF-8 이고 DOG FACE 문자를 표현합니다.
UTF-16 Representation
String 의 utf16 프로퍼티를 사용하세요.
- Type: String.UTF16View
- collection of unsigned 16-bit (UInt16) values
처음 3개 codeUnit 값 (68, 111, 103) 은 각각 D, o, g 를 표현하며 이는 UTF-8 표현과 같은 값입니다. D, o, g 는 ASCII character 로 표기할 수 있는 문자들이기 때문입니다.
4번째 codeUnit 값 (8252) 는 16진수 값 203C 를 10진수로 나타낸 것입니다. 유니코드 스칼라 U+203C 는 DOUBLE EXCLAMATION MARK 문자를 표현합니다. 이 문자는 UTF-16 에서 1개의 code unit 으로 나타낼 수 있습니다.
그러나 그 다음 나오는 DOG FACE 문자는 UTF-16 에서 2개의 codeUnit 이 필요합니다. 55357(U+D83D)과 56374(U+DC36)은 DOG FACE를 나타내기 위한 UTF-16 surrogate pair 입니다.
<보충설명> surrogate pair 란? 2 byte 인 UTF-16 으로 모든 문자를 표현하기에는 부족하기 때문에, 2 byte 만으로는 표현할 수 없는 예외 문자들을 Supplementary Characters 라고 정했습니다. 이 문자를 만들기 위한 인코딩 방식을 Surrogate Pair 라고 합니다.
Unicode Scalar Representation
String 의 unicodeScalars 프로퍼티를 사용하세요.
- Type: UnicodeScalarView
- collection of values of type UnicodeScalar
- 각 UnicodeScalar 는 value 라는 프로퍼티를 가진다. (scalar의 21-bit value, 즉 Uint32 값)
for scalar in dogString.unicodeScalars { print("\(scalar.value) ", terminator: "") } print("") // Prints "68 111 103 8252 128054 " | cs |
처음 세 개의 UnicodeScalar 값 (68, 111, 103) 은 변함없이 D, o, g 입니다.
4번째 codeUnit 값 (8252) 도 변함없이 16진수 값 203C 를 10진수로 나타낸 것입니다. 유니코드 스칼라 U+203C 는 DOUBLE EXCLAMATION MARK 문자를 표현합니다.
그 다음 UnicodeScalar 값 128054 는 DOG FACE 인 유니코드 스칼라 U+1F436 을 10진수로 나타낸 것입니다.
다음과 같이 UnicodeScalar 를 통해 새로운 String 값을 구성할 수도 있습니다:
for scalar in dogString.unicodeScalars { print("\(scalar) ") } // D // o // g // ‼ // 🐶 | cs |
'Swift 공식 가이드 > Swift 4' 카테고리의 다른 글
Collection Types (0) | 2018.09.05 |
---|---|
Basic Operators (0) | 2018.03.23 |
The basics (0) | 2018.03.02 |
A Swift Tour (0) | 2017.10.17 |
Version Compatibility (0) | 2017.10.04 |