【问题标题】:Replace words except the ones inside braces替换除了大括号内的单词
【发布时间】:2021-09-20 12:20:26
【问题描述】:

我有一个这样的降价字符串 Status of app [TODO app](url.com/apps/list?appid=q1w2e3) has been changed to completed.
我想用<mark></mark> 包装搜索到的单词(见下面的函数),但跳过链接(url.com/apps/list?appid=q1w2e3) 所以我会有TODO <mark>app</mark> 但不是url.com/<mark>app</mark>s/list?<mark>app</mark>id=q1w2e3

我怎样才能做到这一点?

我用来添加marks的代码:

const garbage = /[|\\{}()[\]^$+*?.]/g;

const highlightMarkdown = (originalString = '', highlight = '') => {
  highlight = highlight.trim();
  if (!highlight) return originalString;

  const wordsToFind = highlight.replace(garbage, '').split(' ');

  const result = wordsToFind.reduce((result, word) => {
    const re = new RegExp(`(${word})`, 'gi');

    return result.replace(re, (word) => `<mark>${word}</mark>`);
  }, originalString);

  return result;
};

const result = highlightMarkdown(
  `Status of app [TODO app](url.com/apps/list?appid=q1w2e3) has been changed to completed.`,
  'app'
);

console.log(result);

UPD 我正在尝试mark不仅app而且&lt;mark&gt;app&lt;/mark&gt;s,因为这个功能是供用户搜索

【问题讨论】:

  • 您应该在 DOM 级别执行此操作,您已将此 Markdown 呈现为 HTML。
  • const re = new RegExp(`(\\[^\\][]*]\\([^()]*\\))|${word}`, 'gi'); 然后return result.replace(re, (x,y) =&gt; y || `&lt;mark&gt;${x}&lt;/mark&gt;`);
  • @CBroe 我会尝试,我不会找到更好的解决方案(因为我使用 React)
  • @wiktor-stribiżew 不起作用:(
  • const re = new RegExp(`(\\[[^\\][]*]\\([^()]*\\))|${word}`, 'gi'); return result.replace(re, (x,y) =&gt; y || `&lt;mark&gt;${x}&lt;/mark&gt;`); 有效。 [ 不见了。

标签: javascript regex algorithm replace markdown


【解决方案1】:

确保单词前面/后面没有字母数字,也没有某些特定字符(如/&amp;=-)可能就足够了。

此外,您可以使用 one 正则表达式执行此操作,并且不需要回调作为 replace 调用的参数。您可以使用反向引用$&amp;

const garbage = /[|\\{}()[\]^$+*?.]/g;

const highlightMarkdown = (originalString = '', highlight = '') => {
  highlight = highlight.trim().replace(garbage, '');
  if (!highlight) return originalString;

  const wordsToFind = highlight.replace(/ /g, '|');
  const re = new RegExp(`(?<![/=&-])\\b(${wordsToFind})\\b(?![/=&-])`, 'gi');
  return originalString.replace(re, '<mark>$&</mark>');
};

const result = highlightMarkdown(
  `Status of app [TODO app](url.com/apps/list?appid=q1w2e3) has been changed to completed.`,
  'app'
);

console.log(result);

【讨论】:

  • 用或| 运算符代替splitreduce 替换许多单词的好方法,并且您在链接中使用lookbehind 处理/app/ 时的情况!
【解决方案2】:

您可以删除标志g,但它只会更改第一个匹配的app,而不是括号内的那个[TODO app], 这样做所以你可以定义一个变量 times 并定义你希望单词 app 被替换多少次!

const garbage = /[|\\{}()[\]^$+*?.]/g;

const highlightMarkdown = (originalString = '', highlight = '') => {
  highlight = highlight.trim();
  if (!highlight) return originalString;

  const wordsToFind = highlight.replace(garbage, '').split(' ');
  let times = 0; // Define here
  const result = wordsToFind.reduce((result, word) => {
    const re = new RegExp(`(${word})`, 'gi');

    return result.replace(re, (word) => {
        if(times<2){
            times++; // increment here
            return `<mark>${word}</mark>`;
        }
        return word;
        
    });
  }, originalString);

  return result;
};

const result = highlightMarkdown(
  `Status of app [TODO app](url.com/apps/list?appid=q1w2e3) has been changed to completed.`,
  'app'
);

console.log(result);

【讨论】:

  • 问题是如果你在文本中改变顺序会坏掉
  • 是的,它只会改变前两个应用程序,我使用边界\b提供了更好的答案!
【解决方案3】:

更好的解决方案使用字边界\b

const re = new RegExp(`\\b(${word})\\b`, 'gi');

【讨论】:

  • 如果 url 有 /app/ 这将不足以作为衡量标准...
  • 请注意,如果有这样的链接包含/app/,它将受到影响,因为/被视为单词边界。
猜你喜欢
  • 2020-10-24
  • 2017-09-03
  • 1970-01-01
  • 2011-03-06
  • 1970-01-01
  • 1970-01-01
  • 2022-12-17
  • 1970-01-01
  • 2020-10-10
相关资源
最近更新 更多