【问题标题】:Regex - Capturing a Repeated Group正则表达式 - 捕获重复组
【发布时间】:2011-05-12 18:14:23
【问题描述】:

好的,我已经阅读了tutorials,现在我的头太乱了,现在看不清楚了。

我正在尝试从函数签名中捕获参数及其类型信息。所以给出这样的签名:

function(/*string*/a,b,c)

我想要这样的零件:

type: string
param:a
param:b
param:c

这也可以:

type: string
param:a
type: null (or whitespace)
param:b
type: null (or whitespace)
param:c

所以我想出了这个正则表达式,它犯了重复捕获的常见错误(我已经打开了显式捕获):

function\(((\/\*(?<type>[a-zA-Z]+)\*\/)?(?<param>[0-9a-zA-Z_$]+),?)*\)

问题是,我无法纠正错误。 :(。请帮忙!

【问题讨论】:

  • 您使用什么语言?如果这是一个 .Net 模式,那么你很幸运。否则,可能一步都不可能。
  • 我也希望在不使用 .Net 的情况下解决它,但是是的,我最终使用的是 .Net。另外,我查看了 Captures 集合,但我没有可靠的方法将捕获与组相关联(或者我忽略了什么?)。
  • 查看发布的答案。 Match.Captures 更容易找到但不是很有用,你通常需要Group.Captures(当然我猜这里)。
  • @Kobi - 我将把它打开一段时间,以防有人可以通过纯正则表达式解决它。否则,您的解决方案是我最接近的解决方案。我试过了,它也有效;但是,我们知道它会的,不是吗?

标签: .net regex c#-4.0


【解决方案1】:

通常,您需要两个步骤来获取所有数据。
首先,匹配/验证整个函数:

function\((?<parameters>((\/\*[a-zA-Z]+\*\/)?[0-9a-zA-Z_$]+,?)*)\)

请注意,现在您有一个包含所有参数的 parameters 组。您可以再次匹配某些模式以获取所有参数匹配,或者在这种情况下拆分,

如果您使用的是 .Net,那么您很幸运。 .Net 完整记录每个组的所有捕获,因此您可以使用该集合:

match.Groups["param"].Captures

一些注意事项:

  • 如果您确实想要捕获多个类型,您肯定需要空匹配项,因此您可以轻松组合匹配项(虽然您可以排序,但 1 对 1 捕获更简洁)。在这种情况下,您需要可选组 inside 您捕获的组:(?&lt;type&gt;(\/\*[a-zA-Z]+\*\/)?)
  • 您不必在 .Net 模式中转义斜杠 - / 在那里没有特殊含义(C#/.Net 没有正则表达式分隔符)。

这是一个使用捕获的示例。同样,重点是保持typeparam 之间的关系:您想捕获空类型,所以您不会丢失计数。
图案:

function
\(
(?:
    (?:
        /\*(?<type>[a-zA-Z]+)\*/    # type within /* */
        |                           # or
        (?<type>)                   # capture an empty type.
    )
    (?<param>
        [0-9a-zA-Z_$]+
    )
    (?:,|(?=\s*\)))     # mandatory comma, unless before the last ')'
)*
\)

代码:

Match match = Regex.Match(s, pattern, RegexOptions.IgnorePatternWhitespace);
CaptureCollection types = match.Groups["type"].Captures;
CaptureCollection parameters = match.Groups["param"].Captures;
for (int i = 0; i < parameters.Count; i++)
{
    string parameter = parameters[i].Value;
    string type = types[i].Value;
    if (String.IsNullOrEmpty(type))
        type = "NO TYPE";
    Console.WriteLine("Parameter: {0}, Type: {1}", parameter, type);
}

【讨论】:

  • 我又检查了一遍。它确实捕获了多种类型。另一种想法是捕获括号之间的整个字符串,以逗号分隔,然后循环以逐个捕获类型和参数。
  • @Mrchief - 对,我的错!错过了结束括号:P - 我已经更新了答案。你建议的替代想法是我也建议的,虽然错误地只针对名称 - 我也修复了这个问题。
  • 不知怎的,我在这里丢失了我的 cmets!好的,我之前被您的第一个注释转移了,并没有意识到“替代”解决方案与您所展示的相同。我也尝试过 Group.Captures,但这有点冒险。它确实告诉了所有以前的捕获,但它以一种平坦的方式做到了。我需要能够将类型与参数相关联,因此拥有一个平坦的运行列表不是很有帮助。斜线对我来说是新事物,请注意!
  • @Mrchief - 我想我现在明白了这个问题,也许这个更新是有道理的。请注意,虽然这很有趣,但当替代方案可能更简单时,您不必必须坚持使用单一的正则表达式解决方案。
  • 我现在明白空类型的重要性了。您的示例看起来很整洁(在美学上比拆分方法更好)再次,我坚持使用单个正则表达式,因为我喜欢在 .Net 之外使用它。
【解决方案2】:

您引用的页面使用?: 用于非捕获,然后将重复捕获围绕在其自己的组中。我猜他们是在暗示类似function\(((?:(\/\*(?&lt;type&gt;[a-zA-Z]+)\*\/)?(?&lt;param&gt;[0-9a-zA-Z_$]+),?)*)\)

我喜欢使用http://gskinner.com/RegExr/ 来测试我的表达式,但它不会显示重复捕获。您可能必须在返回的任何返回结构中遍历结果,才能查看其他非 .NET 语言中的值。

对不起,我无法更彻底地测试......

【讨论】:

  • regexstorm.net/tester 是一个用于测试 .Net 正则表达式的有用站点。还有 regexhero.net/tester ,但它是基于 Silverlight 的,并且不时唠叨你要钱。
  • 不仅regexhero 为钱而烦恼,偶尔还会导致浏览器崩溃(Silverlight 插件在长时间使用后崩溃)。 Regexstorm 看起来很有希望。谢谢!
  • @Mrchief - 您使用的是什么浏览器/操作系统?我还没有看到 Regex Hero 导致浏览器崩溃。
  • @Steve - 我使用的是 Chrome(11.0.696.68 或更早版本)。在 Firefox 4 中感觉迟缓,但无论如何 FF 都比 Chrome 迟缓。而且我不记得它是否在 Firefox 中崩溃了。操作系统是 Win XP SP3。
  • @Mrchief - 谢谢伙计,我会研究一些东西,看看有什么问题。
【解决方案3】:

这个问题已经有一段时间了,但我想我终于找到了答案。

我想我正在寻找与您相同的情况,但要与 PHP 一起使用,并且在另一篇文章中有一个答案,我发现使用 PCRE 的 \K\G 命令非常有效。在此处查看 Alan Moore 的答案:PHP Regular Expression - Repeating Match of a Group

我的问题是试图提取表格中的所有单元格值,其中每一行包含一个 6 位数字、20x 一个 1 或 2 位数字以及一个不相关的 1 或 2 位数字。解决方案是:

<tr class="[^"]*">\s+<td>(\d{6})<\/td>|\G<\/td>[^<>]*+<td>\K\d{1,6}|<td>(\d{1,2})<\/td>

如果我自己这么说的话,非常好的解决方案!

【讨论】:

  • 问题是每种技术都有其处理此类事情的利基方式。希望在集合或正则表达式中 within 有一些东西。所以现在,如果有人不使用 .Net 或 PCRE,他们就会被冷落。
猜你喜欢
  • 2017-09-13
  • 2011-03-11
  • 2017-01-07
  • 2019-12-19
  • 2011-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-16
相关资源
最近更新 更多