Kar*_*ren 2 nsstring nsrange swift
let fullString = "Hello world, there are \(string(07)) continents and \(string(195)) countries."
let range = [NSMakeRange(24,2), NSMakeRange(40,3)]
Run Code Online (Sandbox Code Playgroud)
需要找到整个完整字符串中数字的 NSRange,并且两个数字有可能相同。目前如上所示进行硬编码,消息可以是动态的,而硬编码值将出现问题。
我已经分割了字符串并尝试获取,NSRange
因为可能存在相同的值。比如 stringOne 和 stringTwo。
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)
}
})
}
Run Code Online (Sandbox Code Playgroud)
收到类似错误Cannot invoke distance with an argument list of type (String.Index, String.Index)
大家有更好的解决办法吗?
您说您想要迭代NSRange
字符串中的匹配项,以便可以将粗体属性应用于相关子字符串。
在 Swift 5.7 及更高版本中,您可以使用新的Regex
:
string.ranges(of: /\d+/)
.map { NSRange($0, in: string) }
.forEach {
attributedString.setAttributes(attributes, range: $0)
}
Run Code Online (Sandbox Code Playgroud)
或者,如果您发现传统的正则表达式太神秘,您可以导入RegexBuilder
,并且可以使用新的正则表达式 DSL:
string.ranges(of: Regex { OneOrMore(.digit) })
.map { NSRange($0, in: string) }
.forEach {
attributedString.setAttributes(attributes, range: $0)
}
Run Code Online (Sandbox Code Playgroud)
现在,只有当您确实需要 an 时才需要这种将 映射Range<String.Index>
到 a的模式,而现在很少需要这种模式。例如,如果您只想打印子范围,您可以这样做:NSRange
NSRange
string.ranges(of: /\d+/)
.forEach { print(string[$0]) }
Run Code Online (Sandbox Code Playgroud)
AttributedString
或者,如果您需要在原始 中查找范围的基础上更新可变的String
,您可以映射到Range<AttributedString.Index>
:
string.ranges(of: /\d+/)
.compactMap { Range($0, in: attributedString) }
.forEach { attributedString[$0].foregroundColor = .blue }
Run Code Online (Sandbox Code Playgroud)
但关键的一点是,我们现在可以使用字符Regex
包围的本机文字/
,如上所示。
在 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)
}
Run Code Online (Sandbox Code Playgroud)
因为正则表达式反斜杠位于字符串内部,所以必须用另一个反斜杠对其进行转义(这就是其中有两个反斜杠的原因)。或者您可以使用扩展字符串分隔符,替换"\\d+"
为#"\d+"#
.
就个人而言,在 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
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以像这样使用它:
let string = "Hello world, there are 09 continents and 195 countries."
let ranges = string.ranges(of: "[0-9]+", options: .regularExpression)
Run Code Online (Sandbox Code Playgroud)
然后你就可以map
到. 回到最初的示例,如果您想在某些属性字符串中将这些数字设为粗体:Range
NSRange
let string = "Hello world, there are 09 continents and 195 countries."
let ranges = string.ranges(of: "[0-9]+", options: .regularExpression)
Run Code Online (Sandbox Code Playgroud)
资源:
归档时间: |
|
查看次数: |
2013 次 |
最近记录: |