【问题标题】:Error handling special characters using utfOffset16使用 utfOffset16 处理特殊字符时出错
【发布时间】:2020-04-08 02:21:56
【问题描述】:

我有一个函数可以搜索并返回第一次出现 searchStr 的字符串中的索引,但是只要字符串包含任何特殊字符(例如 ç 或 é),我就会不断收到致命错误。该错误似乎发生在 utf16Offset 调用中,我似乎无法弄清楚为什么..这是我正在使用的代码:

func index(of aString: String, startingFrom position: Int? = 0) -> String.Index? {
    guard let position = position else {
        return nil
    }

    if self.startIndex.utf16Offset(in: aString) + position > self.endIndex.utf16Offset(in: aString) {
        return nil
    } // produces fatal error when special character encountered

    let start: String.Index = self.index(self.startIndex, offsetBy: position)
    let range: Range<Index> = Range<Index>.init(uncheckedBounds: (lower: start, upper: self.endIndex))
    return self.range(of: aString, options: .literal, range: range, locale: nil)?.lowerBound
}

【问题讨论】:

  • 我想显而易见的问题是为什么你会尝试使用utf16Offset 循环遍历一个字符串。另外,你为什么要编写一个已经解决问题的方法?这只是一个练习吗?
  • 我不确定您所说的已解决问题是什么意思?此方法是我用来比较 2 个字符串的库的一部分,它会导致我正在尝试诊断的致命错误...我正在尝试修复或防止此致命错误
  • 但是您在问题中没有说任何这些。问题暗示这是您的代码。 — 无论如何,我建议你升级到 Swift 5,如有必要,放弃使用这个库。

标签: swift xcode swift3


【解决方案1】:

这部分对我来说似乎有问题

if self.startIndex.utf16Offset(in: aString) + position > self.endIndex.utf16Offset(in: aString) {
    return nil
}

您正在获取self 上的起始索引,并将其转换为aString 中的UTF-16 偏移量。 selfaString 是两个不相关的字符串,所以这可能是未定义的行为(这可能是您在某些情况下看到它崩溃的原因)。

这个if 语句的意图似乎是确保它产生一个有效的范围(lower &lt;= upper

let start: String.Index = self.index(self.startIndex, offsetBy: position)
let range: Range<Index> = Range<Index>.init(uncheckedBounds: (lower: start, upper: self.endIndex))

您实际上可以通过像这样直接比较Indexes 来做到这一点

let start: String.Index = self.index(self.startIndex, offsetBy: position)

guard start < self.endIndex else {
    return nil
}

// Range is guaranteed to have valid boundaries now
let range: Range<Index> = Range<Index>.init(uncheckedBounds: (lower: start, upper: self.endIndex))

完整示例:

extension String {
    func index(of aString: String, startingFrom position: Int? = 0) -> String.Index? {
        guard let position = position else {
            return nil
        }

        let start: String.Index = self.index(self.startIndex, offsetBy: position)

        guard start < self.endIndex else {
            return nil
        }

        let range: Range<Index> = Range<Index>.init(uncheckedBounds: (lower: start, upper: self.endIndex))
        return self.range(of: aString, options: .literal, range: range, locale: nil)?.lowerBound
    }
}

// Doesn't crash anymore
"aaç".distance(from: foobar.startIndex, to: foobar.index(of: "ç", startingFrom: 0)!)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-04
    • 1970-01-01
    • 2014-09-13
    相关资源
    最近更新 更多