按特定标签将HTML字符串分割成数组

17

假设有一个表示HTML的字符串"html",我该如何将其拆分为一个数组,其中每个标题<h都标记了一个元素的开头?

从这里开始:

<h1>A</h1>
<h2>B</h2>
<p>Foobar</p>
<h3>C</h3>

结果

["<h1>A</h1>", "<h2>B</h2><p>Foobar</p>", "<h3>C</h3>"]

我尝试过的方法:

我想使用带有正则表达式的Array.split(),但结果将每个<h都拆分成自己的元素。 我需要找出如何从一个<h的开头捕获到下一个<h。 然后包括第一个但不包括第二个。

var html = '<h1>A</h1><h2>B</h2><p>Foobar</p><h3>C</h3>';
var foo = html.split(/(<h)/);

编辑: 正则表达式并不是必需的,它只是我认为可以通用地分割HTML字符串的唯一解决方案。


3
为什么你想要使用正则表达式来处理那个? - Tomalak
如果有不使用正则表达式的方法,我完全愿意使用它 :) - Don P
你使用的语言托管在地球上最先进的HTML解析器中,不使用这些HTML解析能力有点儿傻。 - Tomalak
1
请解释一下还有哪些任务需要完成。 (这是一个XY问题,即您已经决定了解决方案,不要再解释任务本身。请解释任务本身,而不是预期的解决方案。) - Tomalak
1
@DonnyP 请查看 document.createDocumentFragment() - Andreas Louv
显示剩余9条评论
5个回答

25

在你的例子中,你可以使用:

/
  <h   // Match literal <h
  (.)  // Match any character and save in a group
  >    // Match literal <
  .*?  // Match any character zero or more times, non greedy
  <\/h // Match literal </h
  \1   // Match what previous grouped in (.)
  >    // Match literal >
/g
var str = '<h1>A</h1><h2>B</h2><p>Foobar</p><h3>C</h3>'
str.match(/<h(.)>.*?<\/h\1>/g); // ["<h1>A</h1>", "<h2>B</h2>", "<h3>C</h3>"]

但是请不要使用正则表达式来解析HTML,可以阅读正则表达式匹配除了XHTML自包含标签之外的其他开放标签


1
那是一个非常棒的SO问题/答案。 - Don P
2
因为在 HTML 问题中提倡使用正则表达式而被踩,根据您的声望,您应该知道这样做不太好。 - Tomalak
1
@DonnyP 这不是代码高尔夫比赛。"一行完成"并不是目标。他的答案与问题不相符。HTML不能使用正则表达式处理。当你在真实代码上尝试时,这将会崩溃和烧毁,等着看吧。 - Tomalak
3
我可以翻译成中文:@DonnyP 我认为你理解了!我用你的示例数据向你展示了它是可能的,但我也警告你应该重新考虑你的方法,特别是如果你不知道你正在处理什么数据。请随意尝试查看它是否适用于你的所有数据集。如果有效,那太棒了!但如果无效,那只是因为你试图用水点火 :-) - Andreas Louv
1
@DonnyP HTML并不是“太过变化无常”的。HTML属于一类语言(非正则),正则表达式本质上无法描述它们。这是正则表达式的一个严格技术限制。试图强行使用正则表达式来处理HTML意味着两种可能性之一:要么你将自己限制在可以被描述为正则语言的严格子集中(你没有这样做,而是从GitHub上获取未知代码),要么你的代码中存在一个令人讨厌的单行错误。我想知道,“但这只是一行代码!”是否足以成为后者的充分理由。 - Tomalak
显示剩余8条评论

10
从问题的评论中可以看出,这似乎是任务:

我正在收集来自GitHub的动态markdown。然后我想将其渲染为HTML,但要将每个标题元素包装在ReactJS的 <WayPoint> 组件中。

以下是完全独立于库的、基于DOM-API的解决方案。

function waypointify(html) {
    var div = document.createElement("div"), nodes;

    // parse HTML and convert into an array (instead of NodeList)
    div.innerHTML = html;
    nodes = [].slice.call(div.childNodes);

    // add <waypoint> elements and distribute nodes by headings
    div.innerHTML = "";
    nodes.forEach(function (node) {
        if (!div.lastChild || /^h[1-6]$/i.test(node.nodeName)) {
            div.appendChild( document.createElement("waypoint") );
        }
        div.lastChild.appendChild(node);
    });

    return div.innerHTML;
}

用更少的代码在现代库中完成相同的操作是完全可能的,把它看作一种挑战。

这是使用您的示例输入所产生的结果:

<waypoint><h1>A</h1></waypoint>
<waypoint><h2>B</h2><p>Foobar</p></waypoint>
<waypoint><h3>C</h3></waypoint>

2

我相信有人可以简化for循环来放回尖括号,但这是我会做的方式。

var html = '<h1>A</h1><h2>B</h2><p>Foobar</p><h3>C</h3>';

//split on ><
var arr = html.split(/></g);

//split removes the >< so we need to determine where to put them back in.
for(var i = 0; i < arr.length; i++){
  if(arr[i].substring(0, 1) != '<'){
    arr[i] = '<' + arr[i];
  }

  if(arr[i].slice(-1) != '>'){
    arr[i] = arr[i] + '>';
  }
}

此外,实际上我们可以先删除第一个和最后一个括号,然后进行分割,最后再将尖括号替换为整个内容。
var html = '<h1>A</h1><h2>B</h2><p>Foobar</p><h3>C</h3>';

//remove first and last characters
html = html.substring(1, html.length-1);

//do the split on ><
var arr = html.split(/></g);

//add the brackets back in
for(var i = 0; i < arr.length; i++){
    arr[i] = '<' + arr[i] + '>';
}

当然,对于没有内容的元素,这将失败。


如果您使用前瞻,实际上可以保留您正在查找的分隔符:https://dev59.com/5Gct5IYBdhLWcg3wjuEj - Thomas

0
我刚刚遇到了这个问题,在我的一个项目中也需要同样的东西。 我做了以下的事情,对所有的HTML字符串都有效。

let splitArray = data.split("><")
    splitArray.forEach((item, index) => {

        if (index === 0) {
            splitArray[index] = item += ">"

            return
        }

        if (index === splitArray.length - 1) {
            splitArray[index] = "<" + item

            return
        }
        
        splitArray[index] = "<" + item + ">"
    })

console.log(splitArray)


数据是HTML字符串的地方

0

你好,我使用了这个函数将HTML字符串DOM转换为数组

  static getArrayTagsHtmlString(str){
    let htmlSplit = str.split(">")
    let arrayElements = []
    let nodeElement =""
    htmlSplit.forEach((element)=>{  
      if (element.includes("<")) {
        nodeElement = element+">"   
       }else{
         nodeElement = element
        }
        arrayElements.push(nodeElement)
    })
    return arrayElements
  }

编程快乐


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