正则表达式在 php 中捕获没有空格的重复组

Regex capturing repeating group in php without whitespace

我正在尝试通过 PHP 中的正则表达式解析始终具有以下格式的字符串: FooBar(,[0-9]{7}[0-9A-F]{8})+ 或换句话说,它们有一个开始 value/word 后跟 1 个或多个条目,每个条目是一个逗号 (,),后跟 7 位数字和 8 个十六进制字符(数字或大写字符 A 到 F)。

我的 Regex 捕获这个是 /^C7(,[0-9]{7}[0-9A-F]{8})+$/ 哪种作品。当在 preg_match_all 中使用时,它 returns 是一个包含两个条目的数组,第一个是预期的输入字符串,但是,在第二个数组中只有一个条目,即最后一个匹配的块。 (见示例)

我需要捕获捕获组匹配的所有块。我做了一些研究并找到了这个答案,它似乎是关于同一个问题:, So I've adjusted my regex to /(,[0-9]{7}[0-9A-F]{8})+$/, but I still only get one match. This can be tested at regex101.com。然后我又做了一些实验,发现如果我更改输入字符串,在块之间包含一个 space(或任何不匹配的字符),如下所示:C7,22801422CFE0F63 ,2280141C5EF0F63 ,22801402EFD0F63 ,2280138C5ED0F63 ,228024329897530 ,228023829877530 并调整正则表达式再次 /(,[0-9]{7}[0-9A-F]{8})+/ 它完全按照预期的方式执行!

问题:有没有办法做到这一点,匹配这个循环组中的所有块而不在中间添加白色space?如果是,怎么做?

编辑

说明问题:
无白spacehttps://regex101.com/r/ilkZjD/1

Whitespace/random 个字符 https://regex101.com/r/mimBgz/1

目标:第二个的行为,带有白色spaces,但不添加白色spaces(分别是不匹配的字符).

编辑 2(hacky 解决方案)

我找到了一个解决方案,考虑到这个 Answer. The Regex /(?:,)([0-9]{7}[0-9A-F]{8})/ works for me. https://regex101.com/r/LEEFzv/1。但是我仍然想要一种方法来匹配初始 FooBar。因为这表明传入的字符串应该与这个正则表达式完全匹配。
(我知道我可以简单地检查第二个正则表达式中的字符串,但是我希望将它放在一个正则表达式中)

示例:
输入:'C7,22801422CFE0F63,2280141C5EF0F63,22801402EFD0F63,2280138C5ED0F63,228024329897530,228023829877530'

这是你想要的吗?

$in = 'C7,22801422CFE0F63 ,2280141C5EF0F63 ,22801402EFD0F63 ,2280138C5ED0F63 ,228024329897530 ,228023829877530';

preg_match_all('/(^\w+|\G)\h*(,[0-9]{7}[0-9A-F]{8})/', $in, $m);
print_r($m);

输出:

Array
(
    [0] => Array
        (
            [0] => C7,22801422CFE0F63
            [1] =>  ,2280141C5EF0F63
            [2] =>  ,22801402EFD0F63
            [3] =>  ,2280138C5ED0F63
            [4] =>  ,228024329897530
            [5] =>  ,228023829877530
        )

    [1] => Array
        (
            [0] => C7
            [1] => 
            [2] => 
            [3] => 
            [4] => 
            [5] => 
        )

    [2] => Array
        (
            [0] => ,22801422CFE0F63
            [1] => ,2280141C5EF0F63
            [2] => ,22801402EFD0F63
            [3] => ,2280138C5ED0F63
            [4] => ,228024329897530
            [5] => ,228023829877530
        )

)

解释:

(               : start group 1
  ^\w+          : beginning of line, 1 or more word characters
  |             : O
  \G            : match form this point
)               : end group 1
\h*             : 0 or more horizontal spaces
(               : start group 2
  ,             : a comma
  [0-9]{7}      : 7 digits
  [0-9A-F]{8}   : 8 hexa
)               : end group 2

要捕获包括第一部分在内的所有卡盘,您可以尝试:

(?:FooBar|(?:[0-9]{7}[0-9A-F]{8})+)

说明

  • 非捕获组(?:
  • 匹配FooBar
  • |
  • 您在重复一次或多次的捕获组中格式化(?:[0-9]{7}[0-9A-F]{8})+
  • 关闭非捕获组

    Output

您可以使用 A 标志构建一个模式来获得连续匹配(这意味着 Anchored)。主要的兴趣是您可以提取您的值并使用前瞻性同时检查行的格式:

$pattern = '~
    (?!^)  # fails at the start of the string
    ( \h*,\h* (?<value>[0-9]{7}[A-F0-9]{8}) )
    # the first capture group is useful to shorten the 
    # the lookahead in the second branch.
  |
    (?<first>[a-zA-Z0-9]+)(?=(?1)*$)
~xA';

if ( preg_match_all($pattern, $yourstring, $matches) ) {
    echo $matches['first'][0], PHP_EOL;
    print_r(array_values(array_filter($matches['value'])));
} 

demo

A 标志强制每个匹配项从字符串的开头或前一个匹配项的结尾开始。

第一个分支描述逗号分隔值,第二个分支描述行的开头。

前瞻(?=(?1)*$)向前检查行的结构。如果这个失败,则无法匹配。

ehmmm...也许我无法理解这个问题,但您的正则表达式将适用于第一种情况,删除尾随 +

(,[0-9]{7}[0-9A-F]{8})