夜中にAppleの新製品とかiOSとかSwiftとか色々発表されたみたいですね!
個人的にはSwift2.2正式版がでたのが嬉しいです。ライブラリとかちょこちょこ対応させる作業が必要ですが…笑
を見て、自分なりに実装してみようということでチャレンジしてみました。 (この記事にコメントしたのと同じものです。)
実装してみる
こんな感じで実装してみます。(swift2.1、多分2.2でも大丈夫…?)
public extension String {
public func split(length: Int) -> [String] {
let array = self.characters.map { String($0) } // ★1
let limit = self.characters.count // ★2
return 0
.stride(to: limit, by: length) // ★3
.map({
array[$0..<$0.advancedBy(length, limit: limit)].joinWithSeparator("") // ★4
})
}
}
実行してみる
let str = "Hello, world!"
_ = str.split(2) // ["He", "ll", "o,", " w", "or", "ld", "!"]
_ = str.split(3) // ["Hel", "lo,", " wo", "rld", "!"]
_ = str.split(20) // ["Hello, world!"]
解説
上記のコードで ★
を付けた箇所を順に見ていきます。
★1
まずは、Stringの文字列を、1文字ずつ区切った配列にします。
★2
文字数を取得します。後述の分割処理時に用います。
★3
stride
関数を使って、指定した分割数で分割する場合の、各文字のstartIndexを作成します。
コードに改行が入っていて分かりづらいのですが、しっかりつなげて書くと、
0.stride(to: limit, by: length)
となっています。
このstride
関数は、Strideable
という protocol で定義されていて、
レシーバーの値から、to:
に指定した値を超えない範囲で、by:
で指定した値を足していった配列を作って返してくれるものです。
そして、Strideable
は Int や Float に最初から適応されています。
例えば、
10.stride(to: 23, by: 3)
としたら、得られる配列は、
[10, 13, 16, 19, 22]
となります。
★4
★3のstride
の処理で受けたstartIndexを元に文字列を分割して返します。
単純に、array[$0..<$0+length]
としてしまうと、ぴったり分割できない場合にエラーになってしまうので、
$0.advancedBy(length, limit: limit)
として、 limit を超えないendIndexを作って使います。
ただ、これで得られる値は[String]なので、joinWithSeparator("")
をしてから返します。
おまけ: strideを使わないでfilterを使う場合
public extension String {
public func split(length: Int) -> [String] {
let array = self.characters.map { String($0) }
let limit = self.characters.count
return (0..<limit)
.filter { $0 % length == 0}
.map({
array[$0..<$0.advancedBy(length, limit: limit)].joinWithSeparator("")
})
}
}
こんな感じですかね。見慣れないとはいえ、stride
の方が短く書けるので個人的には気に入っています。
(追記)
もしかしたらSwift3.0
でstride関数周りが違う名前に置き換わったりして、Swift2.1,2.2で使えているstrideの書き方だと将来的にエラーになるかもしれないので、時期がきたらそちらも踏まえて更新します。