【问题标题】:Replace words in html with links, but prefer longer words if search term collide用链接替换 ​​html 中的单词,但如果搜索词冲突,则更喜欢更长的单词
【发布时间】:2020-12-17 13:08:24
【问题描述】:

我在执行以下任务时遇到问题:

我需要通过将它包含的一些单词链接到“阅读更多”页面来丰富包含 html 的字符串。不幸的是,当我要替换的搜索词开始重叠时,它变得很棘手。 我要么以嵌套链接结束,要么像下面的示例中那样,更长的术语不会被替换。

let html = `<p>So there is this Text in HTML containing words.</p>
<p>I want to link some special words to their read more pages.</p>
<p>But if search terms contain each other they re not linked correctly. Like the ones above.</p>`;

const linkTo = [
    {term: 'words', link: 'https://example.com/words'},
    {term: 'special words', link: 'https://example.com/special_words'},
];

for(const pair of linkTo){
    const re = new RegExp(pair.term, "g");
    html = html.replace(re, `<a href="${pair.link}">${pair.term}</a>`);
}

document.body.innerHTML = html;
&lt;html&gt;&lt;body&gt;&lt;/body&gt;&lt;/html&gt;

在上面的例子中,第 2 行的“特殊词”应该链接到它自己的页面。

有什么想法吗?

提前致谢!

【问题讨论】:

  • 您的问题需要澄清。 (对我来说)很难破译你想要完成的事情。
  • @GetSet 其实很清楚。
  • @WiktorStribiżew 我迷路了
  • my answer

标签: javascript html regex


【解决方案1】:

您需要按长度按降序对键进行排序,并根据术语创建一个正则表达式:

let html = `<p>So there is this Text in HTML containing words.</p>
<p>I want to link some special words to their read more pages.</p>
<p>But if search terms contain each other they re not linked correctly. Like the ones above.</p>`;

const linkTo = [
    {term: 'words', link: 'https://example.com/words'},
    {term: 'special words', link: 'https://example.com/special_words'},
];
const keys = linkTo.map(x => x.term).sort((a, b) => b.length-a.length)
const re = new RegExp("\\b(?:" + keys.join("|") + ")\\b", "g");
html = html.replace(re, (m) => `<a href="${linkTo.find(x => m == x.term).link}">${m}</a>`);
document.body.innerHTML = html;
&lt;html&gt;&lt;body&gt;&lt;/body&gt;&lt;/html&gt;

请注意,我暂时不会转义特殊字符,因为您的所有术语都由单词字符组成,这就是我在单词边界两端添加 \b 的原因。

如果您需要搜索可能包含特殊字符的术语,您将需要使用

const keys = linkTo.map(x => x.term.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')).sort((a, b) => b.length-a.length)
const re = new RegExp("(?<!\\w)(?:" + keys.join("|") + ")(?!\\w)", "g");

更多细节:

  • linkTo.map(x =&gt; x.term).sort((a, b) =&gt; b.length-a.length) - 从 linkTo 项目中获取 terms 并按长度按降序对它们进行排序,越长越好。这是必要的,因为The Regex Engine Is Eager 和第一个备选方案“获胜”并使正则表达式引擎停止处理其他备选方案
  • new RegExp("\\b(?:" + keys.join("|") + ")\\b", "g") 构建一个像 \b(?:special words|words)\b 这样的正则表达式
  • .replace(re, (m) =&gt; `&lt;a href="${linkTo.find(x =&gt; m == x.term).link}"&gt;${m}&lt;/a&gt;`) - 只解析一次字符串,并将每个匹配项替换为对应的link

特殊字符支持解决方案:

let html = `<p>So there is this Text in HTML containing words.</p>
<p>I want to link some special words to their read more pages.</p>
<p>But if search terms contain each other they re not linked correctly. Like the ones above.</p>`;

const linkTo = [
    {term: 'words', link: 'https://example.com/words'},
    {term: 'special words', link: 'https://example.com/special_words'},
];
const keys = linkTo.map(x => x.term.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')).sort((a, b) => b.length-a.length)
const re = new RegExp("(\\W|^)(" + keys.join("|") + ")(?!\\w)", "g");
html = html.replace(re, (x,y,z) => `${y}<a href="${linkTo.find(i => z == i.term).link}">${x}</a>`);
document.body.innerHTML = html;

【讨论】:

  • 这似乎工作得很好:) 当我将它部署到设备时,我在创建 RegExp() 的行上得到“SyntaxError:无效的正则表达式:无效的组说明符名称”。你碰巧知道那可能是什么吗?
  • 我正在使用第二个版本的特殊字符。
  • @janrop 你在 Safari 中使用它吗?它不支持lookbehinds。我添加了一个sn-p,请检查。
【解决方案2】:

您可以只使用string.replace() 函数:

let html = `<p>So there is this Text in HTML containing words.</p>
<p>I want to link some special words to their read more pages.</p>
<p>But if search terms contain each other they re not linked correctly. Like the ones above.</p>`;

const linkTo = [
    {term: 'words', link: 'https://example.com/words'},
    {term: 'special words', link: 'https://example.com/special_words'},
];

for(const pair of linkTo){
   html = html.replace(pair.term, `<a href="${pair.link}">${pair.term}</a>`);
}

document.body.innerHTML = html;
&lt;html&gt;&lt;body&gt;&lt;/body&gt;&lt;/html&gt;

【讨论】:

  • 不幸的是,这不会替换全局的单词。我需要替换每个出现的单词。它只适用于意外的示例代码。
猜你喜欢
  • 2014-08-25
  • 2011-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多