我正在尝试查找包含域的字符串。我有以下模式:
"|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#中测试了相同的模式,它们给出了正确的结果:
那这里怎么了?
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)之间或子字符串之后可能没有字符串。因此它应该是可选的。
答案 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
是非常快速的工具)。