Swift - 문자열 자르기
문자열을 쪼개기
Swift 4에서의 변경
Swift 4에서 문자열은 그 자체로 시퀀스이고, 서브시퀀스에 접근하기 위해 characters
속성을 사용하지 않게 되었다. (characters 속성 자체가 제거되었다.). split(separator:)
를 사용해서 문자열을 자른 결과는 Array<Substring>
타입으로 반환된다. Substring
타입 역시 StringProtocol
을 따르고 있기 때문에, 다시 join(separator:)
로 묶은 경우 최종 결과는 String
이 될 수 있다.
let a = "12,34,56,78"
let xs = a.split(separator:",")
let b = xs.joined(separator:"+")
print(b)
// 12+34+56+78
참고로 split(separator:)
에는 빈 문자열을 구분자로 넣을 수 없다. (구분자의 타입은 Character
이다.) 따라서 개별 글자로 쪼개진 배열을 얻고 싶다면, unicodeScalars
프로퍼티를 이용한다. (이 스칼라 코드값을 사용하면 Character나 String을 만들 수 있다.)
let ys = a.unicodeScalars.map(String.init)
// ["1", "2", ",", "3", ... ]
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:"+")
print(b)
//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(" ")
하지만 이렇게 해서 얻은 결과는 Foundation이 제공하는 API를 통해 잘라낸 배열은 [AnyObject]
이다. 만약 우리가 얻고자 하는 결과가 [String]
타입이라면 이를 다시 맵핑해야 한다.[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}
}
이렇게 할 수 있다.