如何从完整的字符串 iOS swift 中查找字符串的多个 NSRange


let fullString = "Hello world, there are (string(07)) continents and (string(195)) countries."
let range = [NSMakeRange(24,2), NSMakeRange(40,3)]

需要找到整个完整字符串中的数字的NSRange,并且两个数字可能相同。当前硬编码如上所示,消息可以是动态的,硬编码值将出现问题。

我已经拆分了字符串并尝试获取NSRange因为存在相同值的可能性。 像字符串一和字符串二。

func findNSMakeRange(initialString:String, fromString: String) {
let fullStringRange = fromString.startIndex..<fromString.endIndex
fromString.enumerateSubstrings(in: fullStringRange, options: NSString.EnumerationOptions.byWords) { (substring, substringRange, enclosingRange, stop) -> () in
let start = distance(fromString.startIndex, substringRange.startIndex)
let length = distance(substringRange.startIndex, substringRange.endIndex)
let range = NSMakeRange(start, length)
if (substring == initialString) {
print(substring, range)
}
})
}

收到Cannot invoke distance with an argument list of type (String.Index, String.Index)等错误

有人有更好的解决方案吗?

您说要循环访问字符串中的NSRange匹配项,以便可以将粗体属性应用于相关子字符串。

在 Swift 5.7 及更高版本中,您可以使用新的正则表达式:

string.ranges(of: /d+/)
.map { NSRange($0, in: string) }
.forEach {
attributedString.setAttributes(attributes, range: $0)
}

或者,如果您发现传统的正则表达式过于神秘,则可以导入RegexBuilder,并且可以使用新的正则表达式DSL:

string.ranges(of: Regex { OneOrMore(.digit) })
.map { NSRange($0, in: string) }
.forEach {
attributedString.setAttributes(attributes, range: $0)
}

在 5.7 之前的 Swift 版本中,人们会使用NSRegularExpression. 例如:

let range = NSRange(location: 0, length: string.count)
try! NSRegularExpression(pattern: "\d+").enumerateMatches(in: string, range: range) { result, _, _ in
guard let range = result?.range else { return }
attributedString.setAttributes(attributes, range: range)
}

就个人而言,在 Swift 5.7 之前,我发现有一个返回 Swift 范围数组的方法很有用,即[Range<String.Index>]

extension StringProtocol {
func ranges<T: StringProtocol>(of string: T, options: String.CompareOptions = []) -> [Range<Index>] {
var ranges: [Range<Index>] = []
var start: Index = startIndex

while let range = range(of: string, options: options, range: start ..< endIndex) {
ranges.append(range)

if !range.isEmpty {
start = range.upperBound               // if not empty, resume search at upper bound
} else if range.lowerBound < endIndex {
start = index(after: range.lowerBound) // if empty and not at end, resume search at next character
} else {
break                                  // if empty and at end, then quit
}
}

return ranges
}
}

然后你可以像这样使用它:

let string = "Hello world, there are 09 continents and 195 countries."
let ranges = string.ranges(of: "[0-9]+", options: .regularExpression)

然后你可以mapRangeNSRange.回到原始示例,如果要使这些数字在某些属性字符串中加粗:

string.ranges(of: "[0-9]+", options: .regularExpression)
.map { NSRange($0, in: string) }
.forEach { attributedString.setAttributes(boldAttributes, range: $0) }
<小时 />

资源:

  • Swift 5.7 及更高版本:
    • WWDC 2022 视频认识斯威夫特正则表达式
    • WWDC 2022 视频 Swift 正则表达式:超越基础知识
    • 使用 Swift 进行黑客攻击:正则表达式
  • 5.7 之前的 Swift:
    • Hacking with Swift: 如何在 Swift 中使用正则表达式
    • NSHipster:Swift 中的正则表达式

最新更新