[Swift] 문자열 처리와 함수 활용 기초 정리

1. 문자열 정리

1. 문자 하나 추출

개념:

String은 배열처럼 인덱스 접근이 불가능해서 startIndex 등을 이용해야 함

예제:


let str = "Hello Swift"
let firstChar = str[str.startIndex]  // "H"


2. 앞/뒤에서 문자열 일부 추출 (prefix, suffix)

개념:

prefix(_:), suffix(_:)를 사용하면 문자열 앞/뒤에서 원하는 개수만큼 추출 가능

예제:


str.prefix(2)   // "He"
str.suffix(3)   // "ift"


3. 특정 위치 기준으로 자르기

개념:

prefix(upTo:), prefix(through:), suffix(from:)으로 특정 인덱스를 기준으로 자를 수 있음

예제:


let index = str.index(str.startIndex, offsetBy: 5)

str.prefix(upTo: index)     // "Hello"
str.prefix(through: index)  // "Hello "
str.suffix(from: index)     // " Swift"


4. 조건 만족 전까지 자르기 (prefix(while:))

개념:

조건에 따라 앞에서부터 자르며, 조건을 처음으로 만족하지 않을 때 멈춤

예제:


str.prefix(while: { $0 != "i" }) // "Hello Sw"


5. 범위를 이용한 부분 문자열 추출

개념:

String.Index를 이용해 범위를 지정하면 원하는 구간을 추출할 수 있음

예제:


let part1 = str[str.startIndex ..< str.index(str.startIndex, offsetBy: 2)] // "He"
let part2 = str[str.index(str.startIndex, offsetBy: 2)...]                 // "llo Swift"


6. Substring → String 변환 (swift 4부터 deprecated)

개념:

prefix, suffix 등은 Substring 타입을 반환하므로, 수정이 필요하면 String()으로 변환해야 함

예제:


let sub = str.prefix(4)
let newStr = String(sub)  // "Hell"

7. 문자열에 문자 추가

개념:

Substring은 수정 불가능하므로 String으로 변환 후 insert, append 등을 사용

예제:


var first = String(str.prefix(1))  // "H"
first.insert("!", at: first.endIndex)  // "H!"

8. 접두어 / 접미어 확인

개념:

hasPrefix, hasSuffix로 문자열이 특정 텍스트로 시작하거나 끝나는지 확인 가능 (대소문자 구분)

예제:

str.hasPrefix("Hello") // true
str.hasPrefix("hello") // false
str.hasSuffix("Swift") // true

Copy-on-Write - Swift의 String, Array 등은 복사를 지연시키고, 값을 수정할 때 진짜 복사(copy)가 일어남

예제:

var a = "Hello"
var b = a         // 복사 아님 (메모리 공유)
b += " Swift"     // 여기서 진짜 복사 발생

print(a) // "Hello"
print(b) // "Hello Swift"


9. 문자열 추가 (append, appending)

개념:

  • append(_:): 원본 문자열에 직접 추가 (mutating)
  • appending(_:): 새로운 문자열을 반환 (non-mutating)

예제:


var str = "Hello"
str.append(", ")               // "Hello, "
let s = str.appending("Swift") // "Hello, Swift"


10. 포맷 문자열 추가 (appendingFormat)

개념:

숫자나 포맷이 필요한 텍스트를 문자열에 추가할 때 사용

예제:


let fileSize = "File Size: ".appendingFormat("%.1f", 12.3456) // "File Size: 12.3"


11. 문자열 삽입 (insert, insert(contentsOf:))

개념:

특정 위치에 문자 또는 문자열을 삽입

예제:


str = "Hello Swift"
str.insert(",", at: str.index(str.startIndex, offsetBy: 5)) // "Hello, Swift"

if let sIndex = str.firstIndex(of: "S") {
    str.insert(contentsOf: "Awesome", at: sIndex) // "Hello, AwesomeSwift"
}

12. 문자열 치환 (replaceSubrange)

개념:

특정 문자열 범위를 찾아서 다른 문자열로 교체 (mutating)

예제:


str = "Hello, Objective-C"
if let range = str.range(of: "Objective-C") {
    str.replaceSubrange(range, with: "Swift") // "Hello, Swift"
}


13. 문자열 복사 후 치환 (replacingCharacters)

개념:

문자열을 수정하지 않고 교체된 새 문자열을 반환

예제:


if let range = str.range(of: "Hello") {
    let s = str.replacingCharacters(in: range, with: "Hi") // "Hi, Swift"
}


14. 문자열 전역 치환 (replacingOccurrences)

개념:

문자열 전체에서 해당 문자열을 찾아 모두 교체 (non-mutating)

예제:


var result = str.replacingOccurrences(of: "Swift", with: "Awesome Swift")
// 대소문자 구분 없이
result = str.replacingOccurrences(of: "swift", with: "Awesome Swift", options: [.caseInsensitive])


15. 문자열 비교 (대소문자 구분 없이)

개념:

  • lowercased(), uppercased()로 변환 후 비교
  • caseInsensitiveCompare로 직접 비교 가능

예제:


"apple".lowercased() == "Apple".lowercased() // true
"apple".caseInsensitiveCompare("Apple") == .orderedSame // true


16. 문자열 삭제 (remove, removeSubrange, removeAll)

개념:

문자열의 특정 문자, 범위 또는 전체 삭제

예제:


str = "Hello, Awesome Swift!!!"

let removed = str.remove(at: str.index(before: str.endIndex)) // 마지막 문자 제거
str.removeFirst()  // 첫 문자 제거
str.removeLast()   // 마지막 문자 제거

if let range = str.range(of: "Awesome") {
    str.removeSubrange(range) // 특정 문자열 제거
}

str.removeAll() // 전체 문자열 삭제
str.removeAll(keepingCapacity: true)  // 메모리는 유지


17. 부분 문자열 제거 (dropFirst, dropLast)

개념:

원본 문자열은 유지하면서 앞/뒤에서 원하는 수만큼 문자 제거한 Substring 반환

예제:


str = "Hello, Awesome Swift!!!"

let substr1 = str.dropLast()    // "Hello, Awesome Swift!!"
let substr2 = str.dropLast(3)   // "Hello, Awesome Swift"
let substr3 = str.dropFirst()   // "ello, Awesome Swift!!!"
let substr4 = str.dropFirst(2)  // "llo, Awesome Swift!!!"


2. CharacterSet

1. 대문자 문자셋 & 반전 (CharacterSet.uppercaseLetters, inverted)

개념:

  • CharacterSet.uppercaseLetters: A~Z 대문자 집합
  • .inverted: 해당 집합을 제외한 나머지 문자로 구성된 집합

예제:


let a = CharacterSet.uppercaseLetters
let b = a.inverted


2. 문자열 양쪽 공백 제거 (trimmingCharacters)

개념:

  • 문자열 양 끝의 지정된 문자셋(주로 공백)을 제거
  • 원본을 수정하지 않고 새로운 문자열 반환

예제:


let str = " A p p l e "
let trimmed = str.trimmingCharacters(in: .whitespaces) // "A p p l e"


3. 문자열 내 모든 공백 제거 (replacingOccurrences)

개념:

  • 특정 문자열(예: " ")을 모두 제거
  • 중간 공백 포함 전체 제거 가능

예제:


let noSpaces = str.replacingOccurrences(of: " ", with: "") // "Apple"


4. 문자셋 편집 (insert, remove)

개념:

  • 문자셋에 특정 문자를 삽입/제거 가능
  • charactersIn:을 통해 다중 문자도 추가/제거 가능

예제:


var editTarget = CharacterSet.uppercaseLetters
editTarget.insert("#")
editTarget.insert(charactersIn: "~!@")
editTarget.remove("#")
editTarget.remove(charactersIn: "~!@")


5. 문자열 분리 (components(separatedBy:))

개념:

문자셋을 기준으로 문자열을 나누어 배열로 반환

예제:

swift
복사편집
let email = "user@email.com"
let customCharSet = CharacterSet(charactersIn: "@.")
let components = email.components(separatedBy: customCharSet)
// ["user", "email", "com"]


6. 이메일 유효성 검사

개념:

  • 알파벳, 숫자, @. 외의 문자가 있는지 검사
  • .inverted를 이용해 허용되지 않은 문자 존재 여부 확인

예제:

swift
복사편집
func isValidEmail(_ email: String) -> Bool {
    let allowedSet = CharacterSet.alphanumerics.union(CharacterSet(charactersIn: "@."))
    return email.rangeOfCharacter(from: allowedSet.inverted) == nil
}

isValidEmail("user@email.com")     // true
isValidEmail("user#email.com")     // false


7. 강력한 비밀번호 유효성 검사

개념:

  • 최소 길이 8자 이상
  • 대문자, 소문자, 숫자, 특수문자 각각 하나 이상 포함 여부 검사

예제:

swift
복사편집
func strongPassWord(_ password: String) -> Bool {
    guard password.count >= 8 else { return false }

    let hasUppercase = password.rangeOfCharacter(from: .uppercaseLetters) != nil
    let hasLowercase = password.rangeOfCharacter(from: .lowercaseLetters) != nil
    let hasDigit = password.rangeOfCharacter(from: .decimalDigits) != nil
    let hasPunctuation = password.rangeOfCharacter(from: .punctuationCharacters) != nil

    return hasUppercase && hasLowercase && hasDigit && hasPunctuation
}

strongPassWord("Password123!") // true
strongPassWord("pass123")      // false

3. Compare

1. 대소문자 구분 문자열 비교 (==, caseInsensitiveCompare, compare)

개념:

  • ==: 두 문자열이 대소문자 구분하여 동일한지 비교
  • caseInsensitiveCompare: 대소문자 구분 없이 비교
  • compare(options:): 옵션을 설정하여 대소문자 구분 여부를 지정해 비교

예제:


let bigA = "Apple"
let smallA = "apple"

bigA == smallA // false
bigA.caseInsensitiveCompare(smallA) == .orderedSame // true
bigA.compare(smallA, options: [.caseInsensitive]) == .orderedSame // true


2. 사전식 비교 (<, asciiValue)

개념:

  • 문자열은 유니코드(또는 ASCII) 값을 기준으로 사전식으로 비교
  • ASCII 값이 더 작은 문자는 사전에서 더 앞에 옴
  • asciiValue: Character 타입의 ASCII 값을 반환

예제:


let bigA = "Apple"
let smallA = "apple"

bigA < smallA // true
("A" as Character).asciiValue // 65
("a" as Character).asciiValue // 97


3. 문자열 포함 여부 확인 (contains)

개념:

  • contains: 대소문자를 구분하여 문자열에 특정 값이 포함되어 있는지 확인
  • lowercased().contains: 대소문자 구분 없이 비교하려면, 문자열을 모두 소문자(또는 대문자)로 변환한 후 비교

예제:


let str = "Hello, Swift"

str.contains("Swift") // true
str.contains("swift") // false
str.lowercased().contains("swift".lowercased()) // true


4. 문자열 범위 검색 (range(of:))

개념:

  • range(of:): 문자열에서 특정 부분을 찾아 Range 객체를 반환
  • options: .caseInsensitive 옵션을 사용하여 대소문자를 구분하지 않도록 할 수 있음

예제:


let str = "Hello, Swift"

str.range(of: "swift", options: [.caseInsensitive]) // true

4. Function / Closure

1. 함수 표기법 (Function Notation)

개념:

  • 함수 가리키기를 함수 표기법(Function Notation)이라고 함
  • 함수 자체를 호출하지 않고 가리키는 경우를 의미

// 함수 정의
func sayHello() {
    print("Hello, Swift")
}

// 함수 표기법: 함수 자체를 가리킴
let f1 = sayHello
//f1() // 함수 호출은 되지 않음

예제:


2. 함수는 First-class Citizen

개념:

  • Swift에서 함수는 First-class Citizen이다. 즉, 함수는 다음과 같은 방식으로 다룰 수 있다:
    1. 변수나 상수에 저장 가능
    2. 함수의 파라미터로 전달 가능
    3. 함수의 리턴값으로 반환 가능

예제:


// 함수 정의
func sayHello() {
    print("Hello, Swift")
}

// 함수는 First-class Citizen 이므로 변수에 저장할 수 있음
let f1 = sayHello
f1()  // 함수 호출

// 파라미터로 전달하거나 리턴할 수도 있음
func printHello(with name: String) {
    print("Hello \(name)")
}

let f2: (String) -> () = printHello(with:)
f2("Swift")  // "Hello Swift" 출력


3. 함수 타입에 따른 변수 할당

개념:

  • 함수의 이름만 있으면 그 함수 타입에 맞는 변수나 상수에 할당할 수 있음
  • 함수의 매개변수 이름과 상관없이 같은 함수 타입이라면 동일한 변수나 상수에 할당 가능

예제:


// 함수 정의
func printHello(with name: String) {
    print("Hello \(name)")
}

func printHello2(from name: String) {
    print("Hello \(name)")
}

// 동일한 타입을 가지므로 f3에 할당 가능
let f3 = printHello(with:)
f3("Swift")  // "Hello Swift" 출력


4. 함수 타입에 맞는 변수 할당 예제

개념:

  • Argument Label이 다르더라도 함수 타입이 같으면 같은 변수나 상수에 할당 가능

예제:


func add(a: Int, b: Int) -> Int {
    return a + b
}

func add(_ a: Int, with b: Int) -> Int {
    return a + b
}

// 함수 타입이 같다면 Argument Label이 다르더라도 같은 변수에 할당 가능
var f4: (Int, Int) -> Int = add(a:b:)
f4(1, 2)  // 3

f4 = add(_:with:)
f4(1, 2)  // 3


5. 함수는 모두 클로저 (Closure)

개념:

  • Swift에서 모든 함수는 클로저이다.
  • 함수는 이름을 가진 클로저이고, 익명 함수는 이름이 없는 클로저라고 할 수 있음

예제:


// 이름이 있는 함수 (named Closure)
let c = { print("Hello") }
c()  // "Hello" 출력

// 이름이 없는 클로저 (익명 함수)
let c2 = { (str: String) -> String in
    return "Hello \(str)"
}
c2("Swift")  // "Hello Swift" 출력


© 2021. All rights reserved.