Swift/Swift 공식 문서

[Swift] 문자열과 문자 (Strings and Characters)

hyunjuntyler 2023. 5. 18. 19:36

Swift 에서는 텍스트를 어떻게 저장하고 다루는지 알아보자. String 은 "hello, world" 나 "albatross" 같은 문자의 연속이다. 

Note : Swift의 String 타입은 Foundation 의 NSString 클래스와 연결되어 있다.

문자열 (String Literals)

상수 또는 변수의 초기값으로 문자열을 사용할 수 있다. 문자열은 쌍따옴표 ( " ) 로 둘러싸인 문자의 연속이다.

let someString = "Some string literal value"

Swift 에서는 자동으로 someString 상수를 String 타입으로 추론한다.

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

여러 줄의 문자열이 필요하면 3개의 큰따옴표를 사용해 주면 된다.

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

아래와 같이 주변 코드와 일치하도록 들여쓰기도 가능하다. 닫는 따옴표 ( """ ) 를 기준으로 그 앞의 공백은 무시되는 공백이고, 뒤의 공백은 추가되는 공백이다.

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

문자열은 아래와 같은 특수 문자를 포함할 수 있다.

  • 이스케이프 된 문자 \0 (null character), \\ (backslash), \t (horizontal tab), \n (line feed), \r (carriage return), \" (double quotation mark), \' (single qutation mark)
  • \\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

위와 같이 사용할 수 있다.

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

문자열에 특수문자를 포함하고 싶다면 문자열을 따옴표 ( " ) 로 둘러싸고 숫자기호 ( # ) 으로 둘러싸면 된다. 예를들면 #"Line 1\nLine 2"# 를 입력하게 되면 그대로 출력된다. \n 으로 인해 줄바꿈이 되지 않는다.

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

긴 문자열을 만들기 위한 시작점으로 빈 String 값을 만드려면 아래와 같다. 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")
}
// Prints "Nothing to see here"

문자열 변경 (String Mutability)

아래 예시와 같이 변수 ( var ) 로 선언된 문자열은 변경이 가능하다.

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

문자 작업 (Working with Characters)

for - in 루프로 String 각각의 Character 값에 접근할 수 있다.

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

하나의 문자 Character 타입을 사용하여 단독의 Character 상수 또는 변수를 생성할 수 있다.

let exclamationMark: Character = "!"

또한 이런 Character 값의 배열을 모아 String 값을 만들 수 있다.

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

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

String 값은 다양한 연산자를 추가, 연결 하여 새로운 String 값을 생성 할 수 있다.

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

마지막 예시와 같이 append() 메서드를 이용하여 String 변수에 Character 값을 추가 할 수 있다.

문자열 삽입 (String Interpolation)

문자열인 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"

문자 카운팅 (Counting Characters)

문자열에서 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인덱스 타입 (index type) 을 가지고 있다. 아래와 같이 표현이 가능하다.

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 에서 문자열은 정수값으로 인덱스를 생성할 수 없다. 또한 마지막 글자를 확인하려면 index(before: swift.endIndex) 를 사용해주어야 한다.

indices 프로퍼티를 사용하여 문자열에 있는 개별문자의 모든 인덱스에 접근 가능하다.

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

삽입과 삭제 (Inserting and Removing)

문자열의 특정 위치에 문자를 삽입하려면 아래와 같은 코드를 사용하면 된다.

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

특정 인덱스의 문자를 삭제하려면 아래와 같은 방법을 사용한다.

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"

부분 문자열 (Substrings)

문자열에서 부분문자열을 얻게 된다면 그 결과로 얻는 인스턴스는 String 이 아닌 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)

SubString 은 가져온 String 과 같은 저장소를 쓴다. 그리고 새로운 문자열인 newString 을 선언했을때 따로 저장소가 생기는 것이다.

문자열 비교 (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"

접두사와 접미사 동등성 (Prefix and Suffix 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"
]

hasPrefix(_:) 메서드나 hasSuffix(_:) 메서드를 사용하여 접두사와 접미사를 확인 할 수 있다.

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"