PHP正则表达式负向后观变量长度替代问题

时间:2017-03-09 15:57:29

标签: php regex regex-lookarounds telegram-bot php-telegram-bot

我在PHP中开发Telegram Bot,我必须处理只有Edgar F. Codd和所有<>&符号的字符串不是标记的一部分,HTML实体必须替换为相应的HTML实体(< &lt;> &gt;& &amp;
示例字符串

<b>bold</b>, <strong>bold</strong>
<i>italic</i>, <em>italic</em>
<a href="http://www.example.com/" >inline URL</a>
<code>inline fixed-width code</code>
<pre>pre-formatted fixed-width code block</pre>
yes<b bad<>b> <bad& hi>;<strong >b<a<

我设法使用Regex替换&<。例如,我在此模式<(?!(?:(?:\/?)(?:(?:b>)|(?:strong>)|(?:i>)|(?:em>)|(?:code>)|(?:pre>)|(?:a(?:[^>]+?)?>))))中使用否定前瞻来摆脱<符号。

但是我无法构建模式来替换不属于任何标记的>符号。 PCRE不支持无限量词。虽然它允许外观内部的替代品具有不同的长度,但要求每个替代品具有固定的长度。

所以,我尝试使用这种模式(仍然不完整)(?<!(?:(?:<b)|(?:<strong)|(?:<i)|(?:<em)|(?:<code)|(?:<pre>)|(?:<a)))>,其中所有替代品都有固定的长度,但它仍然说Compilation failed: lookbehind assertion is not fixed length

2 个答案:

答案 0 :(得分:1)

正确的答案是使用DOM解析器。对于快速而肮脏(有时更快)的方法,您可以使用(*SKIP)(*FAIL)实现的PCRE机制:

<[^<>&]+>(*SKIP)(*FAIL)|[<>&]+

a demo on regex101.com

<小时/> 完整的PHP演练将是:

<?php
$string = <<<DATA
<b>bold</b>, <strong>bold</strong>
<i>italic</i>, <em>italic</em>
<a href="http://www.example.com/" >inline URL</a>
<code>inline fixed-width code</code>
<pre>pre-formatted fixed-width code block</pre>
yes<b bad<>b> <bad& hi>;<strong >b<a<
DATA;

$regex = '~<[^<>&]+>(*SKIP)(*FAIL)|[<>&]+~';
$string = preg_replace_callback($regex,
    function($match) {
        return htmlentities($match[0]);
    },
    $string);

echo $string;
?>

哪个收益率:

<b>bold</b>, <strong>bold</strong>
<i>italic</i>, <em>italic</em>
<a href="http://www.example.com/" >inline URL</a>
<code>inline fixed-width code</code>
<pre>pre-formatted fixed-width code block</pre>
yes&lt;b bad&lt;&gt;b&gt; &lt;bad&amp; hi&gt;;<strong >b&lt;a&lt;

然而,正如之前在StackOverflow上多次提到的那样,考虑使用解析器,而不是之后的所有内容。

<小时/> 解析器方式可以是:

$dom = new DOMDocument();
$dom->loadHTML($string, LIBXML_HTML_NOIMPLIED | LIBXML_NOERROR);

echo $dom->saveHTML();

但是,您呈现的代码段已损坏,因此正则表达式可能是处理它的唯一方法。

答案 1 :(得分:1)

您可以找到要转换为此类实体的合法特殊符号。

最重要的是正确解析标签 免责声明 - 如果您不按照以下方式执行操作,则没有理由使用正则表达式,它将无效。

在每场比赛中,组0将包含&lt;,&gt;或&amp;
您可以添加更多内容,请参阅底部的正则表达式

正则表达式 (?:(?><(?:(?:(?:(script|style|object|embed|applet|noframes|noscript|noembed)(?:\s+(?>"[\S\s]*?"|'[\S\s]*?'|(?:(?!/>)[^>])?)+)?\s*>)[\S\s]*?</\1\s*(?=>))|(?:/?[\w:]+\s*/?)|(?:[\w:]+\s+(?:"[\S\s]*?"|'[\S\s]*?'|[^>]?)+\s*/?)|\?[\S\s]*?\?|(?:!(?:(?:DOCTYPE[\S\s]*?)|(?:\[CDATA\[[\S\s]*?\]\])|(?:--[\S\s]*?--)|(?:ATTLIST[\S\s]*?)|(?:ENTITY[\S\s]*?)|(?:ELEMENT[\S\s]*?))))>)(*SKIP)(*FAIL)|[<>]|[&](?!(?i:[a-z]+|(?:\#(?:[0-9]+|x[0-9a-f]+)));))

解释

 (?:
      (?>                           # Atomic group
           <                             # Match tag forms and fail them with skip / fail verbs ( see below )
           (?:
                (?:
                     (?:
                                                        # Invisible content; end tag req'd
                          (                             # (1 start)
                               script
                            |  style
                               #|  head
                            |  object
                            |  embed
                            |  applet
                            |  noframes
                            |  noscript
                            |  noembed 
                          )                             # (1 end)
                          (?:
                               \s+ 
                               (?>
                                    " [\S\s]*? "
                                 |  ' [\S\s]*? '
                                 |  (?:
                                         (?! /> )
                                         [^>] 
                                    )?
                               )+
                          )?
                          \s* >
                     )

                     [\S\s]*? </ \1 \s* 
                     (?= > )
                )

             |  (?: /? [\w:]+ \s* /? )
             |  (?:
                     [\w:]+ 
                     \s+ 
                     (?:
                          " [\S\s]*? " 
                       |  ' [\S\s]*? ' 
                       |  [^>]? 
                     )+
                     \s* /?
                )
             |  \? [\S\s]*? \?
             |  (?:
                     !
                     (?:
                          (?: DOCTYPE [\S\s]*? )
                       |  (?: \[CDATA\[ [\S\s]*? \]\] )
                       |  (?: -- [\S\s]*? -- )
                       |  (?: ATTLIST [\S\s]*? )
                       |  (?: ENTITY [\S\s]*? )
                       |  (?: ELEMENT [\S\s]*? )
                     )
                )
           )
           >
      )                             # End atomic group
      (*SKIP)(*FAIL)

   |                              #or, 
      [<>]                          # Angle brackets

   |                              #or, 
      [&]                           # Ampersand 
      (?!                           # Only if not an entity
           (?i:
                [a-z]+ 
             |  (?:
                     \#
                     (?:
                          [0-9]+ 
                       |  x [0-9a-f]+ 
                     )
                )
           )
           ;     
      )

      # Add more here
 )