【问题标题】:Replace with RegExp only outside tags in the string仅用正则表达式替换字符串中的外部标记
【发布时间】:2015-10-15 14:36:59
【问题描述】:

我有一个字符串可以显示一些 html 标签,比如

this is a nice day for bowling <b>bbbb</b>

如何用 RegExp 替换所有 b 符号,例如,用 :blablabla: (例如)但 ONLY 在 html 标记之外?

所以在这种情况下,结果字符串应该变成

this is a nice day for :blablabla:owling <b>bbbb</b>

编辑:根据我收到的答案,我想更具体一些。所以首先我只有一个字符串,而不是 DOM 元素或其他任何东西。字符串可能包含也可能不包含标签(开始和结束)。主要思想是能够替换文本中除标签内部以外的任何地方。例如,如果我有一个像

这样的字符串
not feeling well today :/ check out this link <a href="http://example.com">http://example.com</a>

正则表达式应该将 only 第一个 :/ 替换为真正的笑脸图像,但不应替换第二个和第三个,因为它们在标签内部(和一部分)。这是一个使用来自答案之一的正则表达式的示例 sn-p。

var s = 'not feeling well today :/ check out this link <a href="http://example.com">http://example.com</a>';
var replaced = s.replace(/(?:<[^\/]*?.*?<\/.*?>)|(:\/)/g, "smiley_image_here");
document.querySelector("pre").textContent = replaced;
&lt;pre&gt;&lt;/pre&gt;

这很奇怪,但 DEMO 表明它捕获了正确的组,但替换函数中的相同正则表达式似乎不起作用。

【问题讨论】:

标签: javascript regex


【解决方案1】:

用:blablabla: 替换所有bs 的正则表达式本身并不难:

.replace(/b/g, ":blablabla:")

获取我们需要执行搜索和替换的文本节点有点棘手。

这是一个基于 DOM 的示例:

function replaceTextOutsideTags(input) {
  var doc = document.createDocumentFragment();
  var wrapper = document.createElement('myelt');
  wrapper.innerHTML = input;
  doc.appendChild( wrapper );
  return textNodesUnder(doc);
}
function textNodesUnder(el){
  var n, walk=document.createTreeWalker(el,NodeFilter.SHOW_TEXT,null,false);
  while(n=walk.nextNode())
  {
       if (n.parentNode.nodeName.toLowerCase() === 'myelt')
      		n.nodeValue =  n.nodeValue.replace(/:\/(?!\/)/g, "smiley_here"); 
  }
  return el.firstChild.innerHTML;
} 

var s = 'not feeling well today :/ check out this link <a href="http://example.com">http://example.com</a>';
console.log(replaceTextOutsideTags(s));

在这里,我们只修改作为名为@9​​87654325@ 的自定义元素的直接子元素的文本节点。

结果:

not feeling well today smiley_here check out this link <a href="http://example.com">http://example.com</a>

【讨论】:

  • 如果您只是可以直接访问文档(例如,它是在浏览器中打开的 HTML 文档),您不必使用自定义元素,只需确保它在 @987654327 下@标签。
  • 我没有解析 DOM。我只有一个字符串,仅此而已。这个想法基本上是替换字符串中的所有位置,除了内部标签。
  • 我的代码用于使用 dom 解析器解析 HTML 字符串。它将替换标签外文本中的子字符串。
  • 不是理想的解决方案,我试图找到仅基于正则表达式的解决方案。你能检查一下我附在初始问题上的片段吗?也许您可以纠正它以使其正常工作。
  • 大多数建议基于正则表达式的 HTML 解析解决方案的答案可能会被否决。我试图避免它。我现在能做的就是稍微美化我的代码,使其更具可读性。
【解决方案2】:

var input = "this is a nice day for bowling <b>bbbb</b>";
var result = input.replace(/(^|>)([^<]*)(<|$)/g, function(_,a,b,c){
				return a
				+ b.replace(/b/g, ':blablabla:')
				+ c;
});
document.querySelector("pre").textContent = result;
&lt;pre&gt;&lt;/pre&gt;

你可以这样做:

var result = input.replace(/(^|>)([^<]*)(<|$)/g, function(_,a,b,c){
            return a
            + b.replace(/b/g, ':blablabla:') // you may do something else here
            + c;
});

请注意,在大多数(不是全部,而是大多数)真正复杂的用例中,操作已解析的 DOM 比仅操作字符串要方便得多。如果您从 HTML 页面开始,您可能会使用库(有些,例如 my one,接受正则表达式)。

【讨论】:

    【解决方案3】:

    我认为您可以使用这样的正则表达式:(仅用于简单数据而不是嵌套数据)

    /<[^\/]*?b.*?<\/.*?>|(b)/ig
    

    [Regex Demo]


    如果你想使用正则表达式,我建议你使用下面的正则表达式递归删除所有标签,直到所有标签都被删除:

    /<[^\/][^<]*>[^<]*<\/.*?>/g
    

    然后使用替换来查找任何b。

    【讨论】:

    • 如果我错了,请纠正我,但第一组 /|(b)/ig 已经在标签内找到(标记,如果我点击演示链接)。如果我在替换函数中使用这个正则表达式,它也会替换内部标签。
    • @kaytrance 在第一个正则表达式中,您将在标签之外捕获b,您可以使用\1 替换刚刚捕获的部分;)。
    • 你能提供一个例子吗,也许只是通过分叉你的演示?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 2017-11-27
    • 2023-03-21
    • 1970-01-01
    • 2015-04-24
    • 1970-01-01
    相关资源
    最近更新 更多