使用preg替换锚定标记后删除空格

时间:2016-08-17 13:44:20

标签: php regex preg-replace html-parsing

我想在锚标记后加一个空格,以便下一个单词与它分开。问题是有锚标签,之后有 个字符,或者可能有另一个html标签打开。因此,在这些情况下,我们不想放置space,因为它会破坏我们的记录。

如果没有空格且有一个单词,我只想在锚之后放置空格。

现在我已经提出了正则表达式,我不确定这正是我想要的

 preg_replace("/\<\/a\>([^\s<&nbsp;])/", '</a> $1', $text, -1, $count);
 print "Number of occurence in type $type = $count \n";
 $this->count += $count;

我试图在实际保存替换字符串之前查看出现的次数。但它显示出更高的数量,我非常怀疑不能。

请帮我修复这个正则表达式。

方案:

<a href="blah.com">Hello</a>World // Here we need to put space between Hello and World

<a href="blah.com">Hello</a>&nbsp;World // Do not touch this

<a href="blah.com">Hello</a><b>World</b> // do not touch this

可能有很多情况需要忽略,但具体来说我们需要执行第一个方案

3 个答案:

答案 0 :(得分:2)

正如@trincot所指出的那样[^\s<&nbsp;]并不意味着如果它不是空格或不间断的空间。它是一个字符类,这些括号之间的任何东西只有一个字符的平均值。所以它意味着如果它不是space<&或......

您需要检查下一个字符是否为单词\w,表示[a-zA-Z0-9_],然后考虑在使用正向前瞻的零宽度断言中添加空格:

 preg_replace("~</a>\K(?=\w)~", ' ', $text, -1, $count);
 echo "Number of occurrences in type $type is $count \n";

这个RegEx是什么意思?

</a>    # Match closing anchor tag
\K      # Reset match
(?=\w)  # Look if next character is a word character

更新:涵盖所有HTML问题案例的另一种解决方案:

preg_replace("~</a>\K(?!&nbsp;)~", '&nbsp;', $text, -1, $count);

当关闭锚标记后没有不间断的空格时,这会增加一个不间断的空格。

答案 1 :(得分:2)

正如您可能会发现的那样,正则表达式解决方案迟早会证明是不够的。例如,它不会检测到在此HTML代码段中显示的两个单词之间没有空格:

<a>test</a><span>hello</span>

在许多其他情况下,正则表达式解决方案很难检测到相邻的单词,因为HTML的呈现并不像看起来那么简单。

虽然您已经接受了解决方案,但我在此提供了一个解决方案,该解决方案使用PHP中提供的DOMDocument接口来检测链接文本在其后面的文本中的位置,即使它在DOM节点层次结构中与它远程分离:

function separateAnchors($html) {
    // Define a character sequence that 
    // will certainly not occur in your document,
    // and is interpreted as literal in regular expressions:
    $magicChar = "²³²"; 
    $doc = new DOMDocument();
    $doc->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
    $xpath = new DOMXPath($doc);
    $anchors = $xpath->query("//a");
    foreach (array_reverse(iterator_to_array($anchors)) as $anchor) {
        $parent = $anchor->parentNode;
        $origAnchor = $anchor->cloneNode(true);
        // temporariy put the special text in the anchor
        $anchor->textContent = $magicChar;
        // and then take the document's text content
        $txt = $doc->textContent;
        // If that contains the special text with a non-space following it:
        if (preg_match("/{$magicChar}\S/u", $txt)) {
            // ... then add a single space node after it, after
            // any closing parent nodes
            $elem = $anchor;
            while (!$elem->nextSibling) $elem = $elem->parentNode;
            $elem->parentNode->insertBefore($doc->createTextNode(" "), 
                                            $elem->nextSibling);
        }
        // Put original anchor back in place
        $parent->replaceChild($origAnchor, $anchor);
    }
    return $doc->saveHTML();
}

// sample data
$html = "<p><a>first link</a>&nbsp;<a>second link</a>this word is too close</p>\n
         <table><tr><td><a>table cell</a></td></tr></table><span>end</span>\n
         <span><a>link</a></span><span><a>too close</a></span>";

// inject spaces
$html = separateAnchors($html);

// Show result
echo $html;

ideone.com

上查看它

答案 2 :(得分:1)

您可以使用:/(?<=<\/a>)(\w+)/g正则表达式

含义:找到关闭锚标记之前的单词并将其替换为空格并首先捕获组引用($ 1)

Demo and Meaning of each construct used