在字符串中仅替换标签外的内容,使用正则表达式进行替换。

3

我有一些字符串,其中可能会出现一些HTML标签,例如

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

我该如何使用正则表达式替换所有的b符号,例如用:blablabla:(仅为例子),但仅限于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>

这个正则表达式应该只替换第一个:/为真正的笑脸图片,但不能替换第二个和第三个,因为它们在标签内(并且是标签的一部分)。以下是使用答案中的正则表达式的示例片段。

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;
<pre></pre>

很奇怪,但是演示显示已经捕获了正确的组,但是在替换函数中相同的正则表达式似乎不起作用。


6
使用解析器而非正则表达式。 - elixenide
3
Ed所说的没错。仅仅使用正则表达式无法可靠地处理HTML代码(https://dev59.com/X3I-5IYBdhLWcg3wq6do#1732454)。你不能这样做,即使你认为“哦,我的用例足够简单...”实际上不是这样的。它根本不是这样的。 - T.J. Crowder
3个回答

0

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;
<pre></pre>

你可以这样做:
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,接受正则表达式来实现)。

0

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

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

[正则表达式演示]


如果您想使用正则表达式,我建议您使用以下正则表达式递归地删除所有标记,直到所有标记都被删除:
/<[^\/][^<]*>[^<]*<\/.*?>/g

然后使用替换函数查找任何b


请纠正我,但是第一组 /<[^/]*?b.*?</.*?>|(b)/ig 已经可以找到(如果我按照演示链接)标签内的出现次数。如果我在替换函数中使用这个正则表达式,它也会替换标签内的内容。 - kaytrance
@kaytrance 首先,在正则表达式中,您将捕获标签外的“b”,然后可以使用“\1”替换刚刚捕获的部分。 - shA.t
你能提供一个例子吗,也许通过分叉你的演示来展示? - kaytrance

0

用于将所有b替换为:blablabla:的正则表达式本身并不难:

.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));

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

结果:

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

如果您只是直接访问文档(比如在浏览器中打开一个HTML文档),您无需使用自定义元素,只需确保它位于<body>标签下即可。 - Wiktor Stribiżew
我不解析DOM。我只有一个字符串,仅此而已。基本上的想法是在字符串中替换所有内容,除了标签内部。 - kaytrance
我的代码是用dom解析器解析HTML字符串的。它将替换标签外文本中的子字符串。 - Wiktor Stribiżew
不是理想的解决方案,我正在尝试寻找基于正则表达式的解决方案。你能否检查我在初始问题中附加的代码片段?也许你可以纠正它使其正常工作。 - kaytrance
大多数建议使用基于正则表达式的解决方案来解析HTML的答案可能会被投票降低。我正在尝试避免这种情况。现在我所能做的就是稍微美化一下我的代码,使其更易读。 - Wiktor Stribiżew
我将代码分割成几部分,以使其更易读。即使您说它“不是理想的解决方案”,但这是修改任意HTML的唯一正确方法:使用解析器进行解析,并仅修改所需的纯文本。 - Wiktor Stribiżew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接