一尘不染

Swift提取正则表达式匹配

swift

我想从匹配正则表达式模式的字符串中提取子字符串。

所以我正在寻找这样的东西:

func matchesForRegexInText(regex: String!, text: String!) -> [String] {
   ???
}

这就是我所拥有的:

func matchesForRegexInText(regex: String!, text: String!) -> [String] {

    var regex = NSRegularExpression(pattern: regex, 
        options: nil, error: nil)

    var results = regex.matchesInString(text, 
        options: nil, range: NSMakeRange(0, countElements(text))) 
            as Array<NSTextCheckingResult>

    /// ???

    return ...
}

问题是,这matchesInString为我提供了NSTextCheckingResultwhere
NSTextCheckingResult.range类型的数组NSRange

NSRange与不兼容Range<String.Index>,因此它阻止了我使用text.substringWithRange(...)

知道如何在没有太多代码行的情况下快速实现此简单操作吗?


阅读 291

收藏
2020-07-07

共1个答案

一尘不染

即使该matchesInString()方法将a
String作为第一个参数,它也将在内部使用NSString,并且range参数必须使用NSStringlength而不是Swift字符串长度来给出。否则,对于“扩展字素簇”(例如“标志”),它将失败。

Swift 4 (Xcode 9)开始,Swift标准库提供了在Range<String.Index>
和之间进行转换的函数NSRange

func matches(for regex: String, in text: String) -> [String] {

    do {
        let regex = try NSRegularExpression(pattern: regex)
        let results = regex.matches(in: text,
                                    range: NSRange(text.startIndex..., in: text))
        return results.map {
            String(text[Range($0.range, in: text)!])
        }
    } catch let error {
        print("invalid regex: \(error.localizedDescription)")
        return []
    }
}

例:

let string = "🇩🇪€4€9"
let matched = matches(for: "[0-9]", in: string)
print(matched)
// ["4", "9"]

注意: 强制展开Range($0.range, in: text)!是安全的,因为NSRange引用是指给定string的子字符串text。但是,如果要避免这种情况,请使用

        return results.flatMap {
            Range($0.range, in: text).map { String(text[$0]) }
        }

代替。


(Swift 3和更早版本的较旧答案:)

因此,您应该将给定的Swift字符串转换为NSString,然后提取范围。结果将自动转换为Swift字符串数组。

(可在编辑历史记录中找到Swift 1.2的代码。)

Swift 2(Xcode 7.3.1):

func matchesForRegexInText(regex: String, text: String) -> [String] {

    do {
        let regex = try NSRegularExpression(pattern: regex, options: [])
        let nsString = text as NSString
        let results = regex.matchesInString(text,
                                            options: [], range: NSMakeRange(0, nsString.length))
        return results.map { nsString.substringWithRange($0.range)}
    } catch let error as NSError {
        print("invalid regex: \(error.localizedDescription)")
        return []
    }
}

例:

let string = "🇩🇪€4€9"
let matches = matchesForRegexInText("[0-9]", text: string)
print(matches)
// ["4", "9"]

斯威夫特3(Xcode 8)

func matches(for regex: String, in text: String) -> [String] {

    do {
        let regex = try NSRegularExpression(pattern: regex)
        let nsString = text as NSString
        let results = regex.matches(in: text, range: NSRange(location: 0, length: nsString.length))
        return results.map { nsString.substring(with: $0.range)}
    } catch let error {
        print("invalid regex: \(error.localizedDescription)")
        return []
    }
}

例:

let string = "🇩🇪€4€9"
let matched = matches(for: "[0-9]", in: string)
print(matched)
// ["4", "9"]
2020-07-07