捕获组在 NSRegularExpression 中不起作用

Posted

技术标签:

【中文标题】捕获组在 NSRegularExpression 中不起作用【英文标题】:Capture groups not working in NSRegularExpression 【发布时间】:2011-10-12 22:27:03 【问题描述】:

为什么这段代码只吐出整个正则表达式匹配而不是捕获组?

输入

@"A long string containing Name:</td><td>A name here</td> amongst other things"

预期输出

A name here

实际输出

Name:</td><td>A name here</td>

代码

NSString *htmlString = @"A long string containing Name:</td><td>A name here</td> amongst other things";
NSRegularExpression *nameExpression = [NSRegularExpression regularExpressionWithPattern:@"Name:</td>.*\">(.*)</td>" options:NSRegularExpressionSearch error:nil];

NSArray *matches = [nameExpression matchesInString:htmlString
                                  options:0
                                    range:NSMakeRange(0, [htmlString length])];
for (NSTextCheckingResult *match in matches) 
    NSRange matchRange = [match range];
    NSString *matchString = [htmlString substringWithRange:matchRange];
    NSLog(@"%@", matchString);

取自 Apple 文档的代码。 我知道还有其他库可以做到这一点,但我想坚持这项任务的内置内容。

【问题讨论】:

更新:添加更多捕获组不会退出更多匹配项。总是一场比赛。为什么?! 【参考方案1】:

您将使用以下方法访问第一个组范围:

for (NSTextCheckingResult *match in matches) 
    //NSRange matchRange = [match range];
    NSRange matchRange = [match rangeAtIndex:1];
    NSString *matchString = [htmlString substringWithRange:matchRange];
    NSLog(@"%@", matchString);

【讨论】:

我非常有信心我已经尝试过,但不知何故这次它奏效了。谢谢! 在访问索引范围之前,您必须检查 numberOfRanges 值以防止崩溃。【参考方案2】:

不要使用正则表达式或 NSScanner 解析 HTML。沿着这条路走下去就是疯狂。

这在 SO 上已被多次询问。

parsing HTML on the iPhone

我挑选的数据就像&lt;td&gt;Name: A name&lt;/td&gt; 一样简单,我 认为它很简单,只需使用正则表达式而不是 在项目中包括一个完整的 HTML 解析器。

由你决定,我强烈主张“首先进入市场具有巨大优势”。

不同之处在于,使用适当的 HTML 解析器,您正在考虑文档的结构。使用正则表达式,您依赖的文档永远不会以语法上完全有效的方式更改格式。

即如果输入是&lt;td class="name"&gt;Name: A name&lt;/td&gt; 怎么办?您的正则表达式解析器刚刚破坏了有效的 HTML 输入,并且从标签内容的角度来看,与原始输入相同。

【讨论】:

如果您只需要几个字符串,为什么不呢?没有列表等。 即输入永远不会改变结构,标签的顺序永远不会改变,代码永远不会被重用或重构,标签永远不会添加属性,编码永远不会改变?当然。去吧。 (说真的 - 如果它现在足够好......去吧。只要知道你有一个时间吮吸你的手,可能有一天会突然出现。) 好吧,如果你使用解析器,你仍然需要知道数据在文档中的什么位置,并且无论你怎么做,原始文档的变化都会影响你的解析。我挑选的数据就像 Name: A name 一样简单,我认为它足够简单,只需使用正则表达式,而不是在项目中包含完整的 HTML 解析器。 正则表达式不够复杂,无法正确解析 HTML,因为 HTML 不是常规语言。您必须对输入做出很多假设,例如限制嵌套级别。您的程序将在任何违反这些严格期望的输入上失败。你愿意承担这个风险吗? 是的,因为我在使用上述简单字符串之后,现在它可以完美地工作,因为我能够访问捕获组。【参考方案3】:

在 swift3 中

//: Playground - noun: a place where people can play

import UIKit

/// Two groups. 1: [A-Z]+, 2: [0-9]+
var pattern = "([A-Z]+)([0-9]+)"

let regex = try NSRegularExpression(pattern: pattern, options:[.caseInsensitive])

let str = "AA01B2C3DD4"
let strLen = str.characters.count
let results = regex.matches(in: str, options: [], range: NSMakeRange(0, strLen))

let nsStr = str as NSString

for a in results 

    let c = a.numberOfRanges 
    print(c)

    let m0 = a.rangeAt(0)  //< Ex: 'AA01'
    let m1 = a.rangeAt(1)  //< Group 1: Alpha chars, ex: 'AA'
    let m2 = a.rangeAt(2)  //< Group 2: Digital numbers, ex: '01'
    // let m3 = a.rangeAt(3) //< Runtime exceptions

    let s = nsStr.substring(with: m2)
    print(s)

【讨论】:

【参考方案4】:

HTML 不是常规语言,无法使用正则表达式正确解析。 Here's a classic SO answer 解释这个常见的程序员误区。

【讨论】:

不要用正则表达式解析 HTML,因为“每次你试图用正则表达式解析 HTML 时,邪恶的孩子都会流着处女的血,俄罗斯黑客会攻击你的 webapp。”?长大了。 不,不要用正则表达式解析 HTML,因为你不能用正则表达式解析 HTML。 这需要澄清。正则表达式是解析 (X)HTML 的坏工具,但 (X)HTML 或正则表达式的性质并没有使它“错误”。应用于 (X)HTML 的正则表达式将按预期运行,它只是一个糟糕的工具。

以上是关于捕获组在 NSRegularExpression 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

NSPredicate 和 NSRegularExpression

NSRegularExpression如何让NSRange超出范围?

非贪婪的 NSRegularExpression

NSRegularExpression 与 Swift 中的模板

如何在Objective C(NSRegularExpression)中编写正则表达式?

iOS 中文字符判断 正则NSRegularExpression 谓词NSPredicate 和 NSRange