2017-03-09 136 views
1

我正在PHP中开发一个Telegram Bot,我必须处理字符串,其中只有一些basic HTML tag are allowed和所有<,>&符号不是标记或HTML的一部分实体必须与相应的HTML实体(<&lt;>&gt;&&amp;
例字符串PHP正则表达式负面lookbehind可变长度的替代方案问题

<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< 

我设法取代被替换0和<通过使用正则表达式。例如,我在这种模式<(?!(?:(?:\/?)(?:(?:b>)|(?:strong>)|(?:i>)|(?:em>)|(?:code>)|(?:pre>)|(?:a(?:[^>]+?)?>))))中使用负向视图来摆脱<符号。

但我无法建立一个模式来取代>符号,它不是任何标签的一部分。 PCRE不支持不确定的量词。虽然它允许lookbehinds内部的替代品具有不同的长度,但要求每个替代品具有固定的长度。

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

+0

是会为亚朋友做一个很好的答案。离开,回归一个好的正则表达式解决方案,但看到你已经标记了一个短暂的正则表达式解决方案,永远不会工作。不幸的是,我无法抹去我的答案。当我看到你的名字时,我会更好地知道。 – sln

回答

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; 

然而,由于在计算器上多次表示之前,请考虑使用一个解析器来代替,毕竟这是他们是为了。


解析器的方式可以是:

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

echo $dom->saveHTML(); 

但是,你提出的片段是如此败坏的正则表达式可能是处理它的唯一途径。

+0

谢谢你的回答。我确实尝试过DOM解析器,但没有得到理想的结果。你能告诉我我该怎么做吗? – ManzoorWani

+0

@ManzoorWani:已更新,请参阅答案的结尾。 – Jan

+0

是的,片段预计不会有效,这就是我寻找Regex的原因。无论如何,你给了这个想法如何用正则表达式来处理它。谢谢:) – ManzoorWani

1

你可以找到合法的特殊符号转换为这样的实体。

最重要的是正确解析标签。
免责声明 - 如果你不这样做,没有理由甚至使用正则表达式,它不会工作。

在每场比赛,第0组将包含两种<,>,或&
您可以添加更多的,请参阅正则表达式底部

正则表达式
(?:(?><(?:(?:(?:(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 
)