我正在使用 Qt 4.6 编写程序,我需要从表达式中捕获所有出现的非范围文字
"SUM(A1:A3)+B1-B3+SUM(D1:D3)/COUNT(D1:D3)"
,即 B1、B3,但不是 A1、A3、D1、D3。我曾尝试使用 QRegExp,但它不支持否定的后向断言,所以我不能排除像 A3、D3 这样的文字。我的正则表达式(?<!:)([A-Z]{1,4}[1-9]\\d{0,3})(?!:)
不起作用。我需要你的意见。谢谢。
3 回答
在您的情况下,您可以使用
(?:^|[^:])\b([AZ]{1,4}[1-9]\d{0,3})\b(?!:)
第一组匹配开头的空字符串或除冒号之外的任何字符。我还添加了单词边界 \b
,这样模式就不会匹配A4a
.
通常,编写“积极”模式更简单。例如,使用
(...)(:...)?
通过...
表示您的[A-Z]
模式以匹配单元格引用,您可以一次匹配范围和非范围,然后在循环结果时丢弃所有范围。您可以通过检查第二个捕获组是否为空来轻松检测匹配项是否为范围。
对于需要在不支持环视的引擎上进行环视的解决方案,我只找到了一种选择:我称之为“组合暴力破解”,尽管我确信还有一个更具技术性的名称。一个例子是:Validate proxy URL using XML regex pattern。
但是当您需要查找不止一次出现时,它就不起作用了。您可能自己尝试过这样的事情:
/[^:]\b([A-Z]{1,4}[1-9]\d{0,3})\b[^:]/
(我添加了\b
更安全。另外,请记住再次转义反斜杠。)
如果您确实尝试过,那么您会注意到问题:在阅读到+B1-
;之后找到了第一个匹配项。因此,由于-
已经被读取,因此B3
无法匹配下一个单元格引用,因为 . 没有合适的字符[^:]
。
为了重新描述这个问题,上面的正则表达式只能捕获连续的单元格引用链中的所有其他匹配项,例如字符串,
(A1+A2+A3+A4+A5+A6)/(B1+B2+B3+B4+B5+B6)
^^^^ ^^^^ ^^^^ ^^^^ ^^^^ ^^^^
...只有指定的部分会匹配,也显示在这里。
没有办法在单个正则表达式中解决这个问题。您的替代方案:
使用非正则表达式方法。
如果您出于某种原因必须使用正则表达式,那么您唯一的希望可能是能够使用至少两个正则表达式(例如,使用第一个在所有类似单元格引用的字符串周围插入空格,这样您就没有连续的单元格链参考)。
或者,在不太可能的情况下,将它们捕获到子匹配中就足够了,即可以通过
.cap(1)
、.cap(2)
等访问。您可以执行以下操作。
/[^:]\b([A-Z]{1,4}[1-9]\d{0,3})\b[^:](?:(\b([A-Z]{1,4}[1-9]\d{0,3})\b[^:](?:(\b([A-Z]{1,4}[1-9]\d{0,3})\b[^:](?:(\b([A-Z]{1,4}[1-9]\d{0,3})\b[^:](?:(\b([A-Z]{1,4}[1-9]\d{0,3})\b[^:](?:(\b([A-Z]{1,4}[1-9]\d{0,3})\b[^:](?:(\b([A-Z]{1,4}[1-9]\d{0,3})\b[^:]))?))?))?))?))?))?/
好吧,那是不可能阅读的,所以这里有一个更易读的版本。PretendXY
扩展到我们的单元格引用表达式,\b([A-Z]{1,4}[1-9]\d{0,3})\b
. 那么,上面的同理:
/[^:]XY[^:](?:(XY[^:](?:(XY[^:](?:(XY[^:](?:(XY[^:](?:(XY[^:]))?))?))?))?))?))?/
看到图案了吗?在我们继续之前,您可以看到这个正则表达式与我们的示例完美匹配。缺点是,只要您定义正则表达式,您就只能处理一系列连续的单元格引用。以上可以处理7,超过它会破坏。
Qt 5.0 中的 QRegularExpression 支持(固定长度)lookbehind 断言。
https://bugreports.qt-project.org/browse/QTBUG-2371已于 2012 年 3 月 22 日关闭。Qt 5.0 于 2012 年 12 月 19 日发布。