【问题标题】:wrap HTML tags in plain string with another HTML tag用另一个 HTML 标记将 HTML 标记包装在纯字符串中
【发布时间】:2018-05-31 16:57:20
【问题描述】:

我想将一个 HTML 标记与另一个 HTML 标记包装在一个字符串中(所以不是 DOM 元素,而是一个纯字符串)。我创建了这个函数,但我想知道是否可以在没有 forEach 循环的情况下一次性完成。

这是工作函数:

function style(content) {
    var tempStyledContent = content;

    var imgMatches = tempStyledContent.match(/(<img.*?src=[\"'](.+?)[\"'].*?>)/g);

    imgMatches.forEach(function (imgMatch) {
        var imgTag = imgMatch;
        var imgSrc = imgMatch.match(/src\s*=\s*"(.+?)"/)[1];

        tempStyledContent = tempStyledContent.replace(imgTag,
            "<a href=\"" + imgSrc + "\" data-fancybox>" + imgTag + "</a>");
    });

    return tempStyledContent;
}

参数content 是一个包含HTML 代码的字符串。上面的函数输出与输入相同的 html,但带有 (fancybox) a 标记围绕所有子 img 标签。

所以输入字符串像

"<div><img src='example.jpg'/></div>"

会输出

"<div><a href='example.jpg' data-fancybox><img src='example.jpg'/></a></div>"

有人可以改进吗?我对正则表达式知之甚少,无法让它变得更好。

【问题讨论】:

  • Luca,我有这个功能,我只是想改进它。我在knockoutjs中使用这个字符串与html绑定进行绑定,所以html-string在页面上渲染出来了。
  • 只能在 context 中添加改进。看不到内容(您的 HTML)的样子。任何改进都将无效。
  • 克林顿,我认为代码是不言自明的,不管什么内容,只要知道它是有效的 html(如网页的 html-string,div 的 html-string以img为子),示例:var content = "
    ";这是一个真正的简短示例,因为此评论框中没有足够的字符来制作完整的示例。但我们的目标是让输出字符串具有相同的 html,其中“img”标签被(fancybox)“a”标签包围。
  • 克林顿,我更新了帖子,这确实会清楚一点,我写这篇文章的时候还在编程模式:-)
  • 您是否有特殊原因要使用字符串而不是操作 DOM 元素来执行此操作?在 HTML 上使用正则表达式通常是不明智的。

标签: javascript regex


【解决方案1】:

使用正则表达式处理 HTML 是 notoriously problematic。在 DOM 解析器中微不足道的更改可能很难为其创建健壮的正则表达式;当正则表达式失败时,它会默默地失败,这使得错误很容易被遗漏。在使用正则表达式时,您还必须小心处理标记中所有可能的变化,例如空格、属性顺序、引用样式、标签关闭样式、类似于 html 但您不想修改的属性内容等。

正如下面评论线程中详尽讨论的那样,只要有足够的时间和精力,肯定有可能在正则表达式中处理所有这些事情;但它会导致复杂的、难以维护的正则表达式——最重要的是,很难确定你的正则表达式能适应所有可能的有效标记变化。 DOM 解析会自动处理所有这些内容,并让您直接处理结构化数据,而不必处理其字符串表示中的所有可能变化。

因此,如果您需要对 HTML 字符串进行重大更改,最好将您的 HTML 转换为真正的 DOM 树,使用标准 DOM 方法对其进行操作,然后(如有必要)将其转换回字符串。幸运的是,这样做不需要太多代码。这是一个简单的香草 JS 演示:

var htmlToElement = function(html) {
  var template = document.createElement('template');
  template.innerHTML = html.trim();
  return template.content.firstChild;
};

var elementToHtml = function(el) {
  return el.outerHTML;
}

// Usage demo:
var string = "<div>This <b>is some</b> <i>html</i><img src='http://example.com'></div>";

var foo = htmlToElement(string);

// perform your DOM manipulation as needed on foo here. This would look much simpler if I wasn't so stubborn about avoiding jQuery these days, but here we are anyway:
foo.querySelectorAll('img').forEach(function(img) {
    var link = document.createElement('a');
    link.setAttribute('data-fancybox',true);
    link.setAttribute('href', img.getAttribute('src'));
    img.parentNode.insertBefore(link,img);
    link.appendChild(img);
});

// back to a string:
var bar = elementToHtml(foo);
console.log(bar);

【讨论】:

  • 我看到之前的 cmets 被删除了。我想补充一点,人们使用简单的正则表达式发布了成千上万的答案来提取 html 信息。为什么有一些内在的观念认为 HTML 不能用正则表达式在低级别解析是很奇怪的,因为 W3C 规范在其规范中使用了正则表达式。您错过了重点,没有人可以仅使用正则表达式创建 DOM。但是,与任何事情一样,展开元素的第一级解析是 tag 解析。顺便说一句,very difficult to create a robust regex for (see @sln's answer, for example); and when it fails, it fails catastrophically 是 baloneyl
  • @sln,您显然对正则表达式非常熟练。这很好,您应该继续使用最适合您的任何工具。我的经验是,对于非平凡的更改,正则表达式往往可以在示例 HTML 数据上正常工作,然后在现实世界中失败(例如,如果你的针对包含非自关闭图像标签的 HTML 运行。)显然,特别是一个简单的修复,但保证一个正则表达式会针对现实世界的数据做你想做的事情是困难的:这种失败很容易被错过,因为不会引发错误;事情只是悄悄地失败了。
  • 这不是你应该告诉我的,还是应该你?我不认为你的最后一条评论是给我的,因为我很熟练,简单的解决方法是 -> Regex mod(最后):删除/&gt;,添加&gt;(?:\s*&lt;/img\s*&gt;)? 还是你想这样做?在这里,guaranteeing a regex will do what you want against real-world data is difficult 完全无效。解析 html 标签是原始且可预测的。一个 real-world cnn.com 源代码去除了 html:regex101.com/r/mmalIt/1。这比我告诉你的要多,但我认为你没有兴趣。
  • 您可能希望在下面的答案中将/i 标志添加到正则表达式中,因为它仍然无法匹配许多有效的现实世界html。可以肯定的是,这是一个微不足道的改变,但对于“尽可能原始和可预测”的东西,它确实似乎需要大量的摆弄才能正确......
  • 我认为添加(?i) 是用户的选择,就像匹配自包含闭包的选择一样。但是,如果您不了解正则表达式,您可能会认为这是微不足道的。
【解决方案2】:

好的,我可能会按照@DanielBeck 的建议进行 DOM 操作。一旦淘汰赛完成绑定,我将使用 $.wrap http://api.jquery.com/wrap/ 进行操作。我只是希望有一种不使用 jquery 的简单方法,所以如果有其他建议,请发表评论。

【讨论】:

  • 不要让人们强迫您以任何特定方式编写代码,如果您想使用正则表达式,请使用它。我发布了一个可靠的方法。
猜你喜欢
  • 2020-09-02
  • 2020-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-31
  • 2017-06-13
相关资源
最近更新 更多