簡體   English   中英

將數組添加到多維數組或對象中

[英]Add arrays into multi-dimensional array or object

我正在將由wysiwyg生成的內容解析為React中的目錄小部件。

到目前為止,我正在遍歷標題並將它們添加到數組中。

如何將它們全部放入一個多維數組或對象(最好的方法),使它看起來更像:

h1-1
    h2-1
        h3-1

h1-2
    h2-2
        h3-2

h1-3
    h2-3
        h3-3

然后我可以在UI中使用有序列表進行渲染。

 const str = "<h1>h1-1</h1><h2>h2-1</h2><h3>h3-1</h3><p>something</p><h1>h1-2</h1><h2>h2-2</h2><h3>h3-2</h3>"; const patternh1 = /<h1>(.*?)<\\/h1>/g; const patternh2 = /<h2>(.*?)<\\/h2>/g; const patternh3 = /<h3>(.*?)<\\/h3>/g; let h1s = []; let h2s = []; let h3s = []; let matchh1, matchh2, matchh3; while (matchh1 = patternh1.exec(str)) h1s.push(matchh1[1]) while (matchh2 = patternh2.exec(str)) h2s.push(matchh2[1]) while (matchh3 = patternh3.exec(str)) h3s.push(matchh3[1]) console.log(h1s) console.log(h2s) console.log(h3s) 

我不了解你,但我討厭用正則表達式解析HTML。 相反,我認為讓DOM處理這個問題更好:

 const str = `<h1>h1-1</h1> <h3>h3-1</h3> <h3>h3-2</h3> <p>something</p> <h1>h1-2</h1> <h2>h2-2</h2> <h3>h3-2</h3>`; const wrapper = document.createElement('div'); wrapper.innerHTML = str.trim(); let tree = []; let leaf = null; for (const node of wrapper.querySelectorAll("h1, h2, h3, h4, h5, h6")) { const nodeLevel = parseInt(node.tagName[1]); const newLeaf = { level: nodeLevel, text: node.textContent, children: [], parent: leaf }; while (leaf && newLeaf.level <= leaf.level) leaf = leaf.parent; if (!leaf) tree.push(newLeaf); else leaf.children.push(newLeaf); leaf = newLeaf; } console.log(tree); 

這個答案不需要h3跟隨h2 ; 如果你願意, h3可以跟隨h1 如果要將其轉換為有序列表,也可以這樣做:

 const str = `<h1>h1-1</h1> <h3>h3-1</h3> <h3>h3-2</h3> <p>something</p> <h1>h1-2</h1> <h2>h2-2</h2> <h3>h3-2</h3>`; const wrapper = document.createElement('div'); wrapper.innerHTML = str.trim(); let tree = []; let leaf = null; for (const node of wrapper.querySelectorAll("h1, h2, h3, h4, h5, h6")) { const nodeLevel = parseInt(node.tagName[1]); const newLeaf = { level: nodeLevel, text: node.textContent, children: [], parent: leaf }; while (leaf && newLeaf.level <= leaf.level) leaf = leaf.parent; if (!leaf) tree.push(newLeaf); else leaf.children.push(newLeaf); leaf = newLeaf; } const ol = document.createElement("ol"); (function makeOl(ol, leaves) { for (const leaf of leaves) { const li = document.createElement("li"); li.appendChild(new Text(leaf.text)); if (leaf.children.length > 0) { const subOl = document.createElement("ol"); makeOl(subOl, leaf.children); li.appendChild(subOl); } ol.appendChild(li); } })(ol, tree); // add it to the DOM document.body.appendChild(ol); // or get it as text const result = ol.outerHTML; 

由於HTML是由DOM而不是正則表達式解析的,因此,如果h1標簽具有屬性,則此解決方案不會遇到任何錯誤。

你可以簡單地收集所有h*然后迭代它們來構造一個樹,如下所示:

使用ES6 (我推斷這可以從你使用constlet

const str = `
    <h1>h1-1</h1>
    <h2>h2-1</h2>
    <h3>h3-1</h3>
    <p>something</p>
    <h1>h1-2</h1>
    <h2>h2-2</h2>
    <h3>h3-2</h3>
`
const patternh = /<h(\d)>(.*?)<\/h(\d)>/g;

let hs = [];

let matchh;

while (matchh = patternh.exec(str))
    hs.push({ lev: matchh[1], text: matchh[2] })

console.log(hs)

// constructs a tree with the format [{ value: ..., children: [{ value: ..., children: [...] }, ...] }, ...]
const add = (res, lev, what) => {
  if (lev === 0) {
    res.push({ value: what, children: [] });
  } else {
    add(res[res.length - 1].children, lev - 1, what);
  }
}

// reduces all hs found into a tree using above method starting with an empty list
const tree = hs.reduce((res, { lev, text }) => {
  add(res, lev-1, text);
  return res;
}, []);

console.log(tree);

但是因為你的html標題本身不在樹形結構中(我猜這是你的用例),這只能在某些假設下工作,例如你不能有一個<h3>除非它上面有一個<h2>和一個<h1>那。 它還假設一個較低級別的標題將始終屬於一個更高級別的最新標題。

如果您想進一步使用樹結構來為例如渲染TOC的代表性有序列表,您可以執行以下操作:

// function to render a bunch of <li>s
const renderLIs = children => children.map(child => `<li>${renderOL(child)}</li>`).join('');

// function to render an <ol> from a tree node
const renderOL = tree => tree.children.length > 0 ? `<ol>${tree.value}${renderLIs(tree.children)}</ol>` : tree.value;

// use a root node for the TOC
const toc = renderOL({ value: 'TOC', children: tree });

console.log(toc);

希望能幫助到你。

您想要做的是被稱為(a的變體) 文檔大綱 ,例如。 從文檔標題創建嵌套列表,尊重其層次結構。

使用DOM和DOMParser API的瀏覽器的簡單實現如下(放入HTML頁面並在ES5中編碼以便於測試):

<!DOCTYPE html>
<html>
<head>
<title>Document outline</title>
</head>
<body>
<div id="outline"></div>
<script>

// test string wrapped in a document (and body) element
var str = "<html><body><h1>h1-1</h1><h2>h2-1</h2><h3>h3-1</h3><p>something</p><h1>h1-2</h1><h2>h2-2</h2><h3>h3-2</h3></body></html>";

// util for traversing a DOM and emit SAX startElement events
function emitSAXLikeEvents(node, handler) {
    handler.startElement(node)
    for (var i = 0; i < node.children.length; i++)
        emitSAXLikeEvents(node.children.item(i), handler)
    handler.endElement(node)
}

var outline = document.getElementById('outline')
var rank = 0
var context = outline
emitSAXLikeEvents(
    (new DOMParser()).parseFromString(str, "text/html").body,
    {
        startElement: function(node) {
            if (/h[1-6]/.test(node.localName)) {
                var newRank = +node.localName.substr(1, 1)

                // set context li node to append
                while (newRank <= rank--)
                    context = context.parentNode.parentNode

                rank = newRank

                // create (if 1st li) or
                // get (if 2nd or subsequent li) ol element
                var ol
                if (context.children.length > 0)
                    ol = context.children[0]
                else {
                    ol = document.createElement('ol')
                    context.appendChild(ol)
                }

                // create and append li with text from
                // heading element
                var li = document.createElement('li')
                li.appendChild(
                  document.createTextNode(node.innerText))
                ol.appendChild(li)

                context = li
            }
        },
        endElement: function(node) {}
    })
</script>
</body>
</html>

我首先將您的片段解析為Document ,然后遍歷它以創建類似SAX的startElement()調用。 startElement()函數中,將根據最近創建的列表項(如果有)的等級檢查標題元素的等級。 然后在正確的層次結構級別附加新的列表項,並且可能創建ol元素作為其容器。 請注意,算法不能在層次結構中從h1 “跳躍”到h3 ,但可以很容易地進行調整。

如果你想在node.js上創建一個大綱/內容表,可以使代碼在服務器端運行,但是需要一個像樣的HTML解析庫(對於node.js來說,DOMParser polyfill,可以這么說)。 還有https://github.com/h5o/h5o-jshttps://github.com/hoyois/html5outliner包用於創建輪廓,但我還沒有測試過。 據推測,這些軟件包還可以處理角落案例,例如iframe標題元素和quote元素,這些元素通常是您在文檔大綱中不需要的。

創建HTML5大綱的主題歷史悠久; 見例如。 http://html5doctor.com/computer-says-no-to-html5-document-outline/ HTML4的實踐是不使用分段根 (在HTML5用語中)包裝元素,用於在同一層次結構級別進行切片和放置標題和內容,這種做法稱為“平面地球標記”。 SGML具有RANK功能,用於處理H1H2等排序元素,並可以用來推斷省略的section元素,從而自動創建輪廓,在簡單的情況下從類似HTML4的“扁平地球標記”(例如,只有允許使用section或其他單個元素作為section root。

我將使用一個單一的正則表達式來獲得<hx></hx>內容,然后對它們進行排序x使用方法Array.reduce


這是基地, 但還沒有結束

 // The string you need to parse const str = "\\ <h1>h1-1</h1>\\ <h2>h2-1</h2>\\ <h3>h3-1</h3>\\ <p>something</p>\\ <h1>h1-2</h1>\\ <h2>h2-2</h2>\\ <h3>h3-2</h3>"; // The regex that will cut down the <hx>something</hx> const regex = /<h[0-9]{1}>(.*?)<\\/h[0-9]{1}>/g; // We get the matches now const matches = str.match(regex); // We match the hx togethers as requested const matchesSorted = Object.values(matches.reduce((tmp, x) => { // We get the number behind hx ---> the x const hNumber = x[2]; // If the container do not exist, create it if (!tmp[hNumber]) { tmp[hNumber] = []; } // Push the new parsed content into the array // 4 is to start after <hx> // length - 9 is to get all except <hx></hx> tmp[hNumber].push(x.substr(4, x.length - 9)); return tmp; }, {})); console.log(matchesSorted); 


在解析html內容時,我想了解一些特殊情況,例如\\nspace presency。 例如,查看以下非工作代碼段:

 // The string you need to parse const str = "\\ <h1>h1-1\\n\\ </h1>\\ <h2> h2-1</h2>\\ <h3>h3-1</h3>\\ <p>something</p>\\ <h1>h1-2 </h1>\\ <h2>h2-2 \\n\\ </h2>\\ <h3>h3-2</h3>"; // The regex that will cut down the <hx>something</hx> const regex = /<h[0-9]{1}>(.*?)<\\/h[0-9]{1}>/g; // We get the matches now const matches = str.match(regex); // We match the hx togethers as requested const matchesSorted = Object.values(matches.reduce((tmp, x) => { // We get the number behind hx ---> the x const hNumber = x[2]; // If the container do not exist, create it if (!tmp[hNumber]) { tmp[hNumber] = []; } // Push the new parsed content into the array // 4 is to start after <hx> // length - 9 is to get all except <hx></hx> tmp[hNumber].push(x.substr(4, x.length - 9)); return tmp; }, {})); console.log(matchesSorted); 


我們必須添加.replace().trim()以刪除不需要的\\nspaces

使用此代碼段

 // The string you need to parse const str = "\\ <h1>h1-1\\n\\ </h1>\\ <h2> h2-1</h2>\\ <h3>h3-1</h3>\\ <p>something</p>\\ <h1>h1-2 </h1>\\ <h2>h2-2 \\n\\ </h2>\\ <h3>h3-2</h3>"; // Remove all unwanted \\n const preparedStr = str.replace(/(\\r\\n\\t|\\n|\\r\\t)/gm, ""); // The regex that will cut down the <hx>something</hx> const regex = /<h[0-9]{1}>(.*?)<\\/h[0-9]{1}>/g; // We get the matches now const matches = preparedStr.match(regex); // We match the hx togethers as requested const matchesSorted = Object.values(matches.reduce((tmp, x) => { // We get the number behind hx ---> the x const hNumber = x[2]; // If the container do not exist, create it if (!tmp[hNumber]) { tmp[hNumber] = []; } // Push the new parsed content into the array // 4 is to start after <hx> // length - 9 is to get all except <hx></hx> // call trim() to remove unwanted spaces tmp[hNumber].push(x.substr(4, x.length - 9).trim()); return tmp; }, {})); console.log(matchesSorted); 

我寫這個代碼適用於JQuery。 (請不要DV 。也許以后有人需要jquery答案)

這個遞歸函數創建了字符串的li ,如果一個項目有一些childern,它會將它們轉換為ol

 const str = "<div><h1>h1-1</h1><h2>h2-1</h2><h3>h3-1</h3></div><p>something</p><h1>h1-2</h1><h2>h2-2</h2><h3>h3-2</h3>"; function strToList(stri) { const tags = $(stri); function partToList(el) { let output = "<li>"; if ($(el).children().length) { output += "<ol>"; $(el) .children() .each(function() { output += partToList($(this)); }); output += "</ol>"; } else { output += $(el).text(); } return output + "</li>"; } let output = "<ol>"; tags.each(function(itm) { output += partToList($(this)); }); return output + "</ol>"; } $("#output").append(strToList(str)); 
 li { padding: 10px; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="output"></div> 

(這段代碼可以輕松轉換為純JS)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM