Swift で String.Index はどのように機能しますか? 質問する

Swift で String.Index はどのように機能しますか? 質問する

私は古いコードと回答の一部を 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ではなくだった場合7ifステートメントはスキップされます。

String.Index が必要な理由は何ですか?

だろう多くの文字列にインデックスを使用する方が簡単ですInt。文字列ごとに新しいものを作成する必要がある理由は、String.IndexSwift の文字は内部的にすべて同じ長さではないためです。単一の Swift 文字は、1 つ、2 つ、またはそれ以上の Unicode コード ポイントで構成されている場合があります。したがって、それぞれの一意の文字列は、その文字のインデックスを計算する必要があります。

この複雑さを Int インデックス拡張の背後に隠すことは可能ですが、私はそうすることに消極的です。実際に何が起こっているかを思い出すのは良いことです。

おすすめ記事