我想从字符串中提取子字符串,忽略重音和大小写。
例如,如果字符串为Curaçao
,而输入子字符串为aca
,则将字符串拆分为三个子字符串:Cur
(匹配子字符串之前的子字符串)、aça
(匹配子字符串)和o
(匹配子字符串之后的剩余子字符串)。
我试过这个代码:
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"))
库拉索
是什么引起的?谢谢你的帮助
发布于 2021-02-22 07:41:22
您可以简单地使用localizedStandardRange,它是不区分大小写的。顺便说一下,不需要将范围转换为整数:
localizedStandardRange(of:)
通过执行大小写和不敏感的、区域设置感知的搜索,查找并返回字符串中给定字符串的第一次出现的范围。
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...]
}
}
print("Curaçao".highlight(substring: "aca") ?? "")
print("Curaçaoçao".highlight(substring: "acaoca") ?? "")
这个会打印出来
库拉索 库拉索
如果只想修复扩展的问题,只需将适当的选项caseInsensitive
和diacriticInsensitive
传递给range方法,不要将范围转换为整数:
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 ""
}
}
您的方法失败的原因是您在哪里搜索范围和计数不同字符串上的距离。
发布于 2021-02-22 07:51:13
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"))
https://stackoverflow.com/questions/66317623
复制