【问题标题】:PHP: Can preg_match include unmatched groups?PHP:preg_match 可以包含不匹配的组吗?
【发布时间】:2017-05-11 10:24:49
【问题描述】:

preg_match() 函数能否包含它在匹配数组中找不到的组?

这是我正在使用的模式:

/^([0-9]+)(.[0-9]+)?\s?([^iIbB])?([iI])?([bB])?$/

我正在尝试将人类可读的大小解析为字节。此模式符合我的要求,但前提是我可以按绝对组顺序检索匹配项。

这可以生成最多 5 个匹配组,这将产生一个索引为 0-5 的匹配数组。但是,如果字符串不匹配所有组,则匹配数组可能具有,例如,组 5 实际上在索引 3 处。

我想要的是该模式 (5) 中的最终匹配始终位于匹配数组的相同索引处。因为多个组是可选的,所以在读取匹配数组时我们知道表达式中的哪个组被匹配是非常重要的。

示例情况:regexr.com 的正则表达式测试器将始终以正确的顺序显示所有 5 个组,包括那些不匹配的组。通过启用“全局”和“多行”标志并使用以下文本,您可以将鼠标悬停在蓝色匹配项上以获得良好的视觉效果。

500.2 KiB
256M
700 Mb
1.2GiB

您会注意到并非所有组都始终匹配,但是组索引始终处于正确的顺序。


编辑:是的,我已经在 PHP 中尝试过以下操作:

$matches    = [];
$matchesC   = 0;
$matchesN   = 6;
if (!preg_match("/^([0-9]+)(\.[0-9]+)?\s?([^iIbB])?([iI])?([bB])?$/", $size, $matches) || ($matchesC = count($matches)) < $matchesN) {
    print_r($matches);
    throw new \Exception(sprintf("Could not parse size string. (%d/%d)", $matchesC, $matchesN));
}

$size 为“256M”时,print_r($matches); 返回:

Array
(
    [0] => 256M
    [1] => 256
    [2] => 
    [3] => M
)

缺少第 4 组和第 5 组。

【问题讨论】:

  • 你在 PHP 中测试过吗?见ideone.com/NSm7Iy,所有“空”组都在那里。
  • 是的。匹配数组的 print_r() 不包含不匹配的组,导致匹配组的索引倾斜。
  • 是的,它不显示最后的项目,but they are there。您只需使用empty($m[n]) 检查组是否为空。还是print_r 必须打印空组值?
  • 我想这只是一些额外的工作来迭代到预期的数组大小并执行array_key_exists() 来填充空值。 Kidna 期望 preg_match() 开箱即用。
  • 有一个有趣的事实:在 PHP 中,未参与的组只是没有用空字符串值初始化,因此,组 4 和组 5 是 null,你看起来是对的,这都怪preg_match

标签: php preg-match


【解决方案1】:

未参与的组在 PHP 中只是没有用空字符串值初始化,因此,在 '256M' 字符串的情况下,组 4 和 5 为 nullpreg_match 似乎从数组末尾丢弃了那些未初始化的值。

在你的情况下,你可以让你的捕获组不可选,但里面的模式是可选的。

$arr = array('500.2 KiB', '256M', '700 Mb', '1.2GiB');
foreach ($arr as $s) {
    if (preg_match('~^([0-9]+)(\.[0-9]+)?\s?([^ib]?)(i?)(b?)$~i', $s, $m)) {
        print_r($m) . "\n";
    }
}

输出:

Array
(
    [0] => 500.2 KiB
    [1] => 500
    [2] => .2
    [3] => K
    [4] => i
    [5] => B
)
Array
(
    [0] => 256M
    [1] => 256
    [2] => 
    [3] => M
    [4] => 
    [5] => 
)
Array
(
    [0] => 700 Mb
    [1] => 700
    [2] => 
    [3] => M
    [4] => 
    [5] => b
)
Array
(
    [0] => 1.2GiB
    [1] => 1
    [2] => .2
    [3] => G
    [4] => i
    [5] => B
)

请参阅PHP demo

【讨论】:

  • 我确定我已经用 var_dump() 检查了具有空值的键,哦,好吧。使组非可选工作,但不是通过将? 移动到组中。相反,我使用了这种模式:/^([0-9]+)\.?([0-9]*)\s?([^iIbB]*)([iI]*)([bB]*)$/ -- 旁注:我需要区分大小写,因为“m”和“M”在 IEC 功率因数中具有不同的含义。
  • 是的,正如我所说,您将模式设为可选。 * 也是一个量词,允许匹配原子的 0 次出现。请注意我的正则表达式 不区分大小写 - 请参阅 ~i。另外,我相信您可以使用(?:\.?([0-9]+))? 而不是\.?([0-9]*)
  • 很奇怪,每个组内的 ? 运算符不起作用。 (我希望它会。)
  • 可以,看我的演示。
【解决方案2】:

您可以使用T-Regx,它可以轻松处理此类情况!它总是检查一个组是否匹配,即使它是最后一个并且不匹配。它还可以区分""(匹配为空)或null(不匹配):

pattern('^([0-9]+)(.[0-9]+)?\s?([^iIbB])?([iI])?([bB])?$')
    ->match($size)
    ->first(function (Match $match) {

        // whether the group was used in a pattern
        $match->hasGroup(14);   

        // whether the group was matched, even if last or empty string
        $match->matched(5);

        // group, or default value if not matched
        $match->group(5)->orReturn('unmatched');     
    });

【讨论】:

    猜你喜欢
    • 2021-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-30
    • 2011-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多