-
Strings & CharactersiOS/Swift 공식문서 2022. 2. 14. 17:33
String Literals
큰 따옴표로 감싸서 String 값을 만들 수 있다.
let someString = "Some string literal value"
Multiline String Literals
"""
로 감싸면 여러 줄에 걸쳐서 String 리터럴을 만들 수 있다. 줄넘김도 그대로 반영된다.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." """ print(quotation)
줄넘김을 포함시키지 않으려면 각 줄의 맨 뒤에
\
를 적으면 된다.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." """
처음과 끝에 line feed를 만들고자 하면, 빈 줄을 처음과 끝에 추가하면 된다.
let lineBreaks = """ This string starts with a line break. It also ends with a line break. """
Multiline String의 경우 주변 코드와 들여쓰기를 맞출 수 있게 하는 기능을 제공한다. 닫는 따옴표 이전의 띄어쓰기 개수만큼 각 줄을 시작할 때 띄어쓰기를 무시한다. 그 개수보다 많은 띄어쓰기를 앞에 붙인 경우에는, 그 차이만큼 String에 반영된다. 다음 예시에서 String을 출력한다면, 첫번째와 세번째 줄은 들여쓰기가 없고, 두번째 줄에만 들여쓰기가 있게 된다.
Special Characters in String Literals
String Literal에 포함할 수 있는 특수 문자들은 다음과 같다.
\0
(null 문자),\\
(역슬래시),\t
(tab),\n
(줄넘김),\r
(carriage return),\"
(큰따옴표),\'
(작은따옴표)\u{n}
(임의의 유니코드 문자, n은 8자리 이내의 16진법 수)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
multiline string 안에 큰 따옴표 3개를 넣고 싶으면 한 번만 escape하면 된다. 다음 예시에서 두 줄의 따옴표 3개는 똑같이 출력된다.
let threeDoubleQuotationMarks = """ Escaping the first quotation mark \""" Escaping all three quotation marks \"\"\" """
Extended String Delimiters
String 리터럴의 양쪽을 같은 개수의
#
으로 감싸면 특수문자를 작성하는 sequence를 출력할 수 있다.print(#"Line 1\nLine 2"#) // '\n'을 그대로 출력
Delimiter가 있는 상태에서 특수문자를 출력하고 싶다면 sequence 중간에
#
을 같은 개수만큼 작성하면 된다.print(#"Line 1\nLine 2"#) print(###"Line1\###nLine2"###) // 둘 다 두 줄에 걸쳐서 출력
multiline String에서도
"""
를 출력하기 위해 delimiter를 사용할 수 있다.let threeMoreDoubleQuotationMarks = #""" Here are three more double quotes: """ // 마지막에 """ 도 출력됨 """#
Initializing an Empty String
리터럴을 사용하거나 initializer를 사용하는 방법이 있다. 빈 문자열인지는
isEmpty
라는 프로퍼티를 통해 확인할 수 있다.var emptyString = "" // empty string literal var anotherEmptyString = String() // initializer syntax // these two strings are both empty, and are equivalent to each other if emptyString.isEmpty { print("Nothing to see here") }
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
Strings Are Value Types
C나 Java에서 String이 클래스로 취급되는 것과는 달리, Swift에서는 String은 value type이다. 따라서 함수에 매개변수로 넘겨줄 때도 call by value로 처리된다. 따라서 함수 안에서 String을 수정해도 함수 호출이 끝나면 원래 값이 유지된다.
Working with Characters
String의 경우
for-in
을 통하여 각 문자에 대한 반복문을 수행할 수 있다.for character in "Dog!🐶" { print(character) } // D // o // g // ! // 🐶
문자 하나에 해당하는 Character 상수/변수를 생성할 수 있다. Swift가 String으로 추론하지 않도록 타입을 명시해야 한다.
let exclamationMark: Character = "!"
Character들의 배열을 이용하여 String을 생성하는 것도 가능하다.
let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"] let catString = String(catCharacters) print(catString) // Prints "Cat!🐱"
Concatenating Strings and Characters
String 끼리 더할 때는 +를 이용하면 된다.
let string1 = "hello" let string2 = " there" var welcome = string1 + string2 // welcome now equals "hello there"
+=
를 통하여 기존 String 뒤에 이어붙이는 것이 가능하다.var instruction = "look over" instruction += string2 // instruction now equals "look over there"
String에 Character 하나를 붙이려 한다면 String의
append()
메서드를 호출하면 된다.let exclamationMark: Character = "!" welcome.append(exclamationMark) // welcome now equals "hello there!"
multiline String의 경우도 다른 String처럼 concatenation이 가능하다. 줄넘김을 주의하자.
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
String Interpolation
String이 아닌 다른 타입의 값을 편리하게 String에 포함시키기 위한 기능이다. String 리터럴 안에
\()
을 이용하여 값을 삽입한다.let multiplier = 3 let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)" // message is "3 times 2.5 is 7.5"
Interpolation 효과를 없애기 위해 Extended Delimiter를 사용할 수 있다.
print(#"Write an interpolated string in Swift using \(multiplier)."#) // Prints "Write an interpolated string in Swift using \(multiplier)."
Delimiter를 사용했을 때도 기능을 사용하고자 하면 중간에 같은 개수의
#
을 삽입하면 된다.print(#"6 times 7 is \#(6 * 7)."#) // Prints "6 times 7 is 42."
Unicode
전 세계 모든 문자를 컴퓨터에서 일관성 있게 표현할 수 있게 하기 위한 국제 표준이다. Swift의 문자열과 문자 타입은 유니코드에 compliant 한다.
Unicode Scalar Values
Swift의
String
타입은 유니코드 스칼라 값으로 만들어졌다. 각 유니코드 스칼라 값은 21 bit의 숫자로 구성되어 있다. 모든 21 bit짜리 값이 문자에 배정된 것은 아니다. 몇몇 값은 미래의 assignment를 위해 남겨져 있다.문자에 배정된 값의 경우 일반적으로 이름을 가지고 있다. 예를 들면
U+0061
는 라틴어의 소문자 a를 나타내고U+1F425
는 정면의 병아리 🐥 를 나타낸다.Extended Grapheme Clusters
사람이 읽을 수 있는 하나의 문자를 만들어내는, 하나 혹은 여러 개의 유니코드 스칼라 값의 sequence를 말한다.
Character
타입의 모든 인스턴스는 하나의 Extended Grapheme Cluster를 나타낸다. 다음 예시에서 첫번째 값은 하나의 스칼라 값만 포함하고, 두번째 값은 두 개의 스칼라 값들을 포함한다.let eAcute: Character = "\u{E9}" // é let combinedEAcute: Character = "\u{65}\u{301}" // e followed by ́ // eAcute is é, combinedEAcute is é
한글 글자도 마찬가지로 하나의 스칼라 값 혹은 여러 스칼라 값들의 sequence로 만들 수 있다.
let precomposed: Character = "\u{D55C}" // 한 let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ // precomposed is 한, decomposed is 한
Counting Characters
String
안에 있는Character
값의 개수를 알고자 한다면,count
프로퍼티를 이용하면 된다.let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪" print("unusualMenagerie has \(unusualMenagerie.count) characters") // Prints "unusualMenagerie has 40 characters"
Accessing and Modifying a String
String Indices
String
에서 각Character
의 인덱스를 다루기 위한 타입으로String.Index
가 있다.Int
값은 String의 인덱스로 사용될 수 없다. 각Character
값마다 저장해야 하는 메모리의 양이 다르기 때문에,String
에 대한 iteration을 수행하려면 유니코드 스칼라 단위로 해야 하기 때문이다.var a = "ㅇㅀㄴㅁ" print(a[0]) // error: 'subscript(_:)' is unavailable: cannot subscript String with an Int
startIndex
프로퍼티는String
안의 첫번째Character
의 위치에 접근한다.let greeting = "Guten Tag!" greeting[greeting.startIndex] // G
endIndex
프로퍼티는 마지막Character
다음의 위치를 나타낸다. 따라서String
의 subscript에 유효한 argument가 아니다.greeting[greeting.endIndex] // Error
따라서 마지막 문자에 접근하고자 한다면 이전 인덱스를 반환하는
index(before:)
를 사용하면 된다.greeting[greeting.index(before: greeting.endIndex)] // !
index(after:)
는 인자로 들어간 인덱스의 바로 다음 인덱스를 반환한다.greeting[greeting.index(after: greeting.startIndex)] // u
특정 인덱스로부터 특정 거리만큼 떨어진 인덱스를 반환받고자 하면
index(_:offsetBy:)
메서드를 사용하면 된다.let index = greeting.index(greeting.startIndex, offsetBy: 7) greeting[index] // a
모든 인덱스에 순차적으로 접근하기 위해서
indices
프로퍼티를 이용할 수 있다.for index in greeting.indices { print("\(greeting[index]) ", terminator: "") } // Prints "G u t e n T a g ! "
Inserting and Removing
Character
하나를 삽입하고자 하면insert(_:at:)
를 호출하면 된다.var welcome = "hello" welcome.insert("!", at: welcome.endIndex) // welcome now equals "hello!"
다른
String
을 삽입할 때는insert(contentsOf:at:)
를 호출한다.welcome.insert(contentsOf: " there", at: welcome.index(before: welcome.endIndex)) // welcome now equals "hello there!"
Character
하나를 제거할 때는remove(at:)
를 호출한다.welcome.remove(at: welcome.index(before: welcome.endIndex)) // welcome now equals "hello there"
특정 범위를 제거하고자 하면
removeSubrange(_:)
메서드를 호출한다.let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex welcome.removeSubrange(range) // welcome now equals "hello"
Substrings
Swift에는 부분 문자열을 위한 타입이 따로 존재하는데, 바로
Substring
이다.String
값에서 subscript나prefix(_:)
등을 사용하면String
이 아닌Substring
값이 반환된다.String
에서 사용하는 대부분의 메서드를 사용할 수 있다. 둘 다StringProtocol
을 따르기 때문이다.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)
Substring
도String
처럼 문자열을 구성하는 문자들을 저장하는 공간을 가지고 있다. 다만 차이점도 있는데, 성능 최적화를 위해서Substring
인스턴스는 원래String
을 저장하는 메모리의 일부를 재사용할 수 있다는 것이다. (String
도 비슷한 최적화를 수행하지만, 메모리를 공유한다면 아예 같은 문자열인 것이다.) 이로 인하여, 문자열이나 부분 문자열 둘 중 하나를 수정하기 전까지는 메모리를 복사하는 performance cost를 지불할 필요가 없다.Substring
이String
의 메모리 일부를 공유하기 때문에,Substring
인스턴스가 사용되는 한, 원래String
인스턴스는 메모리에 보존되어야 한다. 따라서Substring
은 오랫동안 사용하기에는 부적합하다. 오래 사용하고자 하면Substring
을String
으로 변환하여 사용하는 것이 좋다.Comparing Strings
String and Character Equality
==
혹은!=
으로 일치 여부를 판단할 수 있다. extended grapheme cluster가 canonically equivalent하면 일치한다고 판단한다. 풀어서 말하자면, 언어적 의미와 appearance가 동일해야 한다는 것이다. 서로 다른 유니코드 스칼라로 구성되었더라도 해당 조건을 만족하면 된다. 예를 들면LATIN SMALL LETTER E WITH ACUTE (U+00E9)
는LATIN SMALL LETTER E (U+0065)
와COMBINING ACUTE ACCENT (U+0301)
를 합친것과 equivalent한 것이다.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") } // Prints "These two strings are considered equal"
appearance가 같다 하더라도 언어적 의미가 다른 경우도 있다. 예를 들어,
LATIN CAPITAL LETTER A (U+0041, or "A")
와 러시아어에서 사용되는CYRILLIC CAPITAL LETTER A (U+0410, or "А")
는 equivalent하지 않다. appearance는 같아도 언어적 의미가 다르기 때문이다.let latinCapitalLetterA: Character = "\u{41}" let cyrillicCapitalLetterA: Character = "\u{0410}" if latinCapitalLetterA != cyrillicCapitalLetterA { print("These two characters aren't equivalent.") } // Prints "These two characters aren't equivalent."
Prefix and Suffix Equality
hasPrefix(_:)
와hasSuffix(_:)
메서드를 호출하여String
이 특정 prefix나 suffix를 가지고 있는지 확인할 수 있다.let romeoAndJuliet = [ "Act 1 Scene 1: Verona, A public place", "Act 1 Scene 2: Capulet's mansion", "Act 1 Scene 3: A room in Capulet's mansion", "Act 1 Scene 4: A street outside Capulet's mansion", "Act 1 Scene 5: The Great Hall in Capulet's mansion", "Act 2 Scene 1: Outside Capulet's mansion", "Act 2 Scene 2: Capulet's orchard", "Act 2 Scene 3: Outside Friar Lawrence's cell", "Act 2 Scene 4: A street in Verona", "Act 2 Scene 5: Capulet's mansion", "Act 2 Scene 6: Friar Lawrence's cell" ] var act1SceneCount = 0 for scene in romeoAndJuliet { if scene.hasPrefix("Act 1 ") { act1SceneCount += 1 } } print("There are \(act1SceneCount) scenes in Act 1") // Prints "There are 5 scenes in Act 1"
Unicode Representations of Strings
유니코드 문자열이 텍스트 파일이나 다른 저장소에 쓰여질 때, 문자열 안의 유니코드 스칼라들은 여러 Unicode-defined encoding form들 중에 하나로 인코딩된다. 각 form은 문자열을 code unit이라는 작은 덩어리로 인코딩한다. UTF-8 encoding form의 경우 문자열을 8 bit의 code unit으로 인코딩하고, UTF-16의 경우 16 bit의 code unit으로 인코딩한다.
UTF-8, UTF-16, UTF-32 code unit의 컬렉션은 각각
String
의utf8
,utf16
,unicodeScalars
프로퍼티로 접근할 수 있다.UTF-8 Representation
utf8
프로퍼티의 반환 타입은String.UTF8View
이다.UInt8
값들의 컬렉션을 반환한다.for codeUnit in dogString.utf8 { print("\(codeUnit) ", terminator: "") } print("") // Prints "68 111 103 226 128 188 240 159 144 182 "
UTF-16 Representation
utf16
프로퍼티의 반환 타입은String.UTF16View
이다.UInt16
값들의 컬렉션을 반환한다.for codeUnit in dogString.utf16 { print("\(codeUnit) ", terminator: "") } print("") // Prints "68 111 103 8252 55357 56374 "
Unicode Scalar Representation
unicodeScalars
프로퍼티의 타입은UnicodeScalarView
이며,UnicodeScalar
값들의 컬렉션을 반환한다.UnicodeScalar
는 21 bit 값을 반환하는value
프로퍼티를 가지며, 반환 타입은UInt32
이다.for scalar in dogString.unicodeScalars { print("\(scalar.value) ", terminator: "") } print("") // Prints "68 111 103 8252 128054 "
Reference
https://docs.swift.org/swift-book/LanguageGuide/StringsAndCharacters.html
'iOS > Swift 공식문서' 카테고리의 다른 글
Functions (0) 2022.02.15 Control Flow (0) 2022.02.15 Collection Types (0) 2022.02.14 Basic Operators (0) 2022.02.12 The Basics (0) 2022.02.11