iOS/swift

[Swift 공식문서 정리] - 문자열과 문자( Strings and Characters)

skyiOS 2021. 10. 21. 21:32
반응형

문자열 리터럴

문자열은 큰 따옴표 (") 로 묶어 표현한다.

let something = "Some string literal value"

여러줄 문자열 리터럴

여러줄의 문자열을 사용하고 싶은 경우 큰 따옴표 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."
"""
문자열을 붙혀 쓰고 싶은 경우 백슬래쉬( \ )를 이용 한다.

들여 쓰기

들여쓰기의 기준은 끝나는 지점의 """의 위치다. """ 위치 앞에 있는 문자들은 전부 무시되고 그 이후의 공백은 문자열에 반영된다.

특수문자

문자열 리터럴은 다음과 같은 특수 문자를 포함할 수 있다.

  • \0 (널 문자), \(백슬래시), \t(가로 탭), \n(줄바꿈), \r(캐리지 리턴), \"(큰따옴표) 및 \'(작은따옴표)
  • u{n} (n은 1-8자리 십진수 형태로 구덩된 유니코드)
let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
// "Imagination is more important than knowlege" - Einstein
let dollaSign = "\u{24}"            // $, 유니코트 U+0024
let blackHeart = "\u{2665}"         // ♥, 유니코드 U+2665
let sparklingHeart = "\u{1F496}" // 💖,유니코드 U+1F496

반응형

빈 문자열 초기화

"" 또는 String( )으로 초기화 할 수 있다.

var emtpryString = ""
var anotherEmptyString = String()
문자열이 비어있는지 확인하기 위해서는 isEmpty 프로퍼티를 사용한다.
if emptyString.isEmpty {
    print("Nothing to see here")
}
// Prints "Nothing to see here"

문자열 수정

문자열의 수정을 위해선 let 이 아닌 var로 선언되어 있어야 한다.
var variableString = "Horse"
variableString += " and carriage"
// variableString = Horse and carriage

let constantString = "Highlander"
constantString += " and another Highlander"
// 문자열 상수(let)로 선언돼 있어 에러발생!

 

Swift의 String은 값 타입(value type)이다.
그래서 String이 다른 함수 혹은 메소드로 부터 생성되면 String값이 할당 될때, 이전 String의 레퍼런스를 할당하는 것이 아니라 값을 복사해서 생성한다.
반대로 이야기 하면 다른 메소드에서 할당 받은 문자열은 그 문자열을 수정해도 원본 문자열이 변하지 않기 때문에 편하게 사용해도 된다.

문자(Character)

문자열의 개별 문자를 for in loop을 사용해 접근할 수 있다.

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

다음과 같이 문자 상수를 선언할 수 있다.

let exclamationMark: Character = "!"

문자 배열을 이용해 문자열의 초기화 메소드에 인자로 넣어 문자열을 생성할 수 있다.

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

문자열과 문자의 결합

문자( Character) 값을 문자열(String)값에 추가하고 싶을 때는 append()를 사용한다.
let string1 = "hello"
let string2 = " there"
var welcome = string1 + string2
// welcome : "hello there

var instruction = "look over"
instruction += string2
// instruction : "look over there"

let exclamationMark: Character = "!"
welcome.append(exclamationMark)
// welcome : "hello there!"

문자열 삽입

백슬래쉬 괄호를 이용해 상수, 변수, 리터럴 값을 문자열에 추가할 수 있다.

let mutiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
// message : "3 times 2.5 is 7.5"

유니코드(Unicode)

유니코드(Unicode)는 전 세계의 모든 문자를 컴퓨터에서 일관되게표현하고 다룰 수 있도록 설계된 국제 표준이다.
Swift의 문자열과 문자 타입은 유니코드에 순응(compliant)한다.

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

Swift의 네이티브 문자열 타입은 유니코드 스칼라 값으로 만들어 졌다. 유니코드 스칼라 값은 유니코드 "문자"에 배당된 숫자로, 통상 "U+" 뒤에 4~6자리 16진수로 표기하며, 하나의 유니코드는 21비트의 숫자로 구성돼 있다. (모든 21비트 유니코드 스칼라 값이 문자에 할당되는 것은 아니다. 일부 스칼라는 나중에 할당하거나 UTF-16 인코딩에서 사용하기 위해 예약되어 있다.)
U+0061는 라틴어의 소문자 a를 나타내고 U+1F425는 정면의 병아리 🐥 를 나타낸다.

자모 그룹의 확장

Swift Character유형 의 모든 인스턴스는 단일 확장 자소 클러스터를 나타낸다. 확장 자소 클러스터는 (결합 시) 사람이 읽을 수 있는 단일 문자를 생성하는 하나 이상의 유니코드 스칼라 시퀀스다.
let eAcute: Character = "\u{E9}"  // é
let combinedEAcute: Character = "\u{65}\u{301}"  // e +  ́
// eAcute : é, combinedEAcute : é

let precomposed: Character = "\u{D55C}"                        // 한
let decomposed: Character = "\u{1112}\u{u1161}\u{11AB}"    // ㅎ, ㅏ,ㄴ
// precomposed : 한, decomposed 한
  
let enclosedEAcute: Character = "\u{E9}\u{20DD}"
// enclosedEAcute : é⃝

let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
// regionalIndicatorForUS : 🇺🇸

문자 세기(Counting Vharacters)

문자열의 문자 숫자를 세기 위해서는 문자열의 count 프로퍼티를 이용한다.

  let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
  print("unusualMenagerie has \(unusualMenagerie.count) characters")
  // "unusualMenagerie의 문자는 40개"
확장된 자소 클러스터 사용 문자열 연결 및 수정이 문자열의 문자 수에 항상 영향을 미치는 것은 아니다!
var word = "cafe"
let nsStringLength1 = NSString(string: word).length

print("the number of characters in \(word) is \(word.count) and \(nsStringLength1)")
// Prints "the number of characters in cafe is 4 and 4"

word += "\u{301}"    // "café"
let nsStringLength2 = NSString(string: word).length

print("the number of characters in \(word) is \(word.count) and \(nsStringLength2)")
// Prints "the number of characters in café is 4 and 5"

문자열의 접근과 수정

문자열의 수정과 접근은 문자열 메소드 혹은 프로퍼티를 이용하거나 서브스크립트 문법을 이용해 할 수 있다.

문자열 인덱스

startIndex, endIndex, index(before:), index(after: ), index:offsetBy:) 메소드 등을 이용해 문자열에서 특정 문자에 접근할 수 있다.

위 메소드들은 Collection 프로토콜을 따르는 Array, Dictionary, Set 등에서도 동일하게 사용할 수 있다.
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

문자열의 인덱스를 벗어나는 문자를 가져오려고 하면 런타임 에러가 발생한다.

endIndex는 마치 C언어의 문자열 마지막 \0을 의미한다고 보면 된다.
즉 , 실제로 유요한 인수가 아니며, 마지막 문자의 다음 위치라고 볼 수 있다.
greeting[greeting.endIndex] // 에러!
greeting.index(after: greeting.endIndex) // 에러!

문자열의 개별 문자를 접근하기 위해서는 indices 프로퍼티를 사용한다.

for index in greeting.indices {
    print("\(greeting[index]) ", terminator: "")
// G u t e n  T a g !

문자의 삽입과 삭제

문자의 삽입과 삭제에는 insert(:at:), insert(contentsOf: at:), remove(at:), removeSubrange(:) 메소드를 사용한다.

위 메소드 들은 RangeReplaceableCollection 프로토콜을 따르는 Array, Dictionary, Set 등에서도 동일하게 사용한다.
// 삽입
var welcome = "hello"
welcome.insert("!", at: welcome.endIndex)
// welcome : hello!

welcome.insert(contentsOf: " there", at: welcome.index(before: welcome.endIndex))
// welcome : hello there!

// 삭제
welcome.remove(at: welcome.index(before: welcome.endIndex))
// welcome : hello there

let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex
welcome.removeSubrange(range)
// welcome : hello

부분 문자열

문자열에서 부분 문자를 얻기 위해 prefix(_:) 와 같은 서브스크립트 메소드를 이용할 수 있는데, 그렇게 얻은 부분 문자열은 문자열(String)인스턴스가 아니라 부분문자열(SubString)인스턴스다. 

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

// SubString인 beginning을 String으로 변환
let newString = String(beginning)
만약 부분 문자열을 단기간에 사용하는게 아니라 오랜기간 사용한다면 문자열 인스턴스로 바꿔서 사용하는게 좋다.

그 이유는 메모리 관리 때문이다.
SubString은 해당 문자를 직접 갖고 있는 것이 아니라 원본 String의 메모리를 참조해 사용한다.(성능 최적화로서 하위 문자열은 원래 문자열을 저장하는 데 사용된 메모리의 일부, 또는 다른 하위 문자열을 저장하는데 사용된 메모리의 일부를 재사용 한다.)
 SubString을 계속 이용하는 이상 원본 String이 계속 메모리에 남아 있게 된다(사용하지 않는 문자열도 남아있다).
그렇게 때문에 SubString을 오래 사용하고자 한다면 위 예제처럼 String에서 인스턴스로 만들어 사용하고자 하는 문자만 메모리에 올려놓고 사용하는 것이 관리 효율면에서 좋다고 할 수 있다.

문자열과 문자 비교

문자열과 문자 비교에는 == 혹은 != 연산자를 사용합니다.

let quotation = "We're a lot alike, you and I."
let sameQuotation = "We're a lost alike, you and I."
if quotation == sameQuotation {
    print("These two strings are considered equal")
}
// 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")
}
// These two strings are considered equal 출력

같은 유니코드 문자여도 유니코드가 다르면 다른 문자로 판별합니다. 아래 예제는 영어의 알파벳 대문자 A(U+0041)와 러시아어에서 사용되는 대문자 A(U+0410)를 비교한 것입니다.

let latinCapitalLetterA: Character = "\u{41}"

let cyrillicCapitalLetterA: Character = "\u{0410}"

if latinCapitalLetterA != cyrillicCapitalLetterA {
    print("These two characters are not equivalent.")
}
// Prints "These two characters are not equivalent."
Swift에서 문자열과 문자의 비교는 언어를 고려하지 않는다. 언어와 상관없이 같은 문자면 같은 문자로 취급한다.

접두사 접미사 비교

접두사와 접미사의 비교를 위해 hasPrefix(:), hasSuffix( : ) 메소드를 사용한다.
둘 다 문자열 타입의 단일 인수를 사용하며, Bool값을 반환한다.

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 remeoAndJuliet {
    if scene.hasPrefix("Act 1 ") {
        act1SceneCount += 1
    }
}
print("There are \(act1SceneCount) scenes in Act 1")
// There are 5 scenes in Act 1

문자열의 유니코드 표현

유니코드 문자가 텍스트 파일이나 다른 저장소에 쓰여질 때 유니코드 스칼라는 UTF-8, UTF-16,UTF-32 등 다양한 유니코드 인코딩 방식이 사용된다.

let dogString = "Dog!!🐶"

UTF-8 표현

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

UTF-16 표현

 

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

유니코드 스칼라 표현

 

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

 

 

 

 

 

반응형