私は古いコードと回答の一部を Swift 3 で更新してきましたが、Swift の文字列とインデックス作成にたどり着いたとき、理解するのが大変でした。
具体的には、次のことを試していました。
let str = "Hello, playground"
let prefixRange = str.startIndex..<str.startIndex.advancedBy(5) // error
2行目に次のエラーが表示されました
'advancedBy' は使用できません: インデックスを n ステップ進めるには、インデックスを生成した CharacterView インスタンスで 'index(_:offsetBy:)' を呼び出します。
String
以下の方法があるようです。
str.index(after: String.Index)
str.index(before: String.Index)
str.index(String.Index, offsetBy: String.IndexDistance)
str.index(String.Index, offsetBy: String.IndexDistance, limitedBy: String.Index)
最初は本当に混乱したので、理解できるまでいろいろ試してみました。使い方を示すために、以下に回答を追加します。
ベストアンサー1
以下の例はすべて
var str = "Hello, playground"
startIndex
そしてendIndex
startIndex
最初の文字のインデックスですendIndex
インデックスは後最後の文字。
例
// character
str[str.startIndex] // H
str[str.endIndex] // error: after last character
// range
let range = str.startIndex..<str.endIndex
str[range] // "Hello, playground"
Swift 4では片側範囲範囲は次のいずれかの形式に簡略化できます。
let range = str.startIndex...
let range = ..<str.endIndex
わかりやすくするために、次の例では完全な形式を使用しますが、読みやすさを考慮して、コードでは片側の範囲を使用することをお勧めします。
after
例えば:index(after: String.Index)
after
指定されたインデックスの直後の文字のインデックスを参照します。
例
// character
let index = str.index(after: str.startIndex)
str[index] // "e"
// range
let range = str.index(after: str.startIndex)..<str.endIndex
str[range] // "ello, playground"
before
例えば:index(before: String.Index)
before
指定されたインデックスの直前の文字のインデックスを参照します。
例
// character
let index = str.index(before: str.endIndex)
str[index] // d
// range
let range = str.startIndex..<str.index(before: str.endIndex)
str[range] // Hello, playgroun
offsetBy
例えば:index(String.Index, offsetBy: String.IndexDistance)
- 値
offsetBy
は正または負の値を取ることができ、指定されたインデックスから始まります。 型ですがString.IndexDistance
、 を指定することもできますInt
。
例
// character
let index = str.index(str.startIndex, offsetBy: 7)
str[index] // p
// range
let start = str.index(str.startIndex, offsetBy: 7)
let end = str.index(str.endIndex, offsetBy: -6)
let range = start..<end
str[range] // play
limitedBy
例えば:index(String.Index, offsetBy: String.IndexDistance, limitedBy: String.Index)
- は
limitedBy
、オフセットによってインデックスが境界外にならないようにするのに役立ちます。これは境界インデックスです。オフセットが制限を超える可能性があるため、このメソッドは Optional を返します。nil
インデックスが境界外の場合は を返します。
例
// character
if let index = str.index(str.startIndex, offsetBy: 7, limitedBy: str.endIndex) {
str[index] // p
}
オフセットが77
ではなくだった場合7
、if
ステートメントはスキップされます。
String.Index が必要な理由は何ですか?
だろう多くの文字列にインデックスを使用する方が簡単ですInt
。文字列ごとに新しいものを作成する必要がある理由は、String.Index
Swift の文字は内部的にすべて同じ長さではないためです。単一の Swift 文字は、1 つ、2 つ、またはそれ以上の Unicode コード ポイントで構成されている場合があります。したがって、それぞれの一意の文字列は、その文字のインデックスを計算する必要があります。
この複雑さを Int インデックス拡張の背後に隠すことは可能ですが、私はそうすることに消極的です。実際に何が起こっているかを思い出すのは良いことです。