动态标签之间的preg_match_all

时间:2016-11-02 00:16:25

标签: php regex preg-match-all

我想抓住每个虚拟主机配置并使用preg_match_all将它们放入一个数组中,这样我就可以从每个配置中提取信息,例如......

$vHostConfig = '    <VirtualHost *:80>
        ServerName localhost
        DocumentRoot c:/wamp/www
        <Directory  "c:/wamp/www/">
           Options +Indexes +Includes +FollowSymLinks +MultiViews
           AllowOverride All
           Require local
        </Directory>
    </VirtualHost>
    <VirtualHost *:8080>
        ServerName testing.com
        DocumentRoot c:/wamp/www/testing.com
        <Directory  "c:/wamp/www/testing.com">
           Options +Indexes +Includes +FollowSymLinks +MultiViews
           AllowOverride All
           Require local
        </Directory>
    </VirtualHost>
    <VirtualHost 127.0.0.1:80>
        ServerName testing2.com
        DocumentRoot c:/wamp/www/testing2.com
        <Directory  "c:/wamp/www/testing2.com">
           Options +Indexes +Includes +FollowSymLinks +MultiViews
           AllowOverride All
           Require local
        </Directory>
    </VirtualHost>
#    <VirtualHost *:80>
#        ServerName testing3.com
#        DocumentRoot c:/wamp/www/testing3.com
#        <Directory  "c:/wamp/www/testing3.com">
#            Options +Indexes +Includes +FollowSymLinks +MultiViews
#            AllowOverride All
#            Require local
#        </Directory>
#    </VirtualHost>';

preg_match_all(<<what to put here>>, $vHostConfig, $vHostConfigMatches);

我想只抓取行开头没有#的活动配置,这意味着我应该有三个以<VirtualHost开头的字符串,并在$ vHostConfigMatches数组中以</VirtualHost>结束。这可能吗?

3 个答案:

答案 0 :(得分:2)

您可以使用此正则表达式:

preg_match_all('/^\h*<VirtualHost.*?>.*?\R\h*<\/VirtualHost>/sm',
               $vHostConfig, $vHostConfigMatches);  

请注意,数组$vHostConfigMatches将具有额外的嵌套级别,因此只需使用reset获取第一个嵌套级别:

print_r(reset($vHostConfigMatches));

答案 1 :(得分:1)

您可以按行拆分: $lines = explode(PHP_EOL, $vhostConfig);

过滤掉所有评论的行: $lines = array_filter($lines, function ($ele) { return substring($ele, 0) != "#"; });

把它放回去: $vhostConfig = implode(PHP_EOL, $lines);

然后使用正则表达式来拉取每个虚拟主机(您可能需要更精确的东西: preg_match_all("@<VirtualHost [\d\.\*:]+>(.*?)</VirtualHost>@", $vhostConfig, $vhostConfigMatches);

未经测试,但应该给你一个想法。这也有利于忽略有效虚拟主机中的任何注释行

答案 2 :(得分:0)

尽管@ trincot的答案工作正常,但它使用.*?(懒惰)量词,使正则表达式引擎高度活跃:这个regex101显示在这个例子中需要950步。

所以我认为,即使它看起来有点复杂,这个简单的PHP代码段也会运行得更快:

$result = array_reduce(
  explode(PHP_EOL, $str),
  function($result, $line) {
    if (trim($line[0]) <> '#') {
      if (strpos($line, '<VirtualHost') !== false) {
        $result[] = $line;
      } else {
        $result[count($result) - 1] .= $line;
      }
    }
    return $result;
  },
  []
);

立刻,它只是:

  • 将原始字符串转换为行数组
  • 删除任何评论
  • 按预期填充所需结果