首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Swift:获得字符串的子字符串,忽略大小写和重音

Swift:获得字符串的子字符串,忽略大小写和重音
EN

Stack Overflow用户
提问于 2021-02-22 14:29:35
回答 2查看 329关注 0票数 0

我想从字符串中提取子字符串,忽略重音和大小写。

例如,如果字符串为Curaçao,而输入子字符串为aca,则将字符串拆分为三个子字符串:Cur (匹配子字符串之前的子字符串)、aça (匹配子字符串)和o (匹配子字符串之后的剩余子字符串)。

我试过这个代码:

代码语言:javascript
运行
复制
extension String {
    subscript(offset: Int) -> Character { self[index(startIndex, offsetBy: offset)] }
    subscript(range: Range<Int>) -> SubSequence {
        let startIndex = index(self.startIndex, offsetBy: range.lowerBound)
        return self[startIndex..<index(startIndex, offsetBy: range.count)]
    }
    subscript(range: ClosedRange<Int>) -> SubSequence {
        let startIndex = index(self.startIndex, offsetBy: range.lowerBound)
        return self[startIndex..<index(startIndex, offsetBy: range.count)]
    }
    subscript(range: PartialRangeFrom<Int>) -> SubSequence { self[index(startIndex, offsetBy: range.lowerBound)...] }
    subscript(range: PartialRangeThrough<Int>) -> SubSequence { self[...index(startIndex, offsetBy: range.upperBound)] }
    subscript(range: PartialRangeUpTo<Int>) -> SubSequence { self[..<index(startIndex, offsetBy: range.upperBound)] }
    
    func highlight(substring: String) -> String {
        if let range = lowercased()
            .folding(options: .diacriticInsensitive, locale: .current)
            .range(of: substring
                    .lowercased()
                    .folding(options: .diacriticInsensitive, locale: .current)) {
            let startPos = distance(from: startIndex, to: range.lowerBound)
            let endPos = distance(from: startIndex, to: range.upperBound)
            let firstSubstring = self[..<startPos]
            let secondSubstring = self[range]
            let thirdSubstring = self[endPos...]
            return "\(firstSubstring)[\(secondSubstring)]\(thirdSubstring)"
        } else {
            return ""
        }
    }
}

然而,在尝试时:

print("Curaçao".highlight(substring: "aca"))

库拉索

另一个例子是:

print("Curaçaoçao".highlight(substring: "acaoca"))

库拉索

是什么引起的?谢谢你的帮助

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-02-22 15:41:22

您可以简单地使用localizedStandardRange,它是不区分大小写的。顺便说一下,不需要将范围转换为整数:

代码语言:javascript
运行
复制
localizedStandardRange(of:)

通过执行大小写和不敏感的、区域设置感知的搜索,查找并返回字符串中给定字符串的第一次出现的范围。

代码语言:javascript
运行
复制
extension StringProtocol where Self: RangeReplaceableCollection {
    func highlight<S: StringProtocol>(substring: S) -> SubSequence? {
        guard let range = localizedStandardRange(of: substring) else { return nil }
        return self[..<range.lowerBound] + "[" + self[range] + "]" + self[range.upperBound...]
    }
}
代码语言:javascript
运行
复制
print("Curaçao".highlight(substring: "aca") ?? "")
print("Curaçaoçao".highlight(substring: "acaoca") ?? "")

这个会打印出来

库拉索 库拉索

如果只想修复扩展的问题,只需将适当的选项caseInsensitivediacriticInsensitive传递给range方法,不要将范围转换为整数:

代码语言:javascript
运行
复制
func highlight(substring: String) -> String {
    if let range = range(of: substring, options: [.caseInsensitive, .diacriticInsensitive]) {
        let firstSubstring = self[..<range.lowerBound]
        let secondSubstring = self[range]
        let thirdSubstring = self[range.upperBound]
        return "\(firstSubstring)[\(secondSubstring)]\(thirdSubstring)"
    } else {
        return ""
    }
}

您的方法失败的原因是您在哪里搜索范围和计数不同字符串上的距离。

票数 3
EN

Stack Overflow用户

发布于 2021-02-22 15:51:13

代码语言:javascript
运行
复制
extension String {
    subscript(_ range: CountableRange<Int>) -> String {
        let start = index(startIndex, offsetBy: max(0, range.lowerBound))
        let end = index(start, offsetBy: min(self.count - range.lowerBound, 
                                             range.upperBound - range.lowerBound))
        return String(self[start..<end])
    }

    subscript(_ range: CountablePartialRangeFrom<Int>) -> String {
        let start = index(startIndex, offsetBy: max(0, range.lowerBound))
        return String(self[start...])
    }

    func highlight(substring: String) -> String {
        let stringWithoutCaseOrLetters = self.folding(options: .diacriticInsensitive, locale: .current)
        if let range = lowercased()
            .folding(options: .diacriticInsensitive, locale: .current)
            .range(of: substring
                    .lowercased()
                    .folding(options: .diacriticInsensitive, locale: .current)) {
            let startPos:Int = stringWithoutCaseOrLetters.distance(from: startIndex, to: range.lowerBound)
            let endPos:Int = stringWithoutCaseOrLetters.distance(from: startIndex, to: range.upperBound)
            let firstSubstring = self[0..<startPos]
            let secondSubstring = self[startPos..<endPos]
            let thirdSubstring = self[endPos...]
            return "\(firstSubstring)[\(secondSubstring)]\(thirdSubstring)"
        }
        return ""
    }
}

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 string = "Curaçao"
print(string[0..<string.count])
print(string.highlight(substring: "aca"))

print("Curaçaoçao".highlight(substring: "acaoca"))
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66317623

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档