Swiftで「Index」を「Int」タイプに変換するにはどうすればよいですか?


90

文字列に含まれる文字のインデックスを整数値に変換したい。ヘッダーファイルを読み込もうとしましたが、メソッド(eg )Indexを使用ForwardIndexTypeしたプロトコルに準拠しているように見えますが、のタイプが見つかりませんdistanceTo

var letters = "abcdefg"
let index = letters.characters.indexOf("c")!

// ERROR: Cannot invoke initializer for type 'Int' with an argument list of type '(String.CharacterView.Index)'
let intValue = Int(index)  // I want the integer value of the index (e.g. 2)

どんな助けでも大歓迎です。


xcode7.2とswift2.xはありますか?
aaisataev 2015

実際、私は現時点でXcode7.2をダウンロードしています。
クリストファー

33
遊び場であなたの顔を見つめたいインデックスを見ることほどイライラすることはありません。インデックスを必要な種類に変換するのは巨大なPITAです。私はむしろ私のペッカーをドアに叩きつけたいです。
エイドリアン

1
Swift 3:let index = letters.characters.index(of: "c") next Linelet int_index = letters.characters.distance(from: letters.startIndex, to: index)
Viktor

8
アップルWTF !!!!!!
Borzh 2017

回答:


87

編集/更新:

Xcode11•Swift5.1以降

extension StringProtocol {
    func distance(of element: Element) -> Int? { firstIndex(of: element)?.distance(in: self) }
    func distance<S: StringProtocol>(of string: S) -> Int? { range(of: string)?.lowerBound.distance(in: self) }
}

extension Collection {
    func distance(to index: Index) -> Int { distance(from: startIndex, to: index) }
}

extension String.Index {
    func distance<S: StringProtocol>(in string: S) -> Int { string.distance(to: self) }
}

遊び場のテスト

let letters = "abcdefg"

let char: Character = "c"
if let distance = letters.distance(of: char) {
    print("character \(char) was found at position #\(distance)")   // "character c was found at position #2\n"
} else {
    print("character \(char) was not found")
}

let string = "cde"
if let distance = letters.distance(of: string) {
    print("string \(string) was found at position #\(distance)")   // "string cde was found at position #2\n"
} else {
    print("string \(string) was not found")
}

47
彼らはただ、配列の要素の整数値のインデックスを返す関数を作成することを決定しないだろう、なぜ私はそうSMH ..困惑している
MarksCode

6
すべての文字を1バイトに格納できるわけではありません。少し時間を取って、Swift Stringのドキュメントを読む必要があります
Leo Dabus 2017


4
Tbh文字列ではなく、通常の配列の要素の整数値インデックスを取得しようとしています。
marksCode 2017

28
単純なものを不必要に複雑にする:(
Iulian Onofrei 2017年

4

スウィフト4

var str = "abcdefg"
let index = str.index(of: "c")?.encodedOffset // Result: 2

注:文字列に同じ複数の文字が含まれている場合は、左から最も近い文字が取得されます

var str = "abcdefgc"
let index = str.index(of: "c")?.encodedOffset // Result: 2

5
encodingOffsetを使用しないでください。encodingOffsetは非推奨です:最も一般的な使用法が正しくないため、encodedOffsetは非推奨になりました。試してみてください"🇺🇸🇺🇸🇧🇷".index(of: "🇧🇷")?.encodedOffset // 16
LeoDabus19年

@LeoDabusは、非推奨であると正しく述べています。しかし、あなたはとにかくそれを答えとして使うことを提案しています。正解は次のとおりです。index_Of_YourStringVariable.utf16Offset(in:yourStringVariable)
TDesign

いいえ。UTF16オフセットはおそらくあなたが望むものではありません
Leo Dabus

1

encodedOffset非推奨になりましたスウィフト4.2

推奨メッセージ: encodedOffset最も一般的な使用法が正しくないため、非推奨になりました。utf16Offset(in:)同じ動作を実現するために使用します。

したがってutf16Offset(in:)、次のように使用できます。

var str = "abcdefgc"
let index = str.index(of: "c")?.utf16Offset(in: str) // Result: 2

1
試してみてくださいlet str = "🇺🇸🇺🇸🇧🇷" let index = str.firstIndex(of: "🇧🇷")?.utf16Offset(in: str)//結果:8
Leo Dabus

0

インデックスに基づいて文字列操作を実行するには、従来のインデックス数値アプローチでは実行できません。swift.indexはindexes関数によって取得され、Int型ではないためです。文字列は文字の配列ですが、それでも要素をインデックスで読み取ることはできません。

これはイライラします。

したがって、文字列のすべての偶数文字の新しい部分文字列を作成するには、以下のコードを確認してください。

let mystr = "abcdefghijklmnopqrstuvwxyz"
let mystrArray = Array(mystr)
let strLength = mystrArray.count
var resultStrArray : [Character] = []
var i = 0
while i < strLength {
    if i % 2 == 0 {
        resultStrArray.append(mystrArray[i])
      }
    i += 1
}
let resultString = String(resultStrArray)
print(resultString)

出力:acegikmoqsuwy

前もって感謝します


これはフィルターで簡単に達成できますvar counter = 0 let result = mystr.filter { _ in defer { counter += 1 } return counter.isMultiple(of: 2) }
Leo Dabus

String.indexを使用したい場合var index = mystr.startIndex let result = mystr.filter { _ in defer { mystr.formIndex(after: &index) } return mystr.distance(from: mystr.startIndex, to: index).isMultiple(of: 2) }
Leo

0

これは、Intの代わりにsとして部分文字列の境界にアクセスできるようにする拡張機能String.Indexです。

import Foundation

/// This extension is available at
/// https://gist.github.com/zackdotcomputer/9d83f4d48af7127cd0bea427b4d6d61b
extension StringProtocol {
    /// Access the range of the search string as integer indices
    /// in the rendered string.
    /// - NOTE: This is "unsafe" because it may not return what you expect if
    ///     your string contains single symbols formed from multiple scalars.
    /// - Returns: A `CountableRange<Int>` that will align with the Swift String.Index
    ///     from the result of the standard function range(of:).
    func countableRange<SearchType: StringProtocol>(
        of search: SearchType,
        options: String.CompareOptions = [],
        range: Range<String.Index>? = nil,
        locale: Locale? = nil
    ) -> CountableRange<Int>? {
        guard let trueRange = self.range(of: search, options: options, range: range, locale: locale) else {
            return nil
        }

        let intStart = self.distance(from: startIndex, to: trueRange.lowerBound)
        let intEnd = self.distance(from: trueRange.lowerBound, to: trueRange.upperBound) + intStart

        return Range(uncheckedBounds: (lower: intStart, upper: intEnd))
    }
}

これが奇妙さをもたらす可能性があることに注意してください。それがAppleがそれを難し​​くすることを選んだ理由です。(それは議論の余地のある設計上の決定ですが、それを難し​​くするだけで危険なものを隠す...)

詳細については、AppleStringドキュメントを参照してください。ただし、tldrは、これらの「インデックス」が実際には実装固有であるという事実に由来しているということです。これらは、OSによってレンダリングされた後の文字列へのインデックスを表すため、使用されているUnicode仕様のバージョンに応じてOSからOSにシフトできます。これは、文字列内の適切な場所を決定するためにUTF仕様をデータに対して実行する必要があるため、インデックスによる値へのアクセスが定数時間操作ではなくなったことを意味します。これらのインデックスは、NSStringにブリッジした場合、NSStringによって生成された値、または基になるUTFスカラーへのインデックスとも一致しません。警告開発者。


startIndexからの距離を再度測定する必要はありません。下部から上部までの距離を取得し、開始点を追加するだけです。
レオダバス

また、メソッドにオプションを追加します。のようなものfunc rangeInt<S: StringProtocol>(of aString: S, options: String.CompareOptions = []) -> Range<Int>? { guard let range = range(of: aString, options: options) else { return nil } let start = distance(from: startIndex, to: range.lowerBound) return start..<start+distance(from: range.lowerBound, to: range.upperBound) }
Leo Dabus

私はおそらくメソッド名をに変更しcountableRangeて返すでしょう CountableRange
Leo Dabus

全面的に良い提案@LeoDabus。実際、すべてのrange(of ...)引数を追加したので、countableRange(of:、options:、range:、locale :)を呼び出すことができます。要旨を更新しました。この投稿も更新します。
ザック

部分文字列でそのメソッドを呼び出すことができることを考えると、範囲は必要ありません
Leo Dabus
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.