在Swift中使用正则表达式匹配获取所有可能的范围

3

我正在使用Swift编写以下代码以构建适用于应用程序的适当正则表达式:

let regExp = "-(\\([0-9.a-z()+-×÷√^₁₀²³/]+\\)|[0-9.a-z()+-×÷√^₁₀²³/]+)"

let testString = "-(hsjshdf)   -hsghsgsgs -(k) -(1/64) -dhsg62 -(p)"

let regularExpression = try! NSRegularExpression(pattern: regExp, options: [])

let matchesArray = regularExpression.matches(in: testString, options: [], range: NSRange(location: 0, length: testString.characters.count))

for match in matchesArray {
    for i in 0..<match.numberOfRanges {
        let range = match.rangeAt(i)
        let r = testString.index(testString.startIndex, offsetBy: range.location) ..< testString.index(testString.startIndex, offsetBy: range.location + range.length)
        print(testString.substring(with: r))
    }
}

我得到的结果如下:
-(hsjshdf)
(hsjshdf)
-hsghsgsgs
hsghsgsgs
-(k)
(k)
-(1/64)
(1/64)
-dhsg62
dhsg62
-(p)
(p)

然而,我希望正则表达式匹配并分组括号内的子字符串,以便获得以下输出:
-(hsjshdf)
(hsjshdf)
hsjshdf
-hsghsgsgs
hsghsgsgs
-(k)
(k)
k
-(1/64)
(1/64)
1/64
-dhsg62
dhsg62
-(p)
(p)
p

我对原正则表达式进行了以下修改,它可以处理子字符串“-(hsjshdf)”,但在打印子字符串“-hsghsgsgs”的匹配项时会崩溃,出现执行时间错误(致命错误:无法超出 endIndex):

let regExp = "-(\\(([0-9.a-z()+-×÷√^₁₀²³/]+)\\)|[0-9.a-z()+-×÷√^₁₀²³/]+)"

我不熟悉NSRegularExpression。我是否使用了错误的正则表达式?我需要设置特定的选项吗?

感谢您的帮助。最亲切的问候。

/TB


请展示生成以下结果的代码。您展示的代码并不能生成这样的结果。 - OOPer
抱歉给您带来不便,我忘记包括遍历范围和子范围的循环,因为我假设问题不在这些循环中。 - Tomas Balderas
1个回答

1
事实上,问题在于循环中。您知道在正则表达式let regExp =“ -(\(([0-9.a-z()+-×÷√^₁₀²³ /] +)\] | [0-9.a-z()+ -×÷√^₁₀²³ /]+)"中有两对捕获括号,后者(内部)可能不会捕获字符串的任何部分。您应该知道的一件事是,NSRegularExpression对于缺少捕获,返回NSRange(location:NSNotFound,length:0)。在当前实现中,NSNotFound具有与任何实际字符串相比都要大得多的值Int.max。您只需要在使用它们之前检查范围的位置是否为NSNotFound即可。
let regExp = "-(\\(([0-9.a-z()+-×÷√^₁₀²³/]+)\\)|[0-9.a-z()+-×÷√^₁₀²³/]+)"

let testString = "-(hsjshdf)   -hsghsgsgs -(k) -(1/64) -dhsg62 -(p)"

let regularExpression = try! NSRegularExpression(pattern: regExp, options: [])

//###(1) Use `.utf16.count`, not `.characters.count`.
let matchesArray = regularExpression.matches(in: testString, options: [], range: NSRange(location: 0, length: testString.utf16.count))

for match in matchesArray {
    for i in 0..<match.numberOfRanges {
        let range = match.rangeAt(i)
        if range.location == NSNotFound {continue} //###(2) Skip missing captures.
        //###(3) Your way of creating `r` does not work for non-BMP characters.
        print((testString as NSString).substring(with: range))
    }
}

我的评论(1)和(3)对于你的输入testString并不是关键的,但你也应该知道NSRegularExpression与内部以UTF-16为基础格式表示的NSString一起工作。 locationlength表示基于UTF-16的偏移量和计数,而不是基于Characters


非常感谢你的纠正和评论,OOPer。我仍然不明白为什么将“-hsghsgsgs”这样的子字符串与正则表达式选项[0-9.a-z()+-×÷√^₁₀²³/]+匹配会导致NSNotFound的情况,因为这种选项不包含内部捕获括号,就像其他选项一样。你能否解释一下或提供一个链接? - Tomas Balderas
最好检查一下您的模式 "-(\\(([0-9.a-z()+-×÷√^₁₀²³/]+)\\)|[0-9.a-z()+-×÷√^₁₀²³/]+)" 如何匹配子字符串 "-hsghsgsgs"。在外部捕获中,有两个子模式位于 - 后面,即 \\(([0-9.a-z()+-×÷√^₁₀²³/]+)\\)[0-9.a-z()+-×÷√^₁₀²³/]+。字符串 hsghsgsgs 没有括号括起来,因此后者匹配成功,前者不匹配。与未匹配子模式包含的捕获对应的范围返回 NSNotFound - OOPer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接