【问题标题】:PHP: Find substrings, wrap in tags with dynamic attributesPHP:查找子字符串,用动态属性包装标签
【发布时间】:2016-04-29 03:29:54
【问题描述】:

我正在为网站开发词汇表自动工具提示功能。这将允许管理员输入具有相应定义的词汇表术语,然后这些词将被制成可悬停的工具提示触发器,它们出现在前端的任何位置。

这是我正在使用的方法:

所有内容在输出之前通过一个函数进行过滤,该函数使用正则表达式搜索词汇表术语并将它们包装在带有类的标签中,然后由 javascript 拾取以处理工具提示的悬停显示。

我需要它做的,但无法弄清楚的是,还包括适当的定义作为跨度上的标题属性。

这是我目前的代码: (初始数组只是示例,每个数组中还有更多条目)

function glossary_highlight( $content ) {
    $glossary = ['Lorem', 'Ipsum'];
    $definitions = ['Lorem is a type of crocodile', 'Ipsum is a kitchen utensil'];
    $patterns = [];
    foreach ($glossary as $term) {
        $patterns[] = '/\b' . $term . '\b/i';
    }
    $wrapper = '<span class="tooltip" title="XXXX">$0</span>';
    $wrapped = preg_replace($patterns, $wrapper, $content);
    return $wrapped;
}

我需要将 XXXX 替换为 $definitions 数组中的相应条目。我无法在 foreach 循环中执行正则表达式,因为如果定义包含另一个词汇表术语等,它可能会开始在其他跨度的标题中添加跨度。

想要的效果 - 给定“Lorem ipsum dolor sit amet”的 $content,这个函数的返回应该是:

<span class="tooltip" title="Lorem is a type of crocodile">Lorem</span> <span class="tooltip" title="Ipsum is a kitchen utensil">ipsum</span> dolor sit amet

我的第一个想法是:

$wrapper = '<span class="tooltip" title="' . $definitions[$key] . '">$0</span>';

其中 $key 与相关词汇表术语的索引相关,但我不知道如何在 foreach 中使用它。

如果我无法在 PHP 中解决所有问题,我想我只会应用工具提示跨度并将定义数组发送到 javascript 以从那里附加 title 属性,但我宁愿不将基本任务拆分为两个语言...

我确信这里有一个完全简单的答案,但我的大脑不会看到它!有人可以帮忙吗?

编辑:感谢 lampyridae 的帮助,代码如下:

function glossary_highlight( $content ) {
    $glossary = ['Lorem', 'Ipsum'];
    $definitions = ['Lorem is a type of crocodile', 'Ipsum is a kitchen utensil'];
    $patterns = [];
    foreach ($glossary as $term) {
        $patterns[] = '/\b' . $term . '\b/i';
    }
    $wrappers = [];
    foreach ($definitions as $definition) {
        $wrappers[] = '<span class="tooltip" title="' . $definition . '">$0</span>';
    }
    $wrapped = preg_replace($patterns, $wrappers, $content);
    return $wrapped;
}

【问题讨论】:

  • 示范$content
  • 请注意,我认为您的代码在某些情况下可能表现得很愚蠢:即包含单词,特别是复数的单词。如果“horse”在词汇表中,“horses”将被标记为“horses”。如果词汇表中有“sequence”,“consequence”将被标记为“consequence”。
  • 谢谢,我已经更新了正则表达式以使用单词边界来规避这个问题。

标签: php html arrays regex


【解决方案1】:

我看到两个选项:

  1. 为每个学期运行一次 preg_replace。如果文本很长,术语很多,而且这是实时完成的,这可能会成为性能问题。
  2. 提供一系列替换,就像您为模式所做的那样。

我认为 2 号通常会更快且仍然简单。这个想法是像这样构建包装器:

$wrappers = [];
foreach ($definitions as $definition) {
    $wrappers[] = '<span class="tooltip" title="' . $definition . '">$0</span>';
}

...然后使用包装器:

$wrapped = preg_replace($patterns, $wrappers, $content);

【讨论】:

    【解决方案2】:

    我会将您的标记存储在一个关联数组中。它更干净,更容易查看匹配项。

    $words = [
        'lorem' => 'Lorem is a type of crocodile',
        'ipsum' => 'Ipsum is a kitchen utensil',
    ];
    

    然后构建模式。注意这里使用 \b 单词边界锚点,以便我们匹配 lorem 而不是 splorem。

    $patterns = [];
    foreach (array_keys($words) as $word) {
        $patterns[] = '/\b' . $word . '\b/i';
    }
    

    然后使用 preg_replace_callback() 即时生成自定义替换字符串:

    $newContent = preg_replace_callback($patterns, function ($matches) use ($words) {
        return
            '<span class="tooltip" title="' .
            $words[strtolower($matches[0])] .
            '">' . $matches[0] . '</span>';
    }, $content);
    

    【讨论】:

    • 谢谢,这也很有帮助。你是对的,关联数组更好。感谢您向我展示了这种更好的技术。
    猜你喜欢
    • 2013-10-22
    • 1970-01-01
    • 2018-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多