var someString: String = "Some Swift😃"
// 문자열은 결국, 각 문자를 모아놓은 데이터 바구니
for code in someString.unicodeScalars {
print(code.value)
}
/**=====================================
- 문자열 UTF-32값 (16진법 표현)
- "S" - 83 ====> 53 (16진법)
- "o" - 111 ====> 6F (16진법)
- "m" - 109 ====> 6D (16진법)
- "e" - 101 ====> 65 (16진법)
- " " - 32 ====> 20 (16진법)
- "S" - 83 ====> 53 (16진법)
- "w" - 119 ====> 77 (16진법)
- "i" - 105 ====> 69 (16진법)
- "f" - 102 ====> 66 (16진법)
- "t" - 116 ====> 74 (16진법)
- "😃" -128515 ====> 1F603 (16진법)
let dogString = "Dog‼🐶"
print(dogString.utf8)
for codeUnit in dogString.utf8 { // 8비트의 숫자값
print("\(codeUnit) ", terminator: "")
}
print("")
// 68 / 111 / 103 / 226 128 188 / 240 159 144 182
for codeUnit in dogString.utf16 { // 16비트의 숫자값
print("\(codeUnit) ", terminator: "")
}
print("")
// 68 / 111 / 103 / 8252 / 55357 56374
for scalar in dogString.unicodeScalars { // 32비트의 숫자값
print("\(scalar.value) ", terminator: "")
}
print("")
// 68 / 111 / 103 / 8252 / 128054
var hangul1 = "\u{D55C}" // "한"
print("\"한\"의 글자수: ", hangul1.count)
var hangul2 = "\u{1112}\u{1161}\u{11AB}" // "ㅎ" "ㅏ" "ㄴ"
print("\"ㅎ\"+\"ㅏ\"+\"ㄴ\"의 글자수: ", hangul2.count)
hangul1 == hangul2
// 한글과 같은 언어들을 "ㅎ" "ㅏ" "ㄴ" 내부적으로 하나의 글자로 취급 ⭐️
var word = "cafe"
print("글자의 숫자 \(word) is \(word.count)")
// "글자의 숫자 cafe is 4"
word += "\u{301}" // COMBINING ACUTE ACCENT, U+0301
print("글자의 숫자 \(word) is \(word.count)")
// "글자의 숫자 café is 4"
) NSString ▶︎ Foundation String 클래스/참조형식 (파운데이션 문자열)
==================================================================**/
var nsString: NSString = "Swift" // 문제없이 저장
//let string: String = nsString //에러발생
let string: String = nsString as String
// String <===> NSString간에 자동으로 변환컨버팅되지는 않음(타입캐스팅해야함)
nsString.length // NSString의 length속성 ===> 유니코드수(UTF-16) 기반
string.count // String의 count속성 ===> 의미 글자수 기반
nsString = string as NSString // 두형식은 브릿징이 가능한 타입 (Toll-Free Bidged) ===> 타입캐스팅으로 호환되는 자료형
// 두 자료형은 서로 호환되는 자료형이지만, 유니코드를 처리하는 방식이 달라서, 조심해서 사용해야함 ⭐️
// word = café 라는 단어가 저장되어 있음
let nsWord = word as NSString
word.count
nsWord.length
// NSString은 Objected-C에서 사용하는 문자열이고
// NSString에서 더 파생된 개념인 NSAttributedString을 실제 앱을 만들때, 간혹가다 사용하는 경우가 있음
// 문자열에 클릭기능을 넣는다던지. 글자별로 색깔을 다르게 한다던지
let singleLineString = "These are \nthe same." // 줄바꿈을 원하면, \n 입력 \ (Escape character)
print(singleLineString)
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."
"""
print(quotation)
let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
print(wiseWords)
var name = #"Steve"#
print(name)
let string1 = #"Line 1\nLine 2"# // 특수문자가 그대로 인식됨
print(string1)
let string2 = #"Line 1\#nLine 2"#
print(string2)
let string3 = ###"Line 1\###nLine 2"###
print(string3)
let string4 = #"My name is \#(name)"# // 이스케이프 시퀀스 효과를 사용하려면, 샵을 입력
let threeMoreDoubleQuotationMarks = #"""
Here are three more double quotes: """
"""#
print(threeMoreDoubleQuotationMarks)
let name = "유나"
//print("브레이브걸스: \(name)")
let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
print(message)
[애플이 미리 만들어 놓은 프로토콜]
- 아래의 프로토콜을 채택해서 구현하면 스트링 인터폴레이션을 직접구현 가능
protocol CustomStringConvertible {
var description { get }
}
========================================================**/
//extension Dog: CustomStringConvertible {
// var description: String {
// return "강아지의 이름은 \(name)이고, 몸무게는 \(weight)kg 입니다."
// }
//}
// 강아지의 이름은 초코이고, 몸무게는 15.0입니다.
var greeting = "Hello, world!"
let index: String.Index = greeting.firstIndex(of: ",") ?? greeting.endIndex // ,(콤마)의 인덱스
let beginning: String.SubSequence = greeting[..<index]// 처음부터 인덱스까지
// "Hello" // 타입 확인해보기 ⭐️ String.SubSequence 타입
var word: String.SubSequence = greeting.prefix(5)
word // String.SubSequence 타입
// "Hello"
greeting = "Happy" // 원본을 바꾸는 순간 Substring 문자열들은 새로운 문자열 공간을 만들어서 저장
print(beginning)
print(word)
word = greeting.suffix(3)
word // String.SubSequence 타입
// "ppy"
// 아니면 명시적으로 문자열로 변환해서 저장 가능 (서브스트링에서 벗어남)
let newString: String = String(word)
var someString = "Swift"
// 1) 문자열을 문자열(String) 배열화 하기 ⭐️
var array: [String] = someString.map { String($0) }
print(array)
// 2) 문자열을 문자(Character) 배열화 하기
var array2: [Character] = Array(someString) // [Character] //typealias Element = Character
// (참고) 문자열을 문자열(String) 배열화하는 추가적 방법
var array3: [String] = Array(arrayLiteral: someString) // [String]
// 3) 문자열 배열 [String] =====> 문자열
var newString = array.joined()
newString = array3.joined()
// 4) 문자 배열 [Character] ======> 문자열
var newString2 = String(array2)
someString = "Swift"
someString.randomElement() // 문자열에서 랜덤으로 뽑아내는 것 가능
someString.shuffled() // 섞어서 문자(Character) 배열로 리턴 ["t", "i", "w", "S", "f"]
//someString.shuffled().joined() // 불가능 (문자배열 이기때문)
var newString3 = String(someString.shuffled())
print(newString3)
// map고차함수를 사용해서 변환 ⭐️
newString3 = someString.map { String($0) }.shuffled().joined()
print(newString3)
var string = "swift"
string.lowercased() // 전체 소문자로 바꾼 문자열 리턴 (원본 그대로)
string.uppercased() // 전체 대문자로 바꾼 문자열 리턴 (원본 그대로)
string.capitalized // 대문자로 시작하는 글자로 리턴하는 속성 (원본 그대로)
//"swift".capitalized
// 소문자로 변형시키서 비교하는 것은 가능
"swift" == "Swift" // false
"swift".lowercased() == "Swift".lowercased() // true
var emptyString = " " // [공백]이 포함된 문자열
// 문자열은 길이를 기준으로 빈문장열을 판단
emptyString.count // 1
emptyString.isEmpty // false
emptyString = "" // [빈] 문자열 (nil이 절대 아님)
emptyString.count // 0
emptyString.isEmpty // true
if emptyString == nil { // 빈 문자열은 nil이 아님 ===> String타입 (O) String?타입 (X)
print("nil")
}
let greeting = "Guten Tag!"
greeting.startIndex
print(greeting.startIndex)
greeting[greeting.startIndex] // "G"
// 정수형태를 한번 변형해서(걸러서) 사용하는 방식 ⭐️
var someIndex = greeting.index(greeting.startIndex, offsetBy: 2)
greeting[someIndex] // "t"
someIndex = greeting.index(greeting.startIndex, offsetBy: 1)
greeting[someIndex] // "u"
someIndex = greeting.index(after: greeting.startIndex)
greeting[someIndex] // "u"
someIndex = greeting.index(before: greeting.endIndex)
greeting[someIndex] // "!"
for index in greeting.indices { // 개별 문자의 인덱스에 접근
print("\(greeting[index]) ", terminator: "")
}
print("")
//======================================== 출력결과는 동일하지만 접근법이 다름
for char in greeting {
print("\(char) ", terminator: "")
}
//========================================
// 공백 문자열 다음의 글자를 알고 싶을때
var firstIndex = greeting.firstIndex(of: " ")!
var nextOfEmptyIndex = greeting.index(firstIndex, offsetBy: 1)
greeting[nextOfEmptyIndex]
// 세번째 글자를 알고 싶을때
var thirdCharIndex = greeting.index(greeting.startIndex, offsetBy: 2) // 스타트 인덱스에서 2만큼 이동한 인덱스로
var thirdCh = greeting[thirdCharIndex]
// 범위를 벗어나면 에러발생 주의 ⭐️
//greeting[greeting.endIndex]
greeting[greeting.index(greeting.endIndex, offsetBy: -1)]
//greeting[greeting.index(before: greeting.endIndex)]
// 예를 들자면, 아래와 같이 올바른 범위에서 실행
someIndex = greeting.index(greeting.startIndex, offsetBy: 7)
if greeting.startIndex <= someIndex && someIndex < greeting.endIndex { // 범위를 벗어나지 않는 경우 코드 실행
print(greeting[someIndex])
}
// indices를 직접 출력해보기
for i in greeting.indices {
print(i)
}
//let greeting = "Guten Tag!"
// 문자열 특정범위를 추출
let lower = greeting.index(greeting.startIndex, offsetBy: 2)
let upper = greeting.index(greeting.startIndex, offsetBy: 5)
greeting[lower...upper]
// 실제로는 뒤에서 배울, 교체/삭제에서 주로 범위를 활용
var range = greeting.range(of: "Tag!")!
greeting[range]
range = greeting.range(of: "tag", options: [.caseInsensitive])!
greeting[range]
// 정수 형태 수치로 거리 측정
var distance = greeting.distance(from: lower, to: upper)
print(distance)
var welcome = "Hello"
welcome.insert("!", at: welcome.endIndex)
// "Hello!"
welcome.insert(contentsOf: " there", at: welcome.index(before: welcome.endIndex))
// "Hello there!"
welcome = "Hello there!"
print(welcome)
if let range = welcome.range(of: " there!") { // 범위를 가지고
welcome.replaceSubrange(range, with: " Swift!") // 교체하기
print(welcome)
}
var newWelcome = welcome.replacingOccurrences(of: "Swift", with: "World")
// "Swift"라는 문자열이 존재하면, "World"로 교체
print(welcome)
print(newWelcome)
// 대소문자 무시 옵션
newWelcome = welcome.replacingOccurrences(of: "swift", with: "New World", options: [.caseInsensitive], range: nil)
print(welcome)
print(newWelcome)
"swift" + "!" // 너무나 당연
welcome.append("!")
welcome.append(" Awesome!")
welcome = "Hello Swift!"
// 인덱스를 가지고 지우기
// (endIndex의 전 인덱스)
welcome.remove(at: welcome.index(before: welcome.endIndex)) // "!" 지우기
welcome
// "Hello Swift"
// 인덱스 범위파악
var range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex
//range = welcome.range(of: " Swift")!
// " Swift"의 범위를 파악하고 지우기
welcome.removeSubrange(range)
welcome // "Hello"
welcome.removeAll()
welcome.removeAll(keepingCapacity: true)
var string = "Hello world"
// 1) " " 공백 문자열의 인덱스 찾기
// 2) " " 공백 문자열의 인덱스에 " super" 삽입하기
if let someIndex = string.firstIndex(of: " ") {
string.insert(contentsOf: " super", at: someIndex)
print(string) // "Hello super world"
}
// 1) 첫 " " 공백 문자열의 인덱스 찾기
// 2) " super" 문자열의 범위 만들기
// 3) 범위 삭제하기
if let firstIndex = string.firstIndex(of: " ") {
let range = firstIndex...string.index(firstIndex, offsetBy: 5)
string.removeSubrange(range)
print(string) // "Hello world"
}
// 바꿀 문자열을 정확하게 알고 있다면 ===> 범위를 직접 리턴하는 메서드 활용 ⭐️
if let range = string.range(of: " world") {
string.removeSubrange(range)
print(string)
}
[Subrange만 반환] 원본은 그대로
swift" == "Swift" // false
"swift" != "Swift" // true ===> 둘의 문자는 다른 것임
"swift" < "Swift" // false ====> 첫 글자의 (유니코드) 순서를 비교
"swift" <= "Swift" // false ====> 소문자가 (유니코드/아스키코드) 더 뒤에 위치
//"Swift" <= "swift" // true
// (간단하게는 일치시킨 후 비교)
"swift".lowercased() == "Swift".lowercased()
var a = "swift"
var b = "Swift"
a.caseInsensitiveCompare(b) == ComparisonResult.orderedSame
//문자열.caseInsensitiveCompare(<#T##aString: StringProtocol##StringProtocol#>)
ComparisonResult 열거형 타입으로 정의 (비교 결과 타입)
1) .orderedSame // 동일
2) .orderedAscending // 오름차순
3) .orderedDescending // 내림차순
- 단순 같은지 틀린지 뿐만아니라, 결과가 오름차순/내림차순인지
내림차순인지 알수 있어서 결과값이 활용성이 높고 보다 구체적인 정보 제공가능 ⭐️
(다만, 처음 사용하는 입장에서 헷갈릴 수 있으므로 잘 알고
사용해야하는 불편함이 있을 수 있음)
// 문자열.compare(_:options:range:locale:) ⭐️
var name = "Hello, Swift"
name.compare("hello", options: [.caseInsensitive]) == .orderedDescending // 내림차순 ( , ==> )
String.CompareOptions 구조체]와 내부의 타입 속성들
옵션 입력 부분
// OptionSet 프로토콜 채택시, 여러개의 옵션을 배열 형식으로 전달 가능
//NSString.CompareOptions
struct CompareOptions : OptionSet 프로토콜 채택
// .diacriticInsensitive 발음구별기호 무시하고
"café".compare("cafe", options: [.diacriticInsensitive]) == .orderedSame
// .widthInsensitive 글자 넓이 무시하고
"ァ".compare("ァ", options: [.widthInsensitive]) == .orderedSame
// .forcedOrdering 강제적 오름차순/내림차순 정렬순 (대소문자 무조건 구별 의미)
"Hello".compare("hello", options: [.forcedOrdering, .caseInsensitive]) == .orderedAscending
// .numeric 옵션 숫자 전체를 인식해서 비교
"album_photo9.jpg".compare("album_photo10.jpg", options: [.numeric]) == .orderedAscending
// .literal 옵션
"\u{D55C}".compare("\u{1112}\u{1161}\u{11AB}", options: [.literal]) == .orderedSame
// "한"(완성형) "ㅎ+ㅏ+ㄴ"(조합형)
// .anchored 옵션 (앞부분부터) 고정시키고 (접두어)
if let _ = "Hello, Swift".range(of: "Hello", options: [.anchored]) { // 범위리턴 ===> 접두어 기능
print("접두어 일치")
}
// .anchored 옵션 + .backwards 뒷자리부터 고정 (접미어)
if let _ = "Hello, Swift".range(of: "Swift", options: [.anchored, .backwards]) { // ===> 접미어 기능
print("접미어 일치")
}
var userEmail = " my-email@example.com "
var trimmedString = userEmail.trimmingCharacters(in: [" "])
print(trimmedString)
// "my-email@example.com" (처음, 마지막의 공백 문자열 제거)
// CharacterSet 개념을 활용해서
trimmedString = userEmail.trimmingCharacters(in: .whitespaces)
print(trimmedString)
var someString = "?Swift!"
var removedString = someString.trimmingCharacters(in: ["?","!"])
print(removedString)
someString = "?Swi!ft!"
removedString = someString.trimmingCharacters(in: ["?","!"])
print(removedString) // 중간에 있는 !는 제거하지 못함
var name = " S t e v e "
var removedName = name.components(separatedBy: " ").joined() //["", "S", "t", "e", "v", "e", ""]
print(removedName)
var phoneNum = "010-1234-1234"
var newPhoneNum = phoneNum.components(separatedBy: "-").joined() // ["010", "1234", "1234"]
print(newPhoneNum)
var numString = "1+2-3*4/5"
var removedNumString = numString.components(separatedBy: ["+","-","*","/"]).joined()
print(removedNumString)
var str = "Hello Swift"
var arr = str.split(separator: " ") // 서브스트링으로 리턴함
print(arr)
print(arr.joined())
// - (1) split은 Substring 배열로 리턴
str.split(separator: " ")
// - (2) split은 클로저를 파라미터로 받기도 함 (클로저에서 원하는 함수내용을 정의하면 되므로 활용도가 더 높을 수 있음)
str.split { $0 == " " }
//str.split(whereSeparator: <#T##(Character) throws -> Bool#>)
참고: https://developer.apple.com/documentation/foundation/characterset
============================================**/
// 문자셋을 활용해서
userEmail = " my-email@example.com "
var characterSet = CharacterSet.whitespaces // 공백문자 집합
trimmedString = userEmail.trimmingCharacters(in: characterSet)
print(trimmedString)
name = " S t e v e "
removedName = name.components(separatedBy: characterSet).joined()
print(removedName)
var phoneNumbers = "010 1111 2222"
print(phoneNumbers.components(separatedBy: .whitespaces).joined())
특정 문자열 검색에도 활용가능
name = "hello+world"
if let range = name.rangeOfCharacter(from: .symbols) {
print(name[range])
}