【问题标题】:skipping html tags in php regex在 php 正则表达式中跳过 html 标签
【发布时间】:2016-09-09 02:41:11
【问题描述】:

我是正确英语的坚持者(是的,我知道“坚持”和“正确”是矛盾的)。我已经创建了一个 CMS 用于我公司的网站,但有一件事情真的让我很紧张——在已发布的内容中创建“智能”引用。

我有一个 reg-ex 可以做到这一点,但是当我在副本中遇到 html 标签时遇到了问题。例如,我的 CMS 使用的一个已发布故事可能包含一堆纯文本和一些 HTML 标签,例如链接标签,其中包含我不想更改为“智能”引号的引号,原因很明显.

15 年前,我是 Perl RegEx 的高手,但我在这方面完全是一片空白。我想要做的是处理一个字符串,忽略html标签内的所有文本,用“智能”引号替换字符串中的所有引号,然后返回完整的html标签字符串。

我有一个函数,我拼凑起来处理我在使用 CMS 时遇到的最常见的场景,但我讨厌它丑陋而且一点也不优雅,而且如果出现无法预料的标签,我的解决方案就会完全崩溃。

这是代码(请不要笑,它被撞在一起超过半瓶苏格兰威士忌):

function educate_quotes($string) {
        $pattern = array('/\b"/',//right double
                        '/"\b/',//left double
                        '/"/',//left double end of line
                        "/(\w+)'(\w+)/",//apostrophe
                        "/\b'/",//left single
                        "/'\b/",//right single
                        "/'$/",//right single end of line
                        "/--/"//emdash
                        );

        $replace = array("”",//right double quote
                        "“",//left double
                        "”",//left double end of line
                        "$1"."’"."$2",//apostrophe
                        "’",//left single
                        "‘",//right single
                        "’",//right single end of line
                        "—"//emdash
                        );

        $string =  preg_replace($pattern,$replace,$string);
        //remove smart quotes around urls
        $string = preg_replace("/href=“(.+)”/","href=\"$1\"",$string);
        //remove smart quotes around images
        $string = preg_replace("/src=“(.+?)”/","src=\"$1\" ",$string);
        //remove smart quotes around alt tags
        $string = str_replace('alt=”"','',$string);
        $pat = "/alt=“(.+?)”/is";
        $rep = "alt=\"$1\" ";
        $string = preg_replace($pat,$rep,$string);
        //i'm too lazy to figure out why this artifact keeps appearing
        $string = str_replace("alt=“",'alt="',$string);
        //same thing here
        $string = preg_replace("/” target/","\" target",$string);
        return $string;
    }

就像我说的,我知道代码很难看,我愿意接受更优雅的解决方案。它可以工作,但在未来,如果出现不可预见的标签,它就会崩溃。作为记录,我想重申一下,我并不是想用正则表达式来解析 html 标签。我试图让它在解析字符串中的所有其余文本时忽略它们。

有什么解决办法吗?我已经做了很多在线搜索,但似乎找不到解决方案,而且我对 PHP 的正则表达式实现不够熟悉,这令人震惊。

【问题讨论】:

  • SLaks,我知道这一点,但我认为由于我没有尝试解析 HTML,因此我不需要 XML 解析器。我只是想对一个可能包含 HTML 标签的字符串进行快速而肮脏的操作,同时完全忽略 HTML 标签,这是重点。
  • 作为记录,我也尝试过这个解决方案:$html_reg = '/<+\s*\/*\s*([A-Z][A-Z0-9]*)\b[^>]*\/*\s*>+/i';,它会去除标签,但在我处理字符串后不会保留它们。
  • 现在我在想,也许 XML 解析器是要走的路?比如,加载字符串,将 html 解析为 SimpleXML 对象,然后将字符串放入智能引号正则表达式中,然后保存 XML 并将其返回给调用者。也许?

标签: php html regex quotes smart-quotes


【解决方案1】:

好的。在 Slacks 建议 DOM 解析之后,我有点回答了我自己的问题,但现在我遇到的问题是正则表达式不适用于创建的字符串。这是我的代码:

function educate_quotes($string) {  
        $pattern = array(
            '/"(\w+)"/',//quotes
            "/(\w+)'(\w+)/",//apostrophe
            "/'(\w+)'/",//single quotes
           "/'\b/",//right single
            "/--/"//emdash
        );

        $replace = array(
            "“"."$1"."”",//quotes
            "$1"."’"."$2",//apostrophe
            "’"."$1"."‘",//single quotes
            "‘",//right single
            "—"//emdash
        );

        $xml = new DOMDocument();
        $xml->loadHTML($string);
        $text = (string)$xml->textContent;
        $smart = preg_replace($pattern,$replace,$text);
        $xml->textContent = $smart; 
        $html = $xml->saveHTML();
        return $html;
    }

DOM 解析工作正常;现在的问题是我的正则表达式(我已经从上面的那个改变了,但直到上面的那个已经不能处理创建的新字符串)实际上并没有替换字符串中的任何引号。

此外,当字符串中的 HTML 代码不完善时,我会收到以下烦人的警告:

Warning: DOMDocument::loadHTML() [domdocument.loadhtml]: Unexpected end tag : p in Entity, line: 2 in /home/leifw/now/cms_functions.php on line 418

由于我不能指望记者总是使用完美的 HTML 代码,这也是个问题。

【讨论】:

    【解决方案2】:

    是否可以根据html<>标签进行拆分,然后再拼凑起来?

    $text = "<div sdfas=\"sdfsd\" >ksdfsdf\"dfsd\" dfs </div> <span sdf='dsfs'> dfsd 'dsf ds' </span> ";
    $new_text = preg_split("/(<.*?>)/", $text, -1, PREG_SPLIT_DELIM_CAPTURE);
    echo htmlspecialchars(print_r($new_text, 1));
    

    所以你得到的是:

    Array
    (
        [0] => 
        [1] => <div sdfas="sdfsd" >
        [2] => ksdfsdf"dfsd" dfs 
        [3] => </div>
        [4] =>  
        [5] => <span sdf='dsfs'>
        [6] =>  dfsd 'dsf ds' 
        [7] => </span>
        [8] =>  
    )
    

    然后你可以做的就是将整个东西拼凑在一起,同时使用 preg_replace,如果它没有&lt;&gt;

    【讨论】:

    • 这很有趣。我想我会测试一下,然后告诉你它是如何工作的。
    【解决方案3】:

    使用 A. Lau 的建议,我想我有一个解决方案,结果它实际上是正则表达式,而不是 xml 解析器。

    这是我的代码:

    $string = '<p>"This" <b>is</b> a "string" with <a href="http://somewhere.com">quotes</a> in it. <img src="blah.jpg" alt="This is an alt tag"></p><p>Whatever, you know?</p>';
    
        $new_string = preg_split("/(<.*?>)/",$string, -1, PREG_SPLIT_DELIM_CAPTURE);
    
        echo "<pre>";
        print_r($new_string);
        echo "</pre>";
    
        for($i=0;$i<count($new_string);$i++) {
            $str = $new_string[$i];
            if ($str) {
                if (strpos($str,"<") === false) {
                    $new_string[$i] = convert_quotes($str);
                }
            }
        }
    
        $str = join('',$new_string);
        echo $str; 
    
        function convert_quotes($string) {
            $pattern = array('/\b"/',//right double
                        '/"\b/',//left double
                        '/"/',//left double end of line
                        "/(\w+)'(\w+)/",//apostrophe
                        "/\b'/",//left single
                        "/'\b/",//right single
                        "/'$/",//right single end of line
                        "/--/"//emdash
                        );
    
            $replace = array("&#8221;",//right double quote
                        "&#8220;",//left double
                        "&#8221;",//left double end of line
                        "$1"."&#8217;"."$2",//apostrophe
                        "&#8217;",//left single
                        "&#8216;",//right single
                        "&#8217;",//right single end of line
                        "&#151;"//emdash
                        );
            return preg_replace($pattern,$replace,$string);
        }
    

    该代码输出以下内容:

    数组(

    >     [0] => 
    >     [1] => <p>
    >     [2] => "This" 
    >     [3] => <b>
    >     [4] => is
    >     [5] => </b>
    >     [6] =>  a "string" with 
    >     [7] => <a href="http://somewhere.com">
    >     [8] => quotes
    >     [9] => </a>
    >     [10] =>  in it. 
    >     [11] => <img src="blah.jpg" alt="This is an alt tag">
    >     [12] => 
    >     [13] => </p>
    >     [14] => 
    >     [15] => <p>
    >     [16] => Whatever, you know?
    >     [17] => </p>
    >     [18] => >
    > Whatever, you know?
    

    “This”是一个带有引号的“字符串”。这是一个alt标签

    不管怎样,你知道吗?

    【讨论】:

    • “这是一个 alt 标签”显示在输出中,因为没有名为“blah.jpg”的实际图像,这正是 alt 标签应该做的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-30
    • 1970-01-01
    • 2014-08-23
    • 1970-01-01
    相关资源
    最近更新 更多