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

brccelvz  于 2022-12-10  发布在  Swift
关注(0)|答案(1)|浏览(250)
let fullString = "Hello world, there are \(string(07)) continents and \(string(195)) countries."
let range = [NSMakeRange(24,2), NSMakeRange(40,3)]

需要在整个完整字符串中查找数字的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)
            }
        })
    }

接收错误,如Cannot invoke distance with an argument list of type (String.Index, String.Index)
有人有更好的解决办法吗?

t3psigkw

t3psigkw1#

您说您希望迭代字符串中的NSRange匹配项,以便将粗体属性应用于相关的子字符串。
在Swift 5.7及更高版本中,您可以使用新的Regex

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

或者,如果您发现传统的正则表达式太晦涩难懂,可以导入RegexBuilder,然后使用新的regex DSL:

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

在Swift 5.7之前的版本中,我们将使用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)

然后你可以把mapRange转换成NSRange。回到最初的例子,如果你想在某个属性化的字符串中把这些数字加粗:

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

资源:

相关问题