Swift :: 문자열을 분해하기

문자열을 쪼개기

Swift3 버전을 중심으로 업데이트.

Swift 문자열은 Collection 타입이 아니기때문에 문자열을 쪼개는 작업은 characters 속성을 이용해야 하는 것은 Swift2와 동일하다. 다만 API의 이름 변경 정책에 따라서 split(_:) 함수가 split(separator:)로 바뀌었다는 것 정도가 차이점이다.

let a = "12,34,56,78"
let xs = a.characters.split(separator:",").map{ String($0) }
let b = xs.joined(separator:"+") //12+34+56+78

  Swift 2.0 버전으로 업데이트 (2015-08-19)

기본적으로 Swift의 String 타입은 Foundation을 임포트하게되면 NSString과 거의 같은 API를 제공하기 때문에 아래와 같이   -componentsSeparatedByString: (Swift3에서는 components(separatedBy:)메소드를 써서 문자열을 분해할 수 있다.

let string = "Fizz Buzz Fizz Buzz FizzBuzz"
let separated = string.componentsSeparatedByString(" ")

하지만 이렇게 해서 얻은 결과는 [AnyObject] 이다. 만약 우리가 얻고자 하는 결과가 [String] 타입이라면 이를 다시 맵핑해야 한다. Foundation이 제공하는 API를 통해 잘라낸 배열은 [String] 타입이다.

Swift는 이 외에도 임의의 배열을 특정한 구분자를 이용해서 쪼갤 수 있는 제네릭 함수를 제공한다. 이 함수는 잘라낼 요소와의 매칭을 검사하는 클로저를 받기 때문에 두 개 이상의 구분자를 혼합해서 쓸 수 있다.

func split<S : Sliceable, R : BooleanType>
    (elements: S, 
     maxSplit: Int = default, 
     allowEmptySlices: Bool = default, 
     #isSeparator: @noescape (S.Generator.Element) -> R) -> [S.SubSlice]

배열을 잘라내는 split()함수는 배열 타입의 split() 메소드로 편입되었다.

불행히도 Swift 2.0 에서는 문자열이 더 이상 collection 타입이 아니기 때문에 이를 적용할 수 없고, 다음과 같이 변경한다.

let string = "Fizz Buzz, Fizz Buzz FizzBuzz"
let separated = split(string.characters, allowEmptySlices=false)
    {$0 == " " || $0 == ","}.map{ String($0) }

각 글자를 쪼개기

문자열내의 각 Character는 1개의 유니코드 문자를 저장하기 위한 메모리의 크기가 글자마다 다르기 때문에 정수형 인덱스를 사용할 수 없다. 따라서 각 인덱스를 순회하기 위해서는 string.characters.indices를 이용한다.

let s = "hello world"
for (i, c) in s.characters.indices {
    print(i, c)
}

각 글자 하나하나를 문자열로 만들고 싶다면,

let scattered = string.characters.map{ String($0) }

으로 할 수 있다.

아스키코드 값 구하기

숫자나 영문자의 아스키코드값은 UTF16, UTF8에서의 코드값과 동일하다. 따라서 이를 이용하면 쉽게 아스키 코드값 배열로 변환할 수 있다. UTF8 맵은 해당 문자열을 UTF8로 인코딩했을 때 데이터 맵이다. 아스키 코드 영역은 글자당 1바이트씩만 차지하고 있으며, 해당 코드 값이 곧 아스키코드 값이다.  UTF8 코드값은 UInt8 타입의 별칭이기도 하다. 따라서 Int타입의 아스키 코드 값을 구하려면 다음과 같이 한다.

let asciiValues = string.utf8.map{ Int($0) }

문자열을 각 자리 숫자의 수로 분해하려면 “0”의 값을 빼주면 된다. (“0″은 참고로 48임)

let zero = "0".utf8.map{Int($0)}[0]
let digitValues = "41238567".utf8.map{Int($0) - zero}

같은 식으로 각 알파벳의 철자값(A=1, B=2 … )을 구하기 위해서는

func characterValues(str:String) -> [Int] {
    let origin = "A".utf8.map{Int($0)}[0]
    return str.utf8.map{ Int($0) - origin + 1}
}

이렇게 할 수 있다.