preg_match_all() 如何处理字符串?

Posted

技术标签:

【中文标题】preg_match_all() 如何处理字符串?【英文标题】:How preg_match_all() processes strings? 【发布时间】:2011-12-11 07:45:03 【问题描述】:

我仍在学习很多关于 php 的知识,而字符串更改是我感兴趣的事情。我以前使用 preg_match 来验证电子邮件地址或搜索查询。

我刚从What's wrong in my regular expression? 这篇帖子中过来,很好奇为什么 preg_match_all 函数会生成 2 个字符串,其中 1 个字符串中的一些字符被剥离,而另一个字符串则产生所需的输出。

根据我对该函数的了解,它使用正则表达式逐个字符地遍历字符串以评估如何处理它。这个 RegEx 的结构是否可以绕过第一个数组条目而只产生所需的结果?

所以你不必去另一个线程

$str = 'text^name1^Jony~text^secondname1^Smith~text^email1^example-
        free@wpdevelop.com~';

preg_match_all('/\^([^^]*?)\~/', $str, $newStr);

for($i=0;$i<count($newStr[0]);$i++)

    echo $newStr[0][$i].'<br>';


echo '<br><br><br>';

for($i=0;$i<count($newStr[1]);$i++)

    echo $newStr[1][$i].'<br>';
 

这将输出

^Jony~^Smith~^example-free@wpdevelop.com~JonySmithexample-free@wpdevelop.com

我很好奇 2 个数组条目的原因是由于字符串的原始语法还是函数的正常处理响应。对不起,如果这不应该在这里,但我真的很好奇它是如何工作的。

谢谢, 布罗迪

【问题讨论】:

输出将始终包含整个匹配项以及表达式中每个捕获组的条目。 不是答案,但值得注意的是PREG_SET_ORDER 标志,它将返回一个更简单的结果列表。虽然您无法删除完整匹配的 [0] 数组条目,但您可以在正则表达式中使用 \K 去除其内容。 【参考方案1】:

当你想象 preg_match_all 的功能有问题时,你应该使用像 preg_match_all tester @ regextester.net 这样的评估器

这会实时向您显示结果,您可以配置结果顺序、元指令、偏移量捕获等内容。

【讨论】:

【参考方案2】:

这个 RegEx 的结构是否可以绕过第一个数组条目而只产生所需的结果?

当然。使用assertions。这个正则表达式:

preg_match_all('/(?<=\^)[^^]*?(?=~)/', $str, $newStr);

结果:

Array
(
    [0] => Array
        (
            [0] => Jony
            [1] => Smith
            [2] => example-free@wpdevelop.com
        )

)

【讨论】:

【参考方案3】:

preg_match_all 结果中的第一个数组返回与您传递给 preg_match_all() 函数的整个模式匹配的字符串,在您的例子中是 /\^([^^]*?)\~/。结果中的后续数组包含模式中括号的匹配项。举个例子可能更容易理解:

$string = 'abcdefg';
preg_match_all('/ab(cd)e(fg)/', $string, $matches);

$matches 数组将是

array(3) 
  [0]=>
  array(1) 
    [0]=>
    string(7) "abcdefg"
  
  [1]=>
  array(1) 
    [0]=>
    string(2) "cd"
  
  [2]=>
  array(1) 
    [0]=>
    string(2) "fg"
  

第一个数组将包含整个模式的匹配项,在本例中为“abcdefg”。第二个数组将包含第一组括号的匹配项,在本例中为“cd”。第三个数组将包含第二组括号的匹配项,在本例中为“fg”。

【讨论】:

【参考方案4】:

正如manual 所述,这是预期的结果(对于默认的PREG_PATTERN_ORDER 标志)。 $newStr 的第一个条目包含所有完整的模式匹配,下一个结果是第一个子模式的所有匹配(在括号中)等等。

【讨论】:

【参考方案5】:

这是 preg_match 和 preg_match_all 的标准行为 - “匹配值”数组中的第一个字符串是正则表达式模式捕获的完整字符串。随后的数组值是“捕获组”,其存在取决于正则表达式模式中() 对的放置/位置。

在您的正则表达式/\^([^^]*?)\~/ 的情况下,完整的匹配字符串将是

^   Jony    ~
|     |     |
^  ([^^]*?) ~   -> $newstr[0] = ^Jony~
                -> $newstr[1] = Jony (due to the `()` capture group).

【讨论】:

啊我明白了,所以它做的第一件事就是找到以 ^ 开头并以 ~ 结尾的文本,然后 () 中的第二个表达式将 ^ 之后的所有内容减去 ~。如果 [^^]*?告诉它在'^'之后抓取文本,为什么它不抓取'~'? 可以,但~ 不在您的捕获组内,因此它只会出现在[0] 部分。您可以将整个正则表达式模式本身视为一个捕获组,以便该虚拟捕获存储在[0] 中,然后您使用() 显式创建的任何捕获进入[1]、[2] 等。 . [^^]*? 以非贪婪的方式 (?) 转换为“尽可能多的字符(*、'0 或更多')不是 ^ ([^^])。跨度> 【参考方案6】:

[0] 包含整个匹配项,而[1] 仅包含一部分(您要提取的部分)... 你可以var_dump($newStr)查看数组结构,你会弄明白的。

$str = 'text^name1^Jony~text^secondname1^Smith~text^email1^example-
        free@wpdevelop.com~';

preg_match_all('/\^([^^]*?)\~/', $str, $newStr);

$newStr = $newStr[1];
foreach($newStr as $key => $value)

    echo $value."\n"; 

这将导致...(奇怪的结果,没有修改表达式)

Jony
Smith
example-
        free@wpdevelop.com

【讨论】:

以上是关于preg_match_all() 如何处理字符串?的主要内容,如果未能解决你的问题,请参考以下文章

如何处理插入 '\0' 的字符数组?

如何处理 JSONDecoder 中的空日期字符串

如何处理此字符串?

Web Api 如何处理这个查询字符串?

开玩笑测试 - 如何处理 JsonWebToken 响应

如何处理 Freemarker 字符串模板?