如何在Swift中将“Index”转换为“Int”类型?

时间:2015-12-31 02:25:26

标签: string swift

我想将字符串中包含的字母的索引转换为整数值。尝试读取头文件,但找不到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)

感谢任何帮助。

7 个答案:

答案 0 :(得分:66)

编辑/更新:

Xcode 10.2.x•Swift 5或更高版本

extension Collection where Element: Equatable {
    func indexDistance(of element: Element) -> Int? {
        guard let index = firstIndex(of: element) else { return nil }
        return distance(from: startIndex, to: index)
    }
}
extension StringProtocol {
    func indexDistance(of string: Self) -> Int? {
        guard let index = range(of: string)?.lowerBound else { return nil }
        return distance(from: startIndex, to: index)
    }
}

Xcode 9•Swift 4

let letters = "abcdefg"

if let index = letters.index(of: "c") {
    let distance = letters.distance(from: letters.startIndex, to: index)
    print("distance:", distance)
}
if let index = letters.range(of: "cde")?.lowerBound {
    let distance = letters.distance(from: letters.startIndex, to: index)
    print("distance:", distance)
}

如果要将其实现为Collection的实例方法:

extension Collection where Element: Equatable {
    func indexDistance(of element: Element) -> Int? {
        guard let index = index(of: element) else { return nil }
        return distance(from: startIndex, to: index)
    }
}
extension StringProtocol where Index == String.Index {
    func indexDistance(of string: Self) -> Int? {
        guard let index = range(of: string)?.lowerBound else { return nil }
        return distance(from: startIndex, to: index)
    }
}

游乐场测试

let letters = "abcdefg"

let char: Character = "c"
if let distance = letters.indexDistance(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 cde = "cde"
if let distance = letters.indexDistance(of: cde) {
    print("string \(cde) was found at position #\(distance)")   // "string cde was found at position #2\n"
} else {
    print("string \(string) was not found")
}

Xcode 8•Swift 3

let letters = "abcdefg"
if let index = letters.characters.index(of: "c") {
    let distance = letters.distance(from: letters.startIndex, to: index)
    print("distance:", distance)
}
extension String {
    func indexDistance(of character: Character) -> Int? {
        guard let index = characters.index(of: character) else { return nil }
        return distance(from: startIndex, to: index)
    }
}
let letters = "abcdefg"
let char: Character = "c"
if let index = letters.indexDistance(of: char) {
    print("character \(char) was found at position #\(index)")   // "character c was found at position #2\n"
} else {
    print("character \(char) was not found")
}

旧答案

您需要使用与原始字符串起始索引相关的distanceTo(index)方法:

let intValue = letters.startIndex.distanceTo(index)

您还可以使用方法扩展String,以返回字符串中第一次出现的字符,如下所示:

extension String {
    func indexDistanceOfFirst(character character: Character) -> Int? {
        guard let index = characters.indexOf(character) else { return nil }
        return startIndex.distanceTo(index)
    }
}
let letters = "abcdefg"
let char: Character = "c"
if let index = letters.indexDistanceOfFirst(character: char) {
    print("character \(char) was found at position #\(index)")   // "character c was found at position #2\n"
} else {
    print("character \(char) was not found")
}

答案 1 :(得分:10)

适用于 Xcode 13Swift 5

let myString = "Hello World"

if let i = myString.firstIndex(of: "o") {
  let index: Int = myString.distance(from: myString.startIndex, to: i)
  print(index) // Prints 4
}

函数 func distance(from start: String.Index, to end: String.Index) -> String.IndexDistance 返回一个 IndexDistance,它只是 typealiasInt

答案 2 :(得分: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

答案 3 :(得分:2)

encodedOffset已从 Swift 4.2 中弃用。

弃用消息: encodedOffset已被弃用,因为大多数常用用法都不正确。使用utf16Offset(in:)实现相同的行为。

因此我们可以像这样使用utf16Offset(in:)

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

答案 4 :(得分:1)

搜索这样的索引时

⛔️ guard let index = (positions.firstIndex { position <= $0 }) else {

它被视为Array.Index。您必须为编译器提供一个想要整数的提示

✅ guard let index: Int = (positions.firstIndex { position <= $0 }) else {

答案 5 :(得分:0)

要基于index执行字符串操作,您不能使用传统的索引数字方法执行此操作。因为swift.index是由indexs函数检索的,并且不是Int类型。即使String是一个字符数组,我们仍然无法按索引读取元素。

这令人沮丧。

因此,要创建字符串的每个偶数字符的新子字符串,请检查以下代码。

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

预先感谢

答案 6 :(得分:0)

Here is an extension,可让您以Int而不是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选择加倍努力的原因。 (尽管这是一个值得商design的设计决策-仅通过使其变得困难来隐藏危险的东西...)

您可以在String documentation from Apple中阅读更多内容,但tldr的原因是这些“索引”实际上是特定于实现的。它们表示由操作系统呈现后的字符串索引,因此可以根据所使用的Unicode规范版本在操作系统之间进行转换。这意味着按索引访问值不再是固定时间的操作,因为必须对数据运行UTF规范才能确定字符串中的正确位置。这些索引也不会与NSString生成的值对齐(如果您将其桥接),也不会与基础UTF标量中的索引对齐。警告开发人员。