【问题标题】:Pattern matching with regex on article reference文章参考上与正则表达式的模式匹配
【发布时间】:2013-05-28 08:20:15
【问题描述】:

我需要在 PHP 中针对给定字符串中的许多文章引用进行模式匹配,然后我想提取它们。引用最多可以有 16 位数字,每个数字都可以有不同的值。要知道的一件事:从(包括)数字 11 开始,传入数据中的所有内容都可以是可选的(但如果在可选数字之后有有效的东西,那么这个数字必然是“-”)。另外,如果你有“-”直到最后,引用可以被截断。例如:

A2--L3500XM-----可以是A2--L3500XM

D4--L4652Z-4----可以是D4--L4652Z-4

A3--L5020MW4---A保持A3--L5020MW4---A

这些都是有效的参考。到目前为止,这是我一直在做的事情:

[DA][1-5][V\-][AN\-][LMFGHN][\d]{4}[H-RT-ZBD]([H-RT-ZBD\-]?)(?(-1)[1-4\-]?)

我最多到第 11 位,但这就是它变得棘手的地方。这是我的示例参考:

D1--L6000T-4       VALID
D1--L6000T         VALID
D1--L6000T4-----   INVALID
D1--L6000T-----    VALID

我已经用 VALID 注释了应该匹配的那些。我的问题是我的正则表达式采用 all (按预期截断“-”),但第三个 不应该 匹配,因为 4 对第 11 位数字。 我认为它采用 4 的原因是因为第 10 位是可选的,这意味着如果它不存在,我猜 -1 可能是指 [H-RT-ZBD],其中包含几乎相同的字符? 所以我在这里有点迷茫,我的问题是:我怎样才能做到这一点?有没有更简单的方法 ?还能做到吗?

模式规则:

digit number : pattern
1 :   [DA]
2 :   [1-5]
3 :   [V-]
4 :   [AN-]
5 :   [LMFGHN]
6-9 : \d{4}
10 :  [H-RT-ZBD]
11 :  [H-RT-ZBD-]?
12 :  [1-4-]?
13 :  [KRX-]?
14 :  [CPW-]?
15 :  [MT-]?
16 :  [A-C-]?

通常,要匹配的输入字符串是一个包含大量空格和任何字符的普通表格。

【问题讨论】:

  • 当你说“一切都可以是可选的”时,模式是什么样的?在您的第三个示例中,为什么 4 不是第 11 个符号的有效条目?你对这个模式规则有什么具体的解释吗?在我看来,4 个例子还远远不够。
  • +1 因为您清楚地解释了您的问题,发布了有关有效输入和预期输出的信息,以及到目前为止您为解决问题所做的尝试,但没有按预期工作。恭喜,你的问题应该被很多人当作例子!
  • @melwil 规则在正则表达式中,每个括号是一个数字。第 11 位应为 [H-RT-ZBD\-]。但由于它是可选的,因此条件子模式可能会出现意外行为。是的,对于以下数字,我需要更多示例,但如果我连这个数字都达不到,那也没用。
  • (?(-1)…) 修饰符是什么?从未见过这种语法。

标签: php regex


【解决方案1】:

以下正则表达式为您提供的所有规则和输入评估为真。您可以复制整个块并使用它,包括 cmets。

$string = "D1--L6000T4------ A3--L5020MW4---A D4--L4652Z-4---- D1--L6000T";

preg_match_all(
    '/(                  # Matching the start of the group
       [DA]              # Digit 1
       [1-5]             # Digit 2
       [V-]              # Digit 3
       [AN-]             # Digit 4
       [LMFGHN]          # Digit 5
       \d{4}             # Digit 6-9
       [H-RT-ZBD]        # Digit 10
    (?:[H-RT-ZBD-]       # Digit 11
    (?:[1-4-]            # Digit 12
    (?:[KRX-]            # Digit 13
    (?:[CPW-]            # Digit 14
    (?:[MT-]             # Digit 15
       [A-C-]            # Digit 16
    ?)?)?)?)?)?)         # Closing all the groups and alternations
    (?:(?=(\s|%20))|$    # Matching a space (even %20) or end of string. This is done to exclude partial matches.
    )/x', 
    $string, $matches
);

var_dump($matches);

关于我所做更改的几点说明。

删除了字符组内破折号的转义。如果将它放在不标记间隔的地方,它会像任何其他字符一样。

删除了\d周围的字符组[ ]

我没有将第 11 位数字设为可选,而是写出该模式与 11 位以外的模式有何不同。组的递归可选性确保如果第 12 个字符能够匹配,则它需要第 11 个,依此类推。

结束边界

我已将(?:(?=(\s|%20))|$ 添加到正则表达式的末尾,以确保此模式仅在没有以下字符时才会匹配,否则这些字符将成为模式的一部分。当您不能保证每个模式都将由空格分隔时,这样做是在 D1--L6000T4------ 中打折部分匹配(例如 D1--L6000T)的唯一方法。坦率地说,我觉得很奇怪。

检索匹配项

构造正则表达式,以便完整模式可用作匹配部分,或匹配数组中的索引 0。

【讨论】:

  • ^$ 如果模式用于从字符串中提取模式将不起作用,您可以使用 (?:^|[^A-Z])(?:[A-Z]-|$) 代替各自的开始和结束匹配字符串
  • 我的意思是(?:^|[^A-Z])(?:[^A-Z]-|$)
  • 看起来不错!尽管我将首先尝试@Jack 的分而治之替代方案,因为它更易于维护。无论如何,这是一个 +1。
  • 谢谢,但你所要做的就是把我的分成不同的行并添加/x 标志。他没有最后 6 位数字的交替。如果你愿意,我可以为你分行。
  • 实际上,this expression 应该也能正常工作...不要介意 codepad.org 配置错误的 pcre ;-) 无论如何,+1
【解决方案2】:

我猜 -1 可能是指 [H-RT-ZBD],它包含几乎相同的字符?

不,它确实引用了最后一个捕获组 ([H-RT-ZBD\-]?)。然而,它总是匹配,因为该字母是可选的 - 然后捕获空字符串。而且你的条件是真的。

我猜你应该让你的字符捕获组可选而不是捕获一个可选的字符(有关差异,请参阅http://www.regular-expressions.info/captureall.html)。所以试试

[DA][1-5][V-][AN-][LMFGHN]\d{4}[H-RT-ZBD]([H-RT-ZBD-])?(?(-1)([1-4-]))?(?(-1)([KRX-]))?(?(-1)([CPW-]))?(?(-1)([MT-]))?(?(-1)[A-C-])?

如果你不需要捕获组,你可以通过使用更自然的嵌套而不是条件来简化表达式:

[DA][1-5][V-][AN-][LMFGHN]\d{4}[H-RT-ZBD](?:[H-RT-ZBD-](?:[1-4-](?:[KRX-](?:[CPW-](?:[MT-][A-C-]?)?)?)?)?)?

当然,在任何情况下你都必须anchor你的表达式,这样它就不会匹配无效输入的有效子部分:-)你可以将它包装在^+$(?<!\S)+@ 987654330@或(?<=\s|^)+(?=\s|$)

【讨论】:

  • 但是无效的“D1--L6000T4-----”被匹配为“D1--L6000T”,而它根本不应该匹配。
  • @Jack 正确。我很高兴看到我有某种意义。
  • @Shinosha 我建议编写一个匹配整个 16 个字符部分的表达式,然后分别验证每个匹配项。
  • @Jack:是的,但前提是你不锚定表达式(这是我隐含的预期)
  • @Shinosha 因为那样你就可以使用锚定表达式:)
【解决方案3】:

您应该只使用正则表达式来选择可能的模式,以便从原始字符串中提取它们。

在获得选定的潜在模式数组后,使用IFSWITCH 语句,以及substr 和其他字符串比较函数来确定每个模式是否有效。

否则,您可能会编写过于复杂的正则表达式,这将花费很长时间来调试、更新,并且之后没有人愿意使用您的代码。

【讨论】:

  • 如果我这样做,我可以从无效模式中提取有效模式。我不希望这样,因为这最终可能会创建不需要的文章。
  • 这就是您使用条件逻辑来确定所选匹配是否正确的原因 - 这取决于您是否确信您的正则表达式将 100% 正确,或者您是否想在其中添加一些额外的验证逻辑检查它所做的选择,在这种情况下,您可以使您的正则表达式更简单,更易于阅读,(使其更易于更新)并使您的 PHP 逻辑更复杂,使您能够更轻松地评论和记录您的代码,解释每个过程您用于验证输入。
猜你喜欢
  • 2019-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多