【问题标题】:Regex multiple match substring正则表达式多个匹配子字符串
【发布时间】:2014-10-11 19:22:20
【问题描述】:

我有一个应用程序,它根据 perl 正则表达式确定它是否应该显示下拉菜单或简单的输入字段。因此,我必须检查“外部形式”和子字符串的正则表达式模式。为此,我想出了几个解决方案。

给定输入模式“^(100|500|1000)$”,这将导致一个包含三个条目的下拉菜单,100、500 和 1000。我需要一个解析整个模式的正则表达式,以确定是否它是一个有效的列表,并且是一个执行实际子字符串匹配的正则表达式,因为我不知道如何多次匹配一个子字符串。这是我的正则表达式模式:

^\^\((?:((?:[^\|]|\\\|)+)(?:\||(?:\)\$$)))+

稍微简化一下,因为这个正则表达式有点模糊:

^\^\((?:([\w\d]+)(?:\||(?:\)\$$)))+

这可行,但仅存储最后一个子字符串(在给定情况下为 1000)并丢弃其余的,使用 PCRE 和在线正则表达式工具进行测试。要获取实际的子字符串,即下拉菜单字段,我有:

(?:\^\()?((?:[^\|]|\\|)+)(?:\||(?:\)\$$))

再次简化:

(?:\^\()?([\w\d]+)(?:\||(?:\)\$$))

这匹配子字符串,但不匹配另一个正则表达式所做的下拉菜单模式语法(例如,这个也匹配带有子字符串“100”的“^(100|”)。 我的问题是:有没有一种方法可以将这些正则表达式组合成一个匹配 1)整个模式语法和 2)实际子字符串的模式?

提前致谢,

杰里米

P.S.:对不起,如果这很明显,但我今天对所有这些正则表达式有点纠结。

样本数据:

输入正则表达式:^(100|500|1000)$
语法OK!
匹配的子串:100、500、1000
=> 显示下拉菜单

输入正则表达式:^[0-9a-fA-F]+$
语法错误!
=> 显示常规输入字段

输入正则表达式:^(foo|bar)$
语法OK!
匹配的子字符串:“foo”、“bar”
=> 显示下拉菜单

输入正则表达式:^(foo|bar)[0-9]+$
语法错误!
=> 显示常规输入字段

【问题讨论】:

  • 我不确定你的问题。你能把你有什么和你需要什么的样本数据作为输出吗?
  • 感谢您的帮助!我添加了一些示例数据。
  • 我已经用你提供的数据更新了我的答案

标签: regex pcre


【解决方案1】:

你可以通过两个步骤来实现你所需要的。

您可以使用此正则表达式来验证格式:

\^\(\w+(?:\|\w+)*\)\$

Working demo

验证正确的字符串后,您可以使用如下函数:

$str = "^(100|500|1000|2000|3000)$";
$arr = preg_split ("/\W+/" , $str, -1, PREG_SPLIT_NO_EMPTY);
print_r($arr);

输出:

Array
(
    [0] => 100
    [1] => 500
    [2] => 1000
    [3] => 2000
    [4] => 3000
)

【讨论】:

  • 谢谢!这简化了我的语法匹配正则表达式,但不捕获子字符串(在这种情况下为“100”、“500”、“1000”)。你也可以帮我解决这个问题吗?
  • 我将你的正则表达式修改为“\^((\w+)(?:\|(\w+))*)\$”。这会捕获两个组,都是“\w+”,最后一个将被超过 2 个项目覆盖(第一个测试字符串会发生这种情况)。
  • @Jeremy 除了卢卡斯的回答之外,您还可以使用我的正则表达式 \^((\w+)(?:\|(\w+))*)\$。同时我会为此
  • @Jeremy 我认为您应该使用两个步骤。首先使用我的正则表达式来验证模式,然后一旦你验证你可以使用preg_split ("/\W+/", string $subject)
  • 再次感谢您的帮助。由于我的应用程序是用 C 编写的,因此我无法应用您的代码 sn-ps。但我会简化我的正则表达式。正如 Alan 所说,PCRE 不能进行中间捕获。
【解决方案2】:

看起来你正在使用 PCRE。

您可以利用PCRE_DUPNAMES 选项,或者将(?J) 选项放在模式的前面。

此选项使 PCRE 记住每个匹配的捕获组的值,而不仅仅是丢弃除最后一个之外的所有内容。这是错误的,请参阅 cmets)

很遗憾,在线测试工具 AFAIK 不支持它。我不知道您使用哪种语言,但它也需要一些支持才能让您使用此功能。

来自PCRE docs

如果您想获取给定的所有捕获子字符串的完整详细信息 名称,您必须使用 pcre_get_stringtable_entries() 函数。

【讨论】:

  • 我的应用程序是用 C 编写的,而且我确实使用了 pcre。谢谢你的提示,我试试这个。
  • 我承认在查看了 PCRE 文档后我对此有点困惑。我认为它类似于 .NET 的多次捕获,但现在我不太确定了。请告诉我。
  • PCRE_DUPNAMES 允许您为两个或多个组分配相同的名称,即使这些组具有不同的编号。比赛结束后,仍然只有一个值与该名称相关联,与组号相同。 PCRE 仍然没有提供像 .NET 那样检索重复组的中间捕获的方法。
  • @Lucas:我尝试了你的提示,但没有奏效——正如 Alan 所说,PCRE 仍然没有返回所有匹配项。因此,我将按照 Fede 的建议简化我的正则表达式。
  • @AlanMoore 我显然误解了有关此的文档。太糟糕了,谢谢你的澄清。杰里米:很抱歉误导性的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-08
  • 1970-01-01
  • 2013-04-13
  • 2022-07-11
相关资源
最近更新 更多