swift의 String은 Foundation의 NSString과 연결되어 있기 때문에, Foundation을 import하면 NSString의 함수를 String에도 쓸 수 있다.
let str = """
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 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."
"""
\n 같은 명령어로 문자열에 특수효과(?)를 집어넣은 문자열을 #로 감싸서 다 무력화해버릴 수 있다.
let str = #"""
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 str = #"""
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 str1 = ""
let str2 = String()
//str1, str2 모두 빈 문자열이 됨.
if str2.isEmpty{
//str2가 빈 문자열인지 체크할 수 있음
}
타입에는 두 가지가 존재하는데, Value type과 Reference type, 요 두 가지가 있다!
쉽게 말해 value type은 값이 변경되지 않고 복사되어 참조되는 것, reference type은 값이 복사되어 참조되는 것이 아니라 그 자체가 참조되는 것이다.
그니까 value type은 원본이 변경되지 않고, reference type은 원본이 변경되는 거라고 생각하면 편할듯.
새로운 String을 만들면, 이 값은 함수나 메소드에 전달되거나 변수/상수에 assign될 때 복사되어 전달된다.
Swift의 copy-by-default String성질은 함수나 메소드가 문자열을 넘겨줄 때, 이 문자열의 원본은 변경되지 않기 때문에 편하게 사용할 수 있도록 해 준다.
Value type과 Reference type은 다음에 더 자세히 다뤄보도록 합시당.
문자열이 몇 개의 문자로 이뤄졌는지 확인하려면, count 속성을 사용하면 된다.
let str = "This is test string."
print(str.count)
//20
Swift의 문자는 각각 다른 양의 메모리를 먹기 때문에, 문자열에서 정수값의 인덱스로 문자를 나타낼 수가 없다. 그래서 다음과 같은 문법을 사용할 수밖에 없음.
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, 해당 인덱스에서 offsetBy만큼 떨어진 인덱스
//존재하지 않는 인덱스에 대한 접근은 런타임 에러 발생
greeting[greeting.endIndex] // Error
greeting.index(after: greeting.endIndex) // Error
//indices 속성으로 문자열의 모든 인덱스에 접근할 수 있다.
for index in greeting.indices {
print("\(greeting[index]) ", terminator: "")
}
// "G u t e n T a g ! " 출력됨
문자열에 문자 하나 또는 문자열을 삽입하는 것은 다음과 같이 할 수 있다.
// 문자 하나 삽입하기, insert(_: at:) 사용
var welcome = "hello"
welcome.insert("!", at: welcome.endIndex)
// welcome now equals "hello!"
// 문자열 삽입하기, insert(contentsOf: at:) 사용
welcome.insert(contentsOf: " there", at: welcome.index(before: welcome.endIndex))
// welcome now equals "hello there!"
문자열에서 문자 하나 또는 문자열을 제거하는 것은 다음과 같이 할 수 있음.
// 문자 하나 제거하기, 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"
insert(_: at:), insert(contentsOf: at:), remove(at:), removeSubrange(_:)는 RangeReplaceableCollection 프로토콜을 따르는 모든 타입에 적용될 수 있다. 따라서 Array, Dictionary, Set에 적용될 수 있다.
문자열에서 prefix( _: ) 같은 함수를 써서 얻은 substring의 경우에는 Substring 인스턴스가 만들어진다. 또다른 String이 만들어지는 게 아님.
이 Substring의 경우에는 String에 쓸 수 있는 걸 거의 다 쓸 수 있지만, 이걸 긴 시간 동안 쓸 수가 없다는 차이점이 있다.
긴 시간동안 쓰고 싶다면 String 인스턴스로 변환해 줘야 한다.
이 Substring도 String처럼 메모리공간을 점유하고 있는데, 차이점은 이놈은 기존의 문자열이나 다른 Substring 문자열의 메모리 일부분을 참조해 재사용한다는 것이다.
그래서 이 Substring을 사용하려면 원본 String도 메모리에 계속 존재해야 하는데, 만약 이 원본 문자열을 사용하지 않아도 이 Substring때문에 남아 있어야 하는 일이 생긴다. 메모리가 낭비돼버림!
그래서 이 Substring을 오래 쓰고 싶으면 String 인스턴스로 만들어서 사용하고자 하는 문자만 메모리에 올려놓고 쓰는 것이 좋다.
let greeting = "Hello, world!"
let index = greeting.firstIndex(of: ",") ?? greeting.endIndex
let beginning = greeting[..<index]
// beginning is "Hello"
// 긴 시간동안 사용하기 위해 String으로 변환해줌
let newString = String(beginning)
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"
]
//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"
//Capulet's mansion의 접미사와 Friar Lawrence's cell의 접미사를 가진 문자열의 갯수를 세려고 함
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"