【问题标题】:XPath contains() Search for Exact MatchXPath contains() 搜索精确匹配
【发布时间】:2013-09-15 03:43:51
【问题描述】:

是否可以使用 fn:contains 搜索 DOMDocument 对象并仅在单词完全匹配时返回 true?

我有一个文本替换 sn-p,它不是我自己编写的,它对关键字进行内部链接替换。但正如所写,它也替换了部分单词而不是仅替换完整单词。

这里是sn-p:

$autolinks = $this->config->get('autolinks');
if (isset($autolinks) && (strpos($this->data['description'], 'iframe') == false) 
        && (strpos($this->data['description'], 'object') == false)):
    $xdescription = mb_convert_encoding(html_entity_decode($this->data['description'], ENT_COMPAT, "UTF-8"), 'HTML-ENTITIES', "UTF-8"); 
    libxml_use_internal_errors(true);
    $dom = new DOMDocument;             
    $dom->loadHTML('<div>'.$xdescription.'</div>');             
    libxml_use_internal_errors(false);
    $xpath = new DOMXPath($dom);
    foreach ($autolinks as $autolink):
        $keyword    = $autolink['keyword'];
        $xlink  = mb_convert_encoding(html_entity_decode($autolink['link'], ENT_COMPAT, "UTF-8"), 'HTML-ENTITIES', "UTF-8");
        $target     = $autolink['target'];
        $tooltip    = isset($autolink['tooltip']);                          
        $pTexts     = $xpath->query(
            sprintf('///text()[contains(., "%s")]', $keyword)
        );
        foreach ($pTexts as $pText):
            $this->parseText($pText, $keyword, $dom, $xlink, $target, $tooltip);
        endforeach;
    endforeach;
    $this->data['description'] = $dom->saveXML($dom->documentElement);
endif;

例如:

如果我的关键字是“massage”*massage*r 部分匹配并转换为链接,此时只应转换整个词按摩,而不是按摩器。

【问题讨论】:

  • 示例 xml 会很有用。您有哪些输入会产生错误的输出?您想要更改的输入是什么?
  • 对不起,我不明白你在问什么。我需要知道如何仅在上面的 $xpath-&gt;query(sprintf('///text()[contains(., "%s")]', $keyword)); 部分中匹配整个单词。正如我所说,输入 ie: $keyword 变量将是“massage”,错误的输出是“massager”这个词只链接在“massager”这个词上,而结尾“r”作为纯文本保持未链接。 “massager”这个词根本不应该匹配,因为它不是确切的关键字。
  • xml 节点中的按摩 这是一个包含单词按摩的句子。 匹配吗?或者是 massage 形式的所有匹配项
  • 是的,$this-&gt;data['description'] 是一个文本块,一个产品的描述。所以是的,&lt;Tagname&gt;This is a sentence containing the word massage.&lt;/Tagname&gt; 是匹配的,但目前&lt;Tagname&gt;This is a sentence containing the word massager.&lt;/Tagname&gt; 也是如此,这是我想要消除的。

标签: php regex xpath


【解决方案1】:

matches()ends-with()不支持时,可以使用starts-with()string-length()绕过。

例子:

[starts-with(.,'$var') and string-length(.)=string-length('$var')]

这相当于matches()

【讨论】:

  • 这让我免于数小时的头痛。谢谢
【解决方案2】:

这实际上非常简单,我只是在 $keyword 变量的末尾添加了一个空格,所以现在它只有在找到整个单词时才返回 true。

foreach ($autolinks as $autolink):
    $keyword    = trim($autolink['keyword']) . ' ';
    $xlink      = mb_convert_encoding(html_entity_decode($autolink['link'], ENT_COMPAT, "UTF-8"), 'HTML-ENTITIES', "UTF-8");
    $target     = $autolink['target'];
    $tooltip    = isset($autolink['tooltip']);                          
    $pTexts     = $xpath->query(
        sprintf('///text()[contains(., "%s")]', $keyword)
    );
    foreach ($pTexts as $pText):
        $this->parseText($pText, $keyword, $dom, $xlink, $target, $tooltip);
    endforeach;
endforeach;

感谢所有试图提供帮助的人。

【讨论】:

    【解决方案3】:

    XSLT 1.0 中的文本操作非常有限,但如果您不能迁移到 2.0(为什么不呢?),那么translate() 经常会来救援。使用translate() 将所有常用标点字符替换为空格,使用concat() 在前后添加一个空格,然后测试contains(' massage ')(注意空格)。

    【讨论】:

    • XSLT 2.0 在我能找到的 PHP 中不可用。你有如何使用translate()的例子吗?
    • 如果您对 XSLT 很感兴趣——例如,如果您编写的 XSLT 比 PHP 多——那么值得研究调用 Java XSLT 处理器的解决方案,例如。通过 HTTP。 translate() 的例子——是的,我的书中有很多例子。
    【解决方案4】:

    您应该使用 fn:matches 而不是 fn:contains。这允许您使用正则表达式进行匹配。然后你可以用 \b 包含单词边界。

    sprintf('///text()[matches(., "\b%s\b")]', $keyword)
    

    请注意,这不会影响您的函数 parseText 正在执行的任何操作。所以虽然&lt;Tagname&gt;This is a sentence containing the word massager.&lt;/Tagname&gt; 不会受到影响,但我不保证&lt;Tagname&gt;The massager give the customer a massage.&lt;/Tagname&gt; 会发生什么。为确保正确处理,您的 parsetext 函数将需要修改。可能采用与上述类似的方式。

    另请注意,您可能需要对 parsetext 进行修改意味着上述更改变得不必要。

    【讨论】:

    • 显然 fn:matches 在 XSLT 1.0 / XPATH 1.0 中不可用,XSLT 2.0 在 PHP 中不可用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    • 2018-08-23
    • 2020-03-06
    • 1970-01-01
    • 2017-01-09
    相关资源
    最近更新 更多