【问题标题】:Removing spaces after anchor tag with preg replace使用 preg 替换锚标记后删除空格
【发布时间】:2016-08-17 13:44:19
【问题描述】:

我想在锚标记后放置一个空格,以便下一个单词与它分开。问题是有锚标记,之后有   字符,或者可能有另一个 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

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

【问题讨论】:

  • 那里有错误,但他们没有解释更高的计数。您能否提供一个大小有限但足以说明问题的示例文本 (html)?
  • 实际上我现在没有实际的文本,因为它完全基于我们的假设。让我们这样说吧。如果有任何人类语言单词可能是英语,泰国,并且锚点关闭和那个单词之间没有空格。我们必须在那里放置一个空格,以便它成为实际的单词。除此之外,请忽略它们
  • 只要意识到下一个单词可以包裹在span这样的标签中,并且仍然坚持前一个单词,因此排除&lt;并不总是有效。其次,在正则表达式类中,您不能测试字符串,只能测试单个字符。所以对&amp;nbsp; 的测试也将排除nb、...等。
  • @trincot 请查看更新部分。我了解span 部分,但现在我们可以跳过这部分,因为我们知道这样的情况很少。
  • &lt;\/\w+&gt;(\w+) 有什么问题?

标签: php regex preg-replace html-parsing


【解决方案1】:

正如@trincot 指出的那样,[^\s&lt;&amp;nbsp;] 并不意味着 如果它不是空格或不间断空格。它是一个字符类,这些括号之间的内容仅表示单个字符。所以这意味着如果它不是space&lt;&amp; 或...

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

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

这个正则表达式是什么意思?

</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);

这会在关闭锚标记后没有不间断空格时添加一个不间断空格。

【讨论】:

  • 但是你在哪里处理特定的 标签?
  • 我将其更改为仅包含锚标记。 @RaheelKhan
  • 而只是确认~ 意味着与正则表达式的开始和结束相同?
  • 是的,它是允许的delimiters 之一。 @RaheelKhan
  • 也非常感谢您的回答和解释
【解决方案2】:

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

<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 上运行

【讨论】:

  • 太棒了.. 它比正则表达式快吗?在输出中,我看到了一些差异,例如在 &lt;/div&gt;&lt;/td&gt; 前面放置了一个空格
  • 它可能会在关闭标签(如&lt;/div&gt;&lt;/table&gt;)之前添加一个空格,这些标签是块元素,并且已经生成自然中断(除非它们的默认样式被 CSS 覆盖!),但我认为无论如何添加空间不会有什么坏处。或者,可以在紧随其后的最后一个结束标记之后插入空格,但这需要更多代码。不,我认为这不会比简单的正则表达式解决方案运行得更快,但是众所周知,用于 HTML 解析的正则表达式通常是不够的。见this famous answer on that
  • 明白你的意思。它有点学习曲线,但很高兴知道谢谢:)
  • 已知用于 HTML 解析的正则表达式不足 再次,这不称为解析。
  • @RaheelKhan,我更新了代码以在任何结束标记后注入空格,以回应您对 &lt;/div&gt;&lt;/td&gt; 的评论。
【解决方案3】:

你可以使用:/(?&lt;=&lt;\/a&gt;)(\w+)/g正则表达式

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

Demo and Meaning of each construct used

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-08
    • 2015-08-07
    • 2013-08-16
    • 1970-01-01
    相关资源
    最近更新 更多