简体   繁体   English

PHP:查找子字符串,使用动态属性包装标记

[英]PHP: Find substrings, wrap in tags with dynamic attributes

I'm working on a Glossary auto-tooltip function for a site. 我正在为网站制作词汇表自动工具提示功能。 This will allow the admin to enter Glossary terms with corresponding definitions, then those words will be made into hoverable tooltip triggers anywhere they appear on the front end. 这将允许管理员输入带有相应定义的术语表术语,然后这些单词将在它们出现在前端的任何地方被制作成可移动的工具提示触发器。

Here's the method I'm using: 这是我正在使用的方法:

All content is filtered before output through a function which searches with a regular expression for glossary terms and wraps them in tags with a class that is then picked up by javascript to handle the hover display of the tooltip. 所有内容在通过函数输出之前进行过滤,该函数使用正则表达式搜索词汇表术语并将其包装在带有类的标记中,然后由javascript拾取以处理工具提示的悬停显示。

What I need it to do, and can't figure out, is to also include the appropriate definition as a title attribute on the span. 我需要做的,也无法弄清楚的是,还要在span上包含适当的定义作为title属性。

Here is my code so far: (the initial arrays are just examples, there are many more entries in each) 这是我到目前为止的代码:( 初始数组只是示例,每个数组中有更多条目)

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;
}

I need XXXX to be replaced with the appropriate entry in the $definitions array. 我需要用$ definitions数组中的相应条目替换XXXX。 I can't perform the regular expression within the foreach loop because then it may start adding spans within the titles of other spans if a definition contains another glossary term, etc. 我无法在foreach循环中执行正则表达式,因为如果定义包含另一个词汇表术语,它可能会开始在其他跨度的标题内添加跨度。

The desired effect - given a $content of "Lorem ipsum dolor sit amet", the return from this function should be: 期望的效果 - 给出“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

My first inclination was to do something like: 我的第一个倾向是做一些像:

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

where $key would be relative to the index of the glossary term in question, but I can't figure out how to work that into the foreach. 其中$ key是相对于有问题的词汇表术语的索引,但我无法弄清楚如何将其用于foreach。

If I can't figure it all out in PHP I guess I will just apply the tooltip span and send the definition array to javascript to append the title attribute from there, but I'd rather not split the basic task across two languages... 如果我无法用PHP来解决这个问题,我想我将只应用工具提示范围并将定义数组发送到javascript以从那里附加title属性,但我宁愿不将两个语言的基本任务分开。 。

I'm sure there is a totally simple answer here but my brain will not see it! 我相信这里有一个非常简单的答案,但我的大脑不会看到它! Can anyone help? 有人可以帮忙吗?

EDIT: thanks to lampyridae for his help below the code works as follows: 编辑:感谢萤火虫对他的帮助,下面的代码如下:

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;
}

I see two options: 我看到两个选择:

  1. Run preg_replace once for each term. 为每个术语运行一次preg_replace。 If the texts are long, the terms many and this is done in real time this may become a performance issue. 如果文本很长,那么术语很多并且这是实时完成的,这可能会成为性能问题。
  2. Supply an array of replacements just as you do for patterns. 提供一系列替换,就像您对模式一样。

I think number 2 would be generally faster and still simple. 我认为2号通常会更快,但仍然很简单。 The idea is to build wrappers like so: 我的想法是建立这样的包装器:

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

…then use the wrappers: ...然后使用包装器:

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

I would store your tokens in a single associative array. 我会将你的标记存储在一个关联数组中。 It's just cleaner and much easier to see matches. 它更干净,更容易看到比赛。

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

Then build patterns. 然后构建模式。 Note the use of \\b word boundary anchor here so that we match lorem but not splorems. 注意在这里使用\\ b字边界锚点,以便我们匹配lorem但不匹配splorems。

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

Then use preg_replace_callback() to generate a custom replacement string on the fly: 然后使用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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM