preg_match_all找不到所有匹配项

时间:2018-09-17 12:27:26

标签: php regex

我正在尝试查找包含域的字符串。我有以下模式:

"|s:\\d+:\\\\\"((?:.(?!s:\\d+))+?){$domain}(.+?)\\\\\";|"

这个(模式)似乎可以工作,但是我只得到PHP中的前两个匹配项。

$filename = "caciki_tr.sql";
$domain   = "caciki.com.tr";

$domain   = escape($domain, ".");

$content = file_get_contents($filename);

$pattern = "|s:\\d+:\\\\\"((?:.(?!s:\\d+))+?){$domain}(.+?)\\\\\";|";

preg_match_all($pattern, $content, $matches, PREG_SET_ORDER);
print_r($matches);

function escape($string, $chars) {
    $chars = str_split($chars);
    foreach ($chars as $char) {
        $string = str_replace($char, "\\{$char}", $string);
    }
    return $string;
}

Array
(
    [0] => Array
        (
            [0] => s:121:\"/home/caciki/domains/caciki.com.tr/public_html/wp-content/themes/rafine/woocommerce/single-product/product-thumbnails.php\";
            [1] => /home/caciki/domains/
            [2] => /public_html/wp-content/themes/rafine/woocommerce/single-product/product-thumbnails.php
        )

    [1] => Array
        (
            [0] => s:81:\"/home/caciki/domains/caciki.com.tr/public_html/wp-content/themes/rafine/style.css\";
            [1] => /home/caciki/domains/
            [2] => /public_html/wp-content/themes/rafine/style.css
        )

)

仅当我修改目标文件时,我才获得所有匹配项(11)。一定是在破坏模式/ PHP。

我已经在Python和C#中测试了相同的模式,它们给出了正确的结果:

enter image description here

enter image description here

那这里怎么了?

caciki_tr.sql(目标文件)


更新:此处的模式用于不同的子字符串(例如,域,URL,用户名等)。并非目标文件中的所有字符串都遵循相同的模式。例如,URL模式应该能够匹配以下内容:

$url = "http://[DOMAIN_OMITTED]/~caciki";
$pattern = "|s:\d+:\\\\\"([^s]*(?:s(?!:\d)[^s]*)*){$url}(.+?)\\\\\";|";

s:28:\"http://[DOMAIN_OMITTED]/~caciki\";
s:28:\"<a href=\"http://[DOMAIN_OMITTED]/~caciki\">some page</a>\";

简而言之,s:28:\"和子字符串($ url)之间或子字符串之后可能没有字符串。因此它应该是可选的。

1 个答案:

答案 0 :(得分:2)

当前模式效率很低,因为它包含损坏的"tempered greedy token"(?:.(?!s:\d+))+?。如果您想在生产中使用这种正则表达式,这是一个效率很低的构造,应“解开”。

您可以使用[^s]*(?:s(?!:\d)[^s]*)*代替

"|s:\d+:\\\\\"([^s]*(?:s(?!:\d)[^s]*)*)$domain(.+?)\\\\\";|'
               ^^^^^^^^^^^^^^^^^^^^^^^

详细信息

  • [^s]*-除s以外的0多个字符
  • (?:-非捕获组重复...
    • s(?!:\d)-s后没有: +数字
    • [^s]*-除s以外的0多个字符
  • )*-零次或多次。

请注意,如果您打算使用大文件,请确保您的模式尽可能高效。另外,如果您要使用大文件,here是一个有趣的解决方案(pcregrep是非常快速的工具)。