Swift study - Strings and Characters

rbw·2022년 2월 27일
0

swift-study

목록 보기
7/17
post-thumbnail

Swift - Strings and Characters

string은 문자들의 모음이다 예를 들어 "hello, world" or "albatross" 와 같은 것들이 있다. 스위프트의 문자열은 string 타입으로 나타낸다. 문자열과 문자(character)값의 컬렉션을 포함하여 다양한 방법으로 접근할 수 있다.

스위프트의 문자열과 문자타입은 빠르고, 유니코드를 준수하여 코드에 텍스트로 작동 가능하게끔 제공한다. 문자열을 만들고 조작하는 것은 가볍고 읽기 쉽다. C언어의 문자열과 비슷하다. (그럼 어려운거 아닌감?) 문자열의 결합은 +연산자로 간단히 두 문자열을 연결할 수 있으며, 문자열은 상수나 변수에서 골라서 관리가 가능하다. (스위프트의 다른 타입들과 같이) 또한 문자열은 보간법을 사용하여 더 긴 문자열을 상수, 변수, 리터럴, 표현식에 삽입이 가능하다 이는 화면에 보여주는것과 저장, 출력을 위한 커스텀 문자열 값을 쉽게 만들 수 있다.

단순한 구문에도 불구하고, 스위프트의 문자열은 빠르고 현대적인 문자열을 구현한다. 모든 문자열은 인코딩에 독립적인 유니코드 문자로 작성되고, 다양한 유니코드 표현의 문자들에 접근을 지원한다.

NOTE

스위프트의 문자열 타입의 토대는 NSString 클래스이다. 토대는 또한 StringNSString로 정의된 메소드를 보여주기 위해 확장한다. 이는 토대를 가져오면 String에 캐스팅 없이 NSString에 접근을 할 수 있음을 의미한다.

String Literals (문자열 리터럴)

미리 정의된 문자열에 문자열 리터럴을 포함할 수 있다. 문자열 리터럴은 ""로 둘러싸인 일련의 문자들이다.

// 문자열 리터럴로 초기화 하는 예 (상수,변수 모두 가능)
let someString = "Some string literal value"
// 스위프트는 문자열 리터럴로 초기화된 상수를 문자열로 유추한다.

Multiline String Literals (여러줄 문자열 리터럴)

만약 여러줄의 문자열 리터럴을 지정하고 싶다면, 세개의 쌍따옴표를 붙이면 된다.

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
"""

// 문장의 시작과 끝에 쌍따옴표 3개(""")를 붙여 열고 닫힘을 표시해 줘야한다.

여러줄 문자열 리터럴에서의 줄 바꿈은 값에서도 표현이 된다. 만약 이를 피하고 싶다면 끝에 \ 를 붙여주면된다.

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."
"""

// 첫 줄과 끝줄에 공백을 추가하고 싶을 때
let lineBreaks = """

This string starts with a line break.
It also ends with a line break.

"""
// 마지막 따옴표쪽에 들여쓰기를 하면 그 들여쓰기만큼 공백을 무시함
// 밑의 예는 두칸은 무시하고 그 다음 공백부터는 출력해준다.
let lineBreaks = """

  This string starts with a line break. // 공백 x
    It also ends with a line break. // 공백 2칸

  """

Special Characters in String Literals (문자열 리터럴에 특수 문자)

문자열 리터럴의 특수 문자를 포함 할 수 있다 :

  • \0 : null 문자, \\ : 백슬래쉬, \t : 수평 탭, \n : 줄 바꿈, \r : 캐리지 리턴(맨 앞으로 이동), \" : 큰 따옴표, \' 작은 따옴표
  • 임의의 유니코드 스칼라 값 : \u{n}, n은 1~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

여러줄 문자열 리터럴은 쌍따옴표 3개를 쓰기 때문에, 내부에서 이스케이프 문자 필요 없이 쌍따옴표를 포함 할 수 있다. """ 를 출력하려면 하나의 이스케이프 문자가 필요하다 밑의 예시 :

let threeDoubleQuotationMarks = """
Escaping the first quotation mark \"""
Escaping all three quotation marks \"\"\"
"""

Extended String Delimiters (확장된 문자열 구분기호)

확장된 구분기호 (#)내에 문자열 리터럴을 쓴다면 특수 문자를 따로 호출 없이 표현이 가능하다. 쌍따옴표 안에 문자열을 입력하고 #을 둘러싸서 사용이 가능하다. 예시로 #"Line 1\nLine 2"#"Line 1\nLine 2" 로 출력이 된다. 두줄로 표현 x

문자열 리터럴에서 특수 효과가 필요하다면 이스케이프 문자 다음에 오는 문자열 내의 숫자 기호 수를 일치시키면 된다. 예시로 #"Line 1\#nLine 2"# 로 적어 준다면 한 줄 띄워서 출력을 한다.

확장된 구분기호는 여러줄 문자열 리터럴에서도 사용이 가능하다. 쌍따옴표 앞에 기호로 둘러싸면 된다

let threeMoreDoubleQuotationMarks = #"""
Here are three more double quotes: """
"""#

Initializing an Empty String (빈 문자열 초기화)

긴 문자열을 만들기 위해 시작 부분에 빈 문자열을 만드려면, 빈 문자열을 변수에 할당하거나, 초기화 구문으로 새 String 인스턴스를 초기화 해주면 된다.

var emptyString = ""               // empty string literal
var anotherEmptyString = String()  // initializer syntax
// 위 두개는 같고 비어있다

// 빈 문자열을 체크하는 불린 isEmpty 프로퍼티
if emptyString.isEmpty {
    print("Nothing to see here")
}
// Prints "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"
// 컴파일 에러, 상수 문자열은 변경할 수 없다

NOTE

이 접근방식은 Objective-C와 Cocoa에서의 문자열 변형과 다르다. NSString, NSMutableString 중 선택하여 문자열 변경 여부를 나타낸다.

Strings Are Value Types (문자열은 값 타입)

스위프트의 문자열은 값 타입이다. 만약 새 문자열 값을 만든다면, 문자열 값은 함수나 메소드에 전달될 때나 변수나 상수에 할당할 때 복사된다. 각 경우에 존재하는 문자열의 새 복사본이 만들어지고, 원본이 아닌 새 복사본이 전달되거나 할당된다.

스위프트의 기본 문자열 복사 동작은 함수나 메소드에 전달될 때 어디로 부터 온지에 상관없이 정확한 문자열 값을 보장한다. 전달한 문자열은 직접 수정되지 않는한 수정 되지 않는 것을 확신 할 수 있다.

내부에서, 스위프트의 컴파일러는 꼭 필요할 때 실제로 복사가 이뤄지도록 문자열 사용을 최적화한다. 이는 항상 문자열을 값 타입으로서 사용할 때 좋은 성능을 보여준다.

Working with Characters (문자 작업)

for-in 반복문을 사용하여 문자열에 있는 문자로 개별 접근이 가능하다.

for character in "Dog!🐶" {
    print(character)
}
// D
// o
// g
// !
// 🐶

또는, Character 타입을 명시함으로써 단일 문자 문자열 리터럴에서 독립형의 문자 상수나 변수를 만들 수 있다.

let exclamationMark: Character = "!"

문자열 값은 초기화 인자에 Character 값의 배열을 전달하여 구성할 수 있다.

let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"]
let catString = String(catCharacters)
print(catString)
// Prints "Cat!🐱"

Concatenating Strings and Characters (문자열과 문자의 연결)

문자열 값은 + 연산자를 사용하여 함께 추가(연결)하여 새 문자열 값을 만들 수 있다.

let string1 = "hello"
let string2 = " there"
var welcome = string1 + string2
// welcome now equals "hello there"

// += 를 사용하는 모습
var instruction = "look over"
instruction += string2
// instruction은 "look over there"가 된다

// 문자열 타입의 append() 메소드를 사용하는 모습
let exclamationMark: Character = "!"
welcome.append(exclamationMark)
// welcome now equals "hello there!"

NOTE

문자 타입은 새로운 문자열이나 문자를 추가 할 수 없다. 왜냐하면 문자 타입은 오직 하나의 문자만 포함해야하기 때문이다.

여러줄 문자 리터럴의 경우

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 (문자열 보간법)

문자열 보간법은 문자열 리터럴 내부에 값을 포함하여 상수, 변수, 리터럴, 표현식의 혼합으로부터 새 문자열 값을 구성하는 하나의 방법이다. 문자열 보간법은 한 줄 문자열 리터럴과 여러줄 문자열 리터럴 둘 다 사용 가능하다.

// 사용 예
let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
// message is "3 times 2.5 is 7.5"

// 확장된 문자열 구분 기호를 사용하는 경우 문자열 보간에 사용할 문자를 표시 가능 하다
print(#"Write an interpolated string in Swift using \(multiplier)."#)
// Prints "Write an interpolated string in Swift using \(multiplier)."

// 보간법을 사용하려면 기호를 같이 추가해주면 된다
print(#"6 times 7 is \#(6 * 7)."#)
// Prints "6 times 7 is 42."

NOTE

문자열 보간법을 사용한 괄호안에 작성하는 표현식에는 \, \r, \n을 포함할 수 없고 나머지는 포함 가능하다.

Unicode (유니코드)

유니코드는 다양한 작성 시스템들의 텍스트를 인코딩, 표현 및 처리를 위한 국제 표준이다. 이는 모든 언어의 거의 모든 문자를 표준 형식으로 표현하고, 외부 텍스트파일이나 웹 페이지의 문자들을 읽고 쓰는게 가능하다. 스위프트의 문자열과 문자 타입은 완벽히 유니코드를 지원한다.

Unicode Scalar Values (유니코드 스칼라 값)

내부에서, 스위프트의 기본 문자열타입은 유니코드 스칼라 값으로 구성된다. 유니코드 스칼라 값은 문자 또는 수정자에 대한 특수한 21비트 숫자이다.

21비트 유니코드 스칼라 값의 전부가 문자에 할당되는 것은 아니다. 몇몇의 스칼라는 나중에 할당하거나 UTF-16인코딩을 위해 예약(보류)된다. 문자에 할당된 스칼라 값은 일반적으로 이름을 가지고 있다. (e.g LATIN SMALL LETTER A("a"))

Extended Grapheme Clusters (확장된 문자소 클러스터)

문자소 : 의미를 나타내는 최소 문자 단위

모든 스위프트 문자타입의 인스턴스는 하나의 확장된 문자소 클러스터를 나타낸다. 확장된 문자소 클러스터는 결합되었을 때 사람이 읽을 수 있는 단일 문자를 생성하는 하나 이상의 유니코드 스칼라의 연속이다.

밑의 예에서 스칼라 값의 연속으로 똑같은 값을 만들 수 있다. COMBINING ACUTE ACCENT 스칼라는 앞에 오는 스칼라에 그래픽으로 적용되어 유니코드 인식 렌더링 시스템에서 렌더링 될 때 값을 바꾼다.

let eAcute: Character = "\u{E9}"                         // é
let combinedEAcute: Character = "\u{65}\u{301}"          // e followed by ́
// eAcute is é, combinedEAcute is é

확장된 문자소 클러스터는 여러 복잡한 스크립트 문자들을 하나의 문자 값으로 나타내는 유연한 방법이다.

// 한글의 경우, 이 두 표현은 모두 단일 문자 값으로 표시 된다.
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 🇺🇸

Counting Characters (문자 카운팅)

문자열 안에 문자 수를 세는 방법은 문자열에 count 프로퍼티를 이용한다.

let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
print("unusualMenagerie has \(unusualMenagerie.count) characters")
// Prints "unusualMenagerie has 40 characters"

문자 값을 위한 스위프트의 확장된 문자열 클러스터 사용은 문자열의 연결과 변경이 항상 문자열의 문자 카운트에 영향이 없을 수 있음을 의미한다

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"

NOTE

확장된 문자소 클러스터는 여러 유니코드 스칼라들로 구성된다. 이는 다른 문자와 같은 문자의 다른 표현을 저장하기 위해 다른 양의 메모리를 요구할 수 있다는 의미이다. 이 때문에 스위프트의 문자는 각각의 문자열 표현 내에서 같은 양의 메모리를 취하지 않는다. 결과적으로, 문자열 안의 문자들의 수는 확장된 문자소 클러스터 경계를 결정하기 위해 문자열을 반복하지 않고 계산할 수 없다. 만약 특히 긴 문자열 값과 함께 작업하는경우에 count 프로퍼티는 문자열의 문자를 정하기 위해 전체 문자열의 유니코드 스칼라만큼 반복을 해야 함을 알아야 한다.


count 프로퍼티로 반환하는 문자의 수는 항상 NSStringlength 프로퍼티와 같지는 않다.(동일문자) NSString의 길이는 문자열의 UTF-16 표시 안의 16비트 코드 단위수를 토대로 하기 때문이다.

Accessing and Modifying a String (문자열의 접근과 변경)

문자열의 메소드나 속성을 통해 접근과 변경을 할수 있다.(또는 서브스크립트 구문을 사용하여)

서브스크립트(Subscript) : 콜렉션, 리스트, 시퀀스 등 집합의 특정 원소에 간단히 접근 하는 문법

String Indices (문자열 인덱스)

각각의 문자열 값은 연관된 인덱스 타입인 String.Index을 가지고 있고, 이는 문자열안의 각 문자의 위치에 해당한다.

위에 설명처럼, 다른 문자들은 저장을 위한 메모리의 양이 다르다. 그리고 문자의 위치를 지정하기 위해 문자열의 처음부터 끝까지 각각의 유니코드 스칼라를 반복해야만 한다. 이런 이유로 스위프트의 문자열은 정수값으로 인덱스를 생성 할 수 없다.

문자열의 첫 문자의 위치를 접근하기 위해 startIndex 프로퍼티를 사용해라. 마지막 위치는 endIndex 프로퍼티를 사용하면 된다 마지막 문자의 다음 위치이다. 그 결과로, endIndex는 문자열의 서브스크립트에 대한 유효하지 않은 인자이다. 만약 문자열이 비었다면, 위 두 속성의 값은 같다.

index(before:), index(after:) 라는 문자열의 메소드를 사용해서 바로 앞과 뒤 인덱스에 접근할 수 있다. 주어진 인덱스에서 더 멀리 떨어진 인덱스에 접근하려면 index(_: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

// 문자열의 범위를 넘어선 문자 또는 인덱스에 접근하려고 하면 런타임 에러가 발생
greeting[greeting.endIndex] // Error
greeting.index(after: greeting.endIndex) // Error

// indices 프로퍼티를 사용해서 개별의 모든 문자 인덱스에 접근하는 경우
for index in greeting.indices {
    print("\(greeting[index]) ", terminator: "")
}
// Prints "G u t e n   T a g ! "

NOTE

Collection 프로토콜을 준수하는 모든 유옇에서 위 메서드들을 사용 가능하다. 여기서 표시한 문자열과 Array, Dictionary, 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!"

지정된 인덱스에 있는 하나의 문자를 제거하는 경우 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"

NOTE

RangeReplaceableCollection 프로토콜을 준수하는 문자열, Array, Dictionary, Set에 적용이 가능하다.

Substrings (부분 문자열)

문자열로 부터 부분 문자열을 얻을 때 서브스크립트나 prefix(_:) 같은 메소드를 사용하면 이는 Substring의 인스턴스이다. String이 아님. 스위프트의 부분 문자열은 일반 문자열과 거의 동일한 메소드를 가지고 있고, 문자열과 동일하게 작업할 수 있음을 의미한다. 그러나 일반 문자열과 달리 문자열의 수행 동작 동안 짧은 시간 동안만 부분 문자열을 사용한다. 오랜시간 동안 결과로 저장할 준비가 될 때 부분 문자열을 일반 문자열의 인스턴스로 변환한다.

let greeting = "Hello, world!"
let index = greeting.firstIndex(of: ",") ?? greeting.endIndex
let beginning = greeting[..<index]
// beginning is "Hello"

// 오래 저장을 하기 위해 결과를 문자열로 변환
let newString = String(beginning)

문자열과 같이 각각의 부분 문자열은 부분 문자열을 구성하는 문자가 저장되는 메모리 영역을 가지고 있다. 문자열과 부분문자열의 차이는 성능 최적화에 있다. 부분문자열은 원래 문자열을 저장할 때 사용하거나 다른 부분 문자열을 저장할 때 사용한 메모리를 재사용이 가능하다. (문자열도 비슷한 최적화를 가지고 있지만 그 두 문자열은 메모리를 공유하고 둘은 같다) 이 성능 최적화는 문자열이나 부분 문자열을 수정할때까지 메모리 복사의 성능 비용을 지불할 필요가 없음을 의미한다. 위에서 언급했듯이, 부분 문자열은 장기 저장에는 적합하지 않다. 원본 문자열의 저장소를 재사용하기 때문에, 전체 원본 문자열은 부분문자열을 사용되는 한 메모리에 저장을 해야하기 때문이다.

위의 예에서 greeting 은 문자열이다. beginninggreeting의 부분 문자열이므로 greeting의 메모리를 재사용한다. 반대로 newString은 부분문자열에서 만든 문자열이므로 메모리 공간을 가지고 있다.

NOTE

StringProtocol 프로토콜을 따른다. 이는 StringProtocol 값을 문자열 조작 함수로 접근을 편리하게 함을 의미한다. 이런 함수들은 문자열과 부분 문자열에서 호출이 가능하다.

Comparing Strings (문자열의 비교)

스위프트는 텍스트 값을 비교하는 세가지 방법을 제공한다, 문자열과 문자의 동등, 접두사 동등, 접미사 동등 이 있다.

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"

두 문자열 값은 확장된 문자소 클러스터가 정규적으로 동등한경우 동등함이 고려된다. 같은 언어의 의미와 표현을 가진다면 확장된 문자소 클러스터는 정규적으로 동등하다. 심지어 내부에서 다른 유니코드 스칼라로 구성이 되어있어도 마찬가지이다.

두 확장된 문자소 클러스터는 같은 문자를 표현하므로 이는 정규적으로 동등하다고 고려한다.

// "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"

거꾸로, 표현은 같지만, 의미가 다르다면 동등하다고 판단하지 않는다.

// 미국의 A
let latinCapitalLetterA: Character = "\u{41}"

// 러시아의 A
let cyrillicCapitalLetterA: Character = "\u{0410}"

if latinCapitalLetterA != cyrillicCapitalLetterA {
    print("These two characters aren't equivalent.")
}
// Prints "These two characters aren't equivalent."

NOTE

스위프트의 문자열과 문자 비교는 로케일(locale-sensitive)을 구분하지 않는다.

locale-sensitive : 어떤 결과물을 사용자의 환경에 맞게 처리할 수 있는지 확인하는 동작, 어떤 프로그램의 메시지가 여러 언어로 주어져 있는 경우 이중에 어떤 언어의 것을 출력할지 결정하는 것, 그 수단을 로케일이라고 한다.

Prefix and Suffix Equality (접두사와 접미사의 동등)

문자열이 특정 접두사나 접미사를 가지고 있는지 체크하려면 문자열의 hasPrefix(_:), hasSuffix(_:) 메소드를 호출한다. 이는 하나의 문자열 인자를 가지며 불린 값을 반환한다.

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"
]

// "Act 1 " 접두사를 가지는지 확인
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 (문자열의 유니코드 표현)

인코딩(encoding) : 데이터를 생성시 원래 데이터 양을 줄이기 위해 코드화하고 압축하는 것

텍스트 파일이나 다른 저장소에 유니코드 문자열로 기록되었을 때, 그 문자열의 유니코드 스칼라는 여러 유니코드 정의 인코딩 형식중 하나로 인코딩 된다. 각 형식은 코드 유닛으로 알려진 작은 청크로 문자열을 인코딩 된다. 이는 UTF-8, UTF-16, UTF-32의 형식을 포함한다.

스위프트는 문자열의 유니코드 표현에 접근하는 여러 다양한 방법을 제공한다. for-in 문으로 문자열을 반복하여서 유니코드 확장된 문자소 클러스터인 각 문자 값에 접근이 가능하다.

또는, 다른 세 가지 유니코드 호환 표현 중 하나로 문자열 값에 접근한다.

  • UTF-8 코드 유닛의 모음
  • UTF-16 코드 유닛의 모음
  • 문자열 UTF-32 인코딩 형식에 해당하는 21비트 유니코드 스칼라 값 모음

UTF-8 Representation (UTF-8의 표현)

let dogString = "Dog‼🐶"의 예시를 들어서 설명하겠다.

utf8 프로퍼티를 반복하여 문자열의 UTF-8 표현으로 접근이 가능하다. 이 프로퍼티는 문자열의 UTF-8 표현에서 각 바이트에 대해 String.UTF8View 타입으로, 이는 UInt8 값의 모음이다.

for codeUnit in dogString.utf8 {
    print("\(codeUnit) ", terminator: "")
}
print("")
// Prints "68 111 103 226 128 188 240 159 144 182 "

위의 예에서, (68, 111, 103)의 10진수 코드 유닛 값은 UTF-8 표현이 ASCII 표현과 동일한 문자 D o g 를 나타낸다.

UTF-16 Representation (UTF-16의 표현)

utf16 프로퍼티를 반복하여 문자열의 UTF-16 표현으로 접근이 가능하다. 이 프로퍼티는 문자열의 UTF-16 표현에서 각 바이트에 대해 String.UTF16View 타입으로, 이는 UInt16의 모음이다.

for codeUnit in dogString.utf16 {
    print("\(codeUnit) ", terminator: "")
}
print("")
// Prints "68 111 103 8252 55357 56374 "

UTF-16 코드 단위는 UTF-8 표현과 동일한 값을 갖는다.(유니코드 스칼라는 ASCII 문자를 나타내기 때문)

!!UTF-16 하나의 코드 유닛값으로 표현이 가능하다. (8252는 203c의 10진수 표현)

강아지 얼굴은 UTF-16의 대리 쌍표현으로 나타낸다. 이 값은하나의 높은 대리 값과 낮은 대리 값으로 이루어진다.

NOTE

Surrogate characters (대리 문자) : 단일 코드 포인트를 포함하는 두 문자의 조합

높은 대리(서러게이트) : U+D800 to U+DBFF (total of 1,024 code points)

낮은 대리 : U+DC00 to U+DFFF (total of 1,024 code points)

Unicode Scalar Representation (유니코드 스칼라의 표현)

unicodeScalars 프로퍼티를 반복하여 문자열의 유니코드 스칼라 표현에 접근이 가능하다. 이 프로퍼티의 타입은 UnicodeScalarView 이고, 이는 UnicodeScalar 타입의 값의 모음이다.

각각의 UnicodeScalarUInt32 값으로 표현되느 스칼라의 21비트 값을 반환하는 value 프로퍼티를 가지고 있다.

for scalar in dogString.unicodeScalars {
    print("\(scalar.value) ", terminator: "")
}
print("")
// Prints "68 111 103 8252 128054 "

마지막 칸의 128054 값은 16진수인 1F436의 10진수 표현이다.

값 프로퍼티를 쿼리하는 대신 각 UnicodeScalar 값을 사용하여 문자열 보간법과 같이 새 문자열 값을 구성할 수 도있다.

쿼리(Query) : 데이터베이스에 정보를 요청하는것, 질문, 문의하다라는 뜻

for scalar in dogString.unicodeScalars {
    print("\(scalar) ")
}
// D
// o
// g
// ‼
// 🐶
profile
hi there 👋

0개의 댓글