例えば"hogefugapiyo"という文字列があるとして、これを4文字ずつに分割するなら["hoge", "fuga", "piyo"]、5文字ずつに分割するなら["hogef", "ugapi", "yo"]を得たい。

Rubyであればscanメソッドを使って次のように実行できるということがわかった。

1str = "hogefugapiyo"
2# => "hogefugapiyo"
3
4str.scan(/.{1,5}/)
5# => ["hogef", "ugapi", "yo"]

参考

Ruby 文字列を任意の文字数に分割する - Qiita

これと同じことをSwiftでやりたくなったが、どうやら全く同じようなことをする関数はなさそうに見えた。なのでSwift力が足りないながらも自前で書いてみたのでそれを晒してみる。

Rubyの用にArrayを返す関数を追加するのでもよかったが、SequenceTypeを使うほうがよさそうな気がしたので↓のように実装した。Stringsubstr(Int)という関数を生やして、それを呼ぶとforループやmapとかが使えるという感じになった。

 1extension String {
 2    var length: Int { return count(self) }
 3    
 4    internal class SubstringGenerator: GeneratorType {
 5        typealias Element = String
 6        let count: Int
 7        let string: String
 8        var i = 0
 9
10        init(count: Int, string: String) {
11            if count <= 0 {
12                fatalError("'count' must be bigger than 0.")
13            }
14            self.count = count
15            self.string = string
16        }
17        
18        func next() -> Element? {
19            if i < string.length {
20                var endIndex : String.Index
21                if i + count > string.length {
22                    endIndex = string.endIndex
23                } else {
24                    endIndex = advance(string.startIndex, i + count)
25                }
26                
27                var range = advance(string.startIndex, i)..<endIndex
28                i += count
29                return string.substringWithRange(range)
30            } else {
31                return nil
32            }
33        }
34    }
35    
36    internal class SubstringSequence : SequenceType {
37        let count: Int
38        let string : String
39        typealias Generator = SubstringGenerator
40        
41        init(count: Int, string: String) {
42            self.count = count
43            self.string = string
44        }
45        
46        func generate() -> Generator {
47            return Generator(count: count, string: string)
48        }
49    }
50    
51    func substr(count: Int) -> SubstringSequence {
52        return SubstringSequence(count: count, string: self)
53    }
54}

このsubstrを実際に使ってみるとこうなる。

 1for substr in "hogefugapiyo".substr(5) {
 2    println(substr)
 3}
 4// hogef
 5// ugapi
 6// yo
 7
 8var array = map("hogefugapiyo".substr(5)) {$0}
 9println(array)
10// [hogef, ugapi, yo]

どうですかね、これ。