preg_replace多行匹配但保留新行

时间:2017-10-30 20:13:42

标签: php regex preg-replace text-processing

我需要一个可以从HTML文件修剪PHP的内衬。诀窍在于我还需要它来保留以前由PHP行占用的新行。

php -r "echo preg_replace('/<\\\\?.*(\\\\?>|\$)/Us','', file_get_contents(\$argv[1]));" -- "./index.php"

这“有效”但不保留新行,例如:

<html><?php test(); ?>
  <head>
    <?php test();

    ?>
  </head>
  <body>
  </body>
<html>

解析为:

<html>
  <head>

  </head>
  <body>
  </body>
<html>

但我需要它来解决:

<html>
  <head>



  </head>
  <body>
  </body>
<html>

也许我正在使用锤子驱动螺丝,但我想要做的是删除PHP代码,通过htmlhint运行结果并使报告的行号实际上与文件中的行匹配。

如果有更好的解决方案,我很乐意听到。最终目标是将具有PHP,Javascript和HTML混合的文件与各自的链接组合在一起。

2 个答案:

答案 0 :(得分:2)

正则表达式绝对不是这个问题的最佳答案,但是因为您正在以正则表达式形式寻找答案,所以您拥有它!

注意:如果评论或字符串包含<?,则会中断。

代码

See this regex in use here

(?:\G(?!\A)|\h*(?=<\?))(.*(?=(?:(?!<\?)[\s\S])*?(?<=\?>)))

结果

输入

<html><?php test(); ?>
  <head>
    <?php test();

    ?>
  </head>
  <body>
  </body>
<html>

输出

<html>
  <head>



  </head>
  <body>
  </body>
<html>

说明

  • (?:\G(?!\A)|\h*(?=<\?))匹配以下任一选项
    • \G(?!\A)
      • \G在上一场比赛结束时断言位置或第一场比赛的字符串开头
      • (?!\A)否定前瞻声明后面的内容不是字符串的开头(这基本上使\G仅匹配上一个匹配的结尾)
    • \h*(?=<\?)符合以下条件
      • \h*匹配任意数量的水平空格(用于在<?
      • 之前清理空格
      • (?=<\?)确定以下匹配的积极前瞻
        • <字面匹配小于<字符
        • \?字面上匹配问号字符?
  • (.*(?=(?:(?!<\?)[\s\S])*?(?<=\?>)))将以下内容捕获到捕获组1中
    • .*任意次数匹配任何字符(行终止符除外)
    • (?=(?:(?!<\?)[\s\S])*?(?<=\?>))确定后续匹配的正向前瞻
      • (?:(?!<\?)[\s\S])*?匹配以下任意次数,但尽可能少
        • (?!<\?)否定前瞻确保后续内容不匹配
          • <字面匹配小于<字符
          • \?字面上匹配问号字符?
        • [\s\S]匹配任何字符
      • (?<=\?>)负面的背后隐藏确保先于什么匹配以下内容
        • \?字面上匹配问号字符?
        • >字面匹配大于>字符

答案 1 :(得分:0)

使用tokenizer (内部丑陋的东西)

确定一行
php -r 'echo array_reduce(token_get_all(file_get_contents($argv[1])),function($c,$i){return $i[0]==321?$c.$i[1]:$c.str_repeat("\n",@count_chars($i.$i[1])[10]);});'

demo

标记化程序的优点:即使像"abc <?php echo '?>'; ?> def"这样的字符串也能正确解析。

321是常量T_INLINE_HTML的值(所有不在php标记之间)。

10是换行符(LF)的ASCII码。 (默认情况下,count_chars返回一个关联数组,其中ASCII代码为键,出现次数为值)

丑陋的东西是$i.$i[1],它将数组与字符串或带有未定义内容的字符串连接起来。 @避免发出警告和通知。无论如何,这个技巧避免了测试,并且保留了换行符的数量。 (请参阅返回token_get_all以了解问题的原因)。

DOMDocument

php -r '$d=DOMDocument::loadHTMLFile($argv[1],8196);foreach((new DOMXPath($d))->query("//processing-instruction()")as$p)$p->parentNode->replaceChild($d->createTextNode(preg_replace("~\S+~","",$p->nodeValue)),$p);echo$d->saveHTML();'