2020-10-09 追記
自分でも書いてて忘れたのでメモします。
var text = "Hello, playground"
let from = text.index(text.startIndex, offsetBy:0)
let to = text.index(text.startIndex, offsetBy:5)
let newString = String(text[from..<to])
print(newString)
-> Hello
クロージャーで書くとこんな感じ
let substr : (String, Int, Int) -> String = { text, from, length in
let to = text.index(text.startIndex, offsetBy:from + length)
let from = text.index(text.startIndex, offsetBy:from)
return String(text[from...to])
}
let text = "Hello, playground"
let newString = substr(text, 1, 2)
print(newString)
2020/03/17 追記
Swift5だとまた変わってます。何回いじるんやほんま…
Swift5からはString()で囲めばOKです。
let text = text[from...to]
↓
let text = String(text[from...to])
2017/11/07 追記
XCode9.1になってさらっとSwiftが4.0.2にバージョンアップしました。
Stirng.characters
がdeperecatedになっていました。
記憶違いかもしれませんが、確か4.0の時はdeprecatedではなかったと思うのですが...
というわけで下記の修正を行っています。
var hoge : String = "aaaa"
hoge.characters.length
↓
hoge.count
本文
Swift4でそこまで変更ないと思っていましたが、Stringが再度Collectionになった結果地味に書き換える箇所が発生していました。
warningだけでは判断出来なかったので、調べた内容をメモしました。
Swift3 < 4までの書き方
var text1 = text.substring(from: text.index(text.startIndex, offsetBy: 1))
この書き方で書いた場合
'substring(from:)' is deprecated: Please use String slicing subscript with a 'partial range from' operator.
というwarningが出ます。
swift4からrangeを使ってsubstringをすればよい、ということですね。
復習:Swiftでのrangeの書き方
Swiftのrangeの書き方に未だに慣れていないのでまとめます。
1. 1から5まで
let one2five = 1...5
2. 1から5未満
let one2lessthanfive = 1..<5
3. 1以上
let morethanOne = 1...
4. 5以下
let lessthanFive = ...5
5. 5未満
let lessthanFive = ..<5
substringでの利用法
let text : String = "abcdefg"
let text2 = text[1...]
こんな書き方が出来るような気がしたのですが、実際にはこれはエラーになります。
Stringでやる場合はString.Indexを使ってrangeを記述する必要があります。
- 1〜5文字目まで
let text1 = text[text.startIndex...text.index(text.startIndex, offsetBy: 4)]
let text2 = text[text.startIndex..<text.index(text.startIndex, offsetBy: 5)]
let text2 = text[..<text.index(text.startIndex, offsetBy: 5)]
2.2文字目から末尾まで
let text1 = text[text.index(text.startIndex, offsetBy: 1)...]
let text2 = text[text.index(text.startIndex, offsetBy: 1)...text.index(before: text.endIndex)]
let text3 = text[text.index(text.startIndex, offsetBy: 1)..<text.endIndex]
3.2〜4文字目
let text1 = text[text.index(text.startIndex, offsetBy: 1)...text.index(text.startIndex, offsetBy: 3)]
let text2 = text[text.index(text.startIndex, offsetBy: 1)..<text.index(text.startIndex, offsetBy: 4)]
let from = text.index(text.startIndex, offsetBy: 1)
let to = text.index(from, offsetBy: 2)
let text3 = text[from...to]
別の書き方
先頭から、又は末尾から限定であればより短い記述で記述することが出来ます。
1.先頭からx文字
let text1 = text.prefix(x)
2.末尾からx文字
let text1 = text.suffix(x)
マイナス値を指定することが出来ないので、末尾を1文字削る場合などは以下のように書きます。
let text1 = text.prefix(text.characters.count-1)
Range表記とprefix/suffixの違い
Range表記の場合、文字列の範囲外を指定した場合にfatalエラーが出て止まります。
do〜catchでエラーをキャッチすることも出来ないのでコードでチェックする必要がありそうです。
prefix/suffixの場合は長すぎた場合でもエラーが発生しないので、利用箇所は制限されますが、極力こちらを使うのが正解と考えられます。
Extensionで解決
text.substring(1...5)
text.substring(1..<5)
text.substring(1...)
text.substring(...5)
直感的にRangeで書くためのExtensionを作ってみました。
extension String {
func substring(_ r: CountableRange<Int>) -> String {
let length = self.count
let fromIndex = (r.startIndex > 0) ? self.index(self.startIndex, offsetBy: r.startIndex) : self.startIndex
let toIndex = (length > r.endIndex) ? self.index(self.startIndex, offsetBy: r.endIndex) : self.endIndex
if fromIndex >= self.startIndex && toIndex <= self.endIndex {
return String(self[fromIndex..<toIndex])
}
return String(self)
}
func substring(_ r: CountableClosedRange<Int>) -> String {
let from = r.lowerBound
let to = r.upperBound
return self.substring(from..<(to+1))
}
func substring(_ r: CountablePartialRangeFrom<Int>) -> String {
let from = r.lowerBound
let to = self.count
return self.substring(from..<to)
}
func substring(_ r: PartialRangeThrough<Int>) -> String {
let from = 0
let to = r.upperBound
return self.substring(from..<to)
}
}