Search

[Swift 공식 문서] 3. Strings and Characters

부제
카테고리
Swift
세부 카테고리
공식문서 번역
Combine 카테고리
최종편집일
2022/11/29 04:28
작성중
관련된 포스팅
생성 일시
2022/07/16 14:47
태그

요약

여러줄짜리 String “”” ””” 큰따옴표 3개 사용
\ 사용해서 특수문자 사용 예 : 줄바꿈 - \n
String 각 문자 순회 가능
# 사용하면 String interpolation 비활성화 가능

Substring

.prefix(_:) : Substring 타입의 객체를 리턴하는 메서드
hasPrefix(_:) : 문자열의 앞부분이 주어진 문자열과 같은지 검사
hasSuffix(_:) : 문자열의 뒷부분이 같은지 검사
문자열은 문자들의 조합이다. Swfit 에서 문자열은 String 타입으로 사용이 가능하다. String 의 원소들은 다양한 방식으로 접근이 가능하다. ( Character value)
Swift 의 String 과 Character 타입은 빠르고, Unicode 의존적인 텍스트를 작성할 수 있도록 도와준다. 모든 String 은 Unicode 문자로 인코딩할 필요가 없도록 구성되었고, Unicode 로의 다양한 표현을 할 수 있도록 도와줍니다.
Swift 의 String 타입은 Foundation 모듈의 NSString class 와 호환된다, Foundation 은 또한 StringNSString 의 메서드를 사용할 수 있도록 확장하였다. 만약 Foundation 모듈을 import 한다면 , NSString 메서드를 String 에 캐스팅없이 사용이 가능하다.

String Literals

미리 정의된 String 값을 string literal 로 사용할 수 있다. String literal 은 큰따옴표로 둘러쌓인 문자들의 조합이다.
let someString = "Some string literal value"
Swift
복사
string 리터럴로 초기화 되었기 때문에 상수 someString 은 String 타입으로 추론된다.

Mulitiline String Literals

1.
만약 여러줄의 String 이 필요할 때
2.
문자열안에 큰따옴표를 사용해야할때.
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." """
Swift
복사
큰따옴표 3개로 둘러싸면 사용이 가능하다.
let singleLineString = "These are the same." let multilineString = """ These are the same. """
Swift
복사
코드에 줄바꿈을 넣지 않으면서 출력시 줄바꿈을 표현하고자 한다면 back slash 를 사용하자
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." """
Swift
복사
코드의 가독성을 위해 위아래에 공백을 넣어주자.
let lineBreaks = """ This string starts with a line break. It also ends with a line break. """
Swift
복사
들여쓰기또한 가능하다
이때 마지막 큰따옴표 3개가 들여쓰기 된 만큼 다른 문자열들의 들여쓰기를 무시하게된다.

Special Characters in String Literals

\0 (null character)
 \\ (backslash),
 \t (horizontal tab),
 \n (line feed),
 \r (carriage return),
 \" 큰따옴표
 \' 작은 따옴표
특수문자는 위와같이 backslash 와 함께 표현한다.
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
Swift
복사
\u{unicode} : 유니코드의 스칼라 값을 이용가능하다.
""" 을 사용하면 백슬래시 없이 따옴표를 표현할 수 있다.
let threeDoubleQuotationMarks = """ Escaping the first quotation mark \""" Escaping all three quotation marks \"\"\" """
Swift
복사
다만 """ 안에서 """ 을 사용하고자 한다면, 하나의 큰따옴표 만이라도 백슬래시 를 이용해 escape 해주면 된다.

Extended String Delimeters

특수문자를 많이 사용해야할 때는 escape 를 위해 백슬래시를 너무 자주 사용해주어야 한다.
그럴 때 대신 # 을 사용하자.
단, 줄바꿈없이 한줄에 표현된다.
만약 # 을 사용하면서 줄바꿈도 하고싶다면
print(#"Line 1\nLine 2"#) // Line 1\nLine 2 print(#"Line 1\#nLine 2"#) //Line 1 //Line 2
Swift
복사
""" 와 동시에 사용도 가능하다.
let threeMoreDoubleQuotationMarks = #""" Here are three more double quotes: """ """#
Swift
복사
백슬래시가 필요 없다.

Initializing an Empty String

String 값으로 초기화 하고싶다면 아래를 이용하자
var emptyString = "" // empty string literal var anotherEmptyString = String() // initializer syntax // these two strings are both empty, and are equivalent to each other
Swift
복사
위의 두 코드는 서로 같은 결과를 만든다.
if emptyString.isEmpty { print("Nothing to see here") } // Prints "Nothing to see here"
Swift
복사
.isEmpty 프로퍼티를 이용하여서 String 타입에 빈 문자열이 들어있는지 확인할 수 있다.
위 접근 방식은 Objective C 와 cocoa 의 string mutation 과는 접근 방식이 다르다. Ojective-C 와 cocoa 는 NSString NSMutableString 두 클래스 중 하나를 선택하여, String 이 변경가능한 타입인지를 명시한다.

Strings Are Value type

Swfit 의 Stringvalue type 이다.
String 을 복사하여 복사본을 변경해도 원본은 변경되지 않는다.
따라서 복사본의 변경에 따른 원본의 수정을 우려하지 않아도 된다.
내부적으로는 복사본의 생성시 원본의 주소만을 참조해서 불필요한 메모리 낭비를 줄인다. 복사본이 변경되려할 때, 실제 복사를 수행한다.

Working with Characters

String 을 각각의 문자에 대해서 순회시킬 수 있다.
for character in "Dog!🐶" { print(character) } // D // o // g // ! // 🐶
Swift
복사
Character type annotation 을 활용해서 단일문자만을 담을 수 있는 변수를 선언할 수 있다.
let exclamationMark: Character = "!"
Swift
복사
CharacterArrayString 데이터를 생성할 수 있다.
let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"] let catString = String(catCharacters) print(catString) // Prints "Cat!🐱"
Swift
복사

Concatenating Strings and Characters

String 은 덧셈연산자를 통해 하나의 string 으로 합쳐질 수 있습니다.
let string1 = "hello" let string2 = " there" var welcome = string1 + string2 // welcome now equals "hello there"
Swift
복사
가산 연산자도 사용이 가능합니다.
var instruction = "look over" instruction += string2 // instruction now equals "look over there"
Swift
복사
Character 값을 String 변수에 append() 메서드를 활용하여 추가할 수 있습니다.
let exclamationMark: Character = "!" welcome.append(exclamationMark) // welcome now equals "hello there!"
Swift
복사
Character 값에는 append() 사용이 불가능합니다.
multiline String 리터럴을 사용해서 긴 문자열을 생성할 때, 덧셈연산자를 활용하면 서 더하려는 두 문자열 사이에 줄바꿈을 표현하려면 마지막 줄에 line break 를 추가하시면 됩니다.
let badStart = """ one two """ let end = """ three """ print(badStart + end) // Prints two lines: // one // twothree two 와 three 사이에 줄바꿈을 표현하고 싶다면, let goodStart = """ one two """ print(goodStart + end) // Prints three lines: // one // two // three
Swift
복사

String interpolation

String interpolation 을 활용해서 String 리터럴 안에 constant, variable, literal, expression 등의 요소들을 삽입할 수 있습니다.
\() 을 리터럴 내부에 작성하여 사용
let multiplier = 3 let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)" // message is "3 times 2.5 is 7.5"
Swift
복사
새 String 이 생성되면서, String literal 내부의 placeholder 는 실제 값으로 대체 됩니다. 위와 같이, 이 placeholder 에는 상수 변수 뿐만이 아니라 표현식 또한 포함될 수 있습니다.
마찬가지로 새 String 이 생성되면서 placeholder 내부의 표현식의 결과가 실제 String 값으로 대체됩니다.
#(delimiter)을 이용해서 String interpolation 기능을 사용하지 않을 수 있습니다.
print(#"Write an interpolated string in Swift using \(multiplier)."#) // Prints "Write an interpolated string in Swift using \(multiplier)."
Swift
복사
반대로 delimeter 을 사용하면서 String interpolation 을 사용할 수 도 있습니다.
print(#"6 times 7 is \#(6 * 7)."#) // Prints "6 times 7 is 42."
Swift
복사
괄호안에 작성가능한 표현식에는 다른 String literal 들이 포함될 수 있으나, backslash \ 를 사용할 수 없습니다.

Unicode

유니코드는 서로 다른 writing system 내부에서 text 를 다루는데 사용되는 국제 표준입니다. 유니코드를 사용하면 거의 모든 언어의 문자를 ㅛㅍ준화된 형태로 나타낼 수 있고, 텍스트 파일이나 웹페이지 같은 외부 source 에서의 문자를 읽고 쓸 수 있습니다. Swift 의 String, Character 타입은 완벽하게 유니코드를 준수합니다.

Unicode Scalar Values

내부적으로 Swift 의 String 타입은 Unicode scalar values 로 부터 만들어졌습니다. Unicode scalar value 는 각 문자에 대응 되는 유일한 21비트 숫자입니다.
몇몇 21 bit saclar value 들은 예약된 문자에 할당 되어 있습니다. 나머지는 UTF - 16 인코딩에 사용하기위해, 또 가까운 미래에 새로운 문자를 할당하기 위해 보존되어 있습니다.
예: U+0061 for LATIN SMALL LETTER A ("a"), or U+1F425 for FRONT-FACING BABY CHICK ("").

Extended Grapheme Clusters

Grapheme Clusters 란 화면에 나타나는 문자의 단위를 의미합니다. 모든 Swift 의 Character 타입은 하나의 extended Grapheme Cluster 를 나타냅니다. extended Grapheme Cluster 는 여러개의 유니코드 scalar 들의 연속이며, 이러한 연속이 사람이 읽을 수 있는 하나의 문자를 만들어냅니다.
extended Grapheme Cluster 을 활용하면 유연하게 복잡한 문자들로 하나의 character 값을 표현할 수 있습니다.
예를 들어 한글도 이런식으로 하나의 유니코드로 한 을 표현할 수 있을 뿐만아니라 여러개의 문자의 조합 ㅎ,ㅏ,ㄴ 의 조합으로 하나의 Character를 표현할 수 있습니다.
let precomposed: Character = "\u{D55C}" // 한 let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ
Swift
복사

Counting Characters

count 프로퍼티를 이용해 String 데이터의 길이를 확인할 때, count 프로퍼티는 Grapheme Cluster 를 기준으로 데이터의 갯수를 counting 합니다.
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"
Swift
복사
위 코드 처럼 하나의 유니코드를 추가하여도 count 값에는 변화가 없을 수도 있습니다.
Extended grapheme clusters 는 여러개의 유니코드 scalar 로 구성될 수 있습니다. 이 말은 즉슨 같은 문자라도 다른양의 메모리 공간을 필요로 할 수 있다는 뜻이기도 합니다. String 내부의 문자의 개수는 반드시 String 전체를 순회하며, 각각의 grapheme cluster 영역을 확인하지 않고는 셀 수 없습니다. 따라서 count 프로퍼티를 긴 문자열에 사용할 때에는 모든 문자를 순회해야 한다는 사실을 주의하세요.
count 프로퍼티를 긴 문자열에 사용할 때에는 모든 문자를 순회해야 한다. 선형 시간복잡도를 가지게 됩니다.
count 프로퍼티에 의해서 리턴되는 문자의 개수는 NSString 의 length 프로퍼티의 리턴값과 항상 같지는 않습니다. length 프로퍼티는 자소단위의 개수를 세는 것이 아닌 16 비트 유니코드의 갯수를 셉니다.

Accessing and Modifying a String

인덱싱

이러한 이유로 String 타입은 정수형 인덱스가 없다!!
대신 인덱스 객체를 사용한다.
인덱스를 이용한 접근은 String의 프로퍼티 중 하나인 String.Index를 이용해 접근이 가능합니다.
startIndex : 문자열의 맨 처음 문자의 위치를 가리키는 String.Index 객체를 리턴
endIndex : 문자열의 마지막 문자의 다음위치를 가리키는 String.Index 객체를 리턴
greeting[greeting.endIndex] // Error greeting.index(after: greeting.endIndex) // Error
Swift
복사
.index() : 주어진 인덱스로 부터 특정 위치만큼 떨어져있는 인덱스(String.Index)를 리턴
.index(after: ) : 주어진 인덱스의 앞 인덱스 리턴
.index(before: ) : 주어진 인덱스의 뒤 인덱스 리턴
.index(_:offsetBy:) : 주어진 인덱스로 부터 offsetBy 만큼 떨어진 위치의 인덱스 리턴
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
Swift
복사
.indices : 모든 인덱스에 대한 순회 가능한 컬렉션 객체 리턴
for index in greeting.indices { print("\(greeting[index]) ", terminator: "") } // Prints "G u t e n T a g ! "
Swift
복사
위 메서드와 프로퍼티들은 Collection 프로토콜을 준수하는 모든 타입에 대해 사용이 가능합니다. String 뿐만아니라, Array, Dcitionary, Set 도 마찬가지입니다.

Inserting and Removing

.insert(_: at:) : 특정 인덱스에 하나의 문자를 삽입
.insert(contentsOf:at:) : 특정 인덱스에 문자열 삽입.
var welcome = "hello" welcome.insert("!", at: welcome.endIndex) // welcome now equals "hello!" welcome.insert(contentsOf: " there", at: welcome.index(before: welcome.endIndex)) // welcome now equals "hello there!"
Swift
복사
.remove(at:) : 특정 인덱스의 문자 제거
.removeSubrange(_:) : 특정 범위의 문자열 제거
welcome.remove(at: welcome.index(before: welcome.endIndex)) // welcome now equals "hello there" let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex welcome.removeSubrange(range) // welcome now equals "hello"
Swift
복사
위 메서드와 프로퍼티들은 RangeReplaceableCollection 프로토콜을 준수하는 모든 타입에 사용이 가능합니다. String 뿐만아니라, Array, Dcitionary, Set 도 마찬가지입니다.

Substrings

.prefix(_:) : 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)
Swift
복사
첫 복사 이후 둘은 같은 메모리 공간을 가리킨다.
Substring 만을 가지고 오랫동안 작업해야할 경우 SubString 을 사용하는 동안 String 도 메모리 공간에 그대로 유지되게 된다.
따라서 이는 불필요한 메모리를 점유하는 것으로 볼 수 있으므로 SubString 값을 오래 사용해야 한다면Substring 값을 String 타입으로 변경해주자.
둘 중하나가 변경되면 이때 실제적인 메모리공간의 복사가 일어난다.
따라서 substring 값을 오랫동안 사용하고자 한다면 String 객체로 변경해주자.
Substring 타입과 String 타입 모두 StringProtocol 프로토콜을 준수한다. 따라서 문자열 조작과 관련된 많은 편리한 함수 사용이 Substring 에도 가능하다.

Comparing Strings

Swift 에는 텍스트를 비교하는 방법이 세가지가 존재한다.
string and character equality,
prefix equality, and
suffix equality.

String and Character equality

String and Character 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") } // Prints "These two strings are considered equal"
Swift
복사
두 String 값 또는 Character 값은 두 텍스트의 자소 단위가 모두 같다면 같은것으로 여겨진다. 내부적으로는 서로 다른 유니코드에 의해서 구성되어 있다고 하더라도, 둘이 같은 언어적 뜻과 모양을 가진다면 자소단위 는 동등하다.
예를들어
// "Voulez-vous un café?" using LATIN SMALL LETTER E WITH ACUTE let eAcuteQuestion = "Voulez-vous un caf\u{E9}?" // "Voulez-vous un café?" using LATIN SMALL LETTER E and COMBINING ACUTE ACCENT let combinedEAcuteQuestion = "Voulez-vous un caf\u{65}\u{301}?" if eAcuteQuestion == combinedEAcuteQuestion { print("These two strings are considered equal") } // Prints "These two strings are considered equal"
Swift
복사
두 String 은 다른 유니코드 스칼라 값을 가지지만 자소단위로서 그 둘의 의미와 모양이 같기 때문에 두 String 은 동등하다고 판단된다.
반대로,
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."
Swift
복사
영어의 LATIN CAPITAL LETTER A (U+0041, or "A") 와 러시아어의 CYRILLIC CAPITAL LETTER A (U+0410, or "А") 는 외적으로는 모양이 같으나 서로 다른 의미를 가지기 때문에 서로 다른 문자로 판단된다.

Prefix and Suffix Equality

String 이 특정 문자열 Prefix 또는 Suffix 를 갖는지 체크하는방법은 아래의 메서드들을 사용하는 것입니다.
hasPrefix(_:) : 문자열의 앞부분이 주어진 문자열과 같은지 검사 Bool 타입 리턴
hasSuffix(_:) : 문자열의 뒷부분 겁사Bool 타입 리턴
위 두 메서드도 String and Character equality 와 동일하게 자소단위로 문자를 비교합니다.
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" var mansionCount = 0 var cellCount = 0 for scene in romeoAndJuliet { if scene.hasSuffix("Capulet's mansion") { mansionCount += 1 } else if scene.hasSuffix("Friar Lawrence's cell") { cellCount += 1 } } print("\(mansionCount) mansion scenes; \(cellCount) cell scenes") // Prints "6 mansion scenes; 2 cell scenes"
Swift
복사

Unicode Representations of String

유니코드 문자열이 텍스트 파일이나 다른 저장소에 저장될 때 문자열의 유니코드 스칼라 값은 여러 가지 Unicode-defined encoding forms에 의해 인코딩 된다. 여기엔 UTF-8(8비트로 인코딩), UTF-16(16비트로 인코딩), UTF-32(32비트로 인코딩)가 있다.
Swift는 문자열의 유니코드 표현을 하는 방법으로 여러 가지를 제공한다.
세 가지의 유니코드 표현 방식으로 String 값에 접근할 수 있다.(UTF-8, UTF-16, UTF-32)

UTF-8 Representation

utf8 property 를 활용해서 문자열의 UTF-8 표현에 접근할 수 있다. UTF8View 타입의 컬렉션을 리턴하며 각각의 값은 16 비트 code unit 을 나타낸다.
for codeUnit in dogString.utf8 { print("\(codeUnit) ", terminator: "") } print("") // Prints "68 111 103 226 128 188 240 159 144 182 "
Swift
복사
예시와 같이 첫번째 3개의 십진수 codeUnit 값은 문자 D,o,g 를 나타낸다. 그다음 3개의 Code Unit (226, 128, 188) 은 3 byte 크기의 !! DOUBLE EXCLAMATION MARK UTF-8 표현이다. 마지막 네개의 codeUnit 값은 DOG FACE character의 4 byte 크기 UTF-8 표현이다.

UTF-16 Representation

utf16 property 를 활용해서 문자열의 UTF-16 표현에 접근할 수 있다. UTF16View 타입의 컬렉션을 리턴하며 각각의 값은 16 비트 code unit 을 나타낸다.
for codeUnit in dogString.utf16 { print("\(codeUnit) ", terminator: "") } print("") // Prints "68 111 103 8252 55357 56374 "
Swift
복사
(68111103) 첫번째 3 code Unit 은 앞의 D , o , g 세글자를 나타내며 이값은 UTF- 8 표현과 같은 값이다. ( 이 유니코드 스칼라값들이 아스키 문자를 표현하기 때문에)
네번째 codeunit 값인 8252 는 DOUBLE EXCLAMATION MARK 를 나타내는 값으로 16진수의 203C 와 동일한 값이다. 그리고 이 값은 U+203C 유니코드 스칼라 값과 같은 값이다. 이 문자는 하나의 UFT-16 code unit 으로 표현이 가능하다.
5,6번째 codeUnit 값은 55357 56374 는 UTF-16값으로 55357, 56374로 표현된다.

Unicode Scalar Representation

unicodeScalars 프로퍼티를 이용해서 문자열을 유니코드 스칼라 값으로 표현할 수 있다.
UInt32 타입의 스칼라 값을 리턴한다.
for scalar in dogString.unicodeScalars { print("\(scalar.value) ", terminator: "") } print("") // Prints "68 111 103 8252 128054 "
Swift
복사
UnicodeScalar 타입의 값들에 대해서 value 프로퍼티를 사용할 수 있고 이 프로퍼티는 유니코드 스칼라 값에 대응되는 String 을 리턴한다.
for scalar in dogString.unicodeScalars { print("\(scalar) ") } // D // o // g // ‼ // 🐶
Swift
복사
이를 이용해 유니코드 스칼라 값을 이용해 다시 문자열을 표현할 수 있다.