Estaba tratando de resaltar la subcadena dentro de la cadena usando el índice de inicio y fin. Pero me enfrento a un problema al resaltar la subcadena superpuesta. p.ej
Tengo un text y una array para resaltar.
¿Hay alguna manera, cómo puedo evitar las etiquetas superpuestas? Intenté con la coincidencia de regex de la subcadena, pero no pude resolverlo.
let tagObject = { "text": "I am asking a question in stackoverflow", "tags": [{ start: 0, end: 1, value: "I", tag: "TAG1" }, { start: 0, end: 4, value: "I am", tag: "TAG2" }, { start: 5, end: 22, value: "asking a question", tag: "TAG3" }, { start: 14, end: 22, value: "question", tag: "TAG4" }, { start: 14, end: 25, value: "question in", tag: "TAG5" } ] } const color = { outer: "color: #1d39c4; background: #f0f5ff; border-color: #adc6ff;", inner: "background: #adc6ff;", bg: "#f0f5ff" } const createStyledString = (obj) => { let { text, tags } = obj; tags.sort((a, b) => b.start - a.start); tags.forEach(t => { const { start, end, value, tag } = t; text = text.substring(0, start) + `<span contenteditable="false" data-action="${value}---${start}---${end}---${color.bg}---${tag}" unselectable="on" onselectstart="return false;" name="tag" class="outer" style="${color.outer}">${value}<span class="ne-c-inner" unselectable="on" onselectstart="return false;" data-action="${value}---${start}---${end}---${color.bg}---${tag}" style="${color.inner}">${tag}</span></span>` + text.substring(end) }); return text; } document.body.innerHTML=createStyledString(tagObject)Hay dos problemas principales en su enfoque.
Por lo que una posible solución sería la siguiente:
Aquí hay un fragmento de trabajo.
let tagObject = { "text": "I am asking a question in stackoverflow", "tags": [{ start: 0, end: 1, value: "I", tag: "TAG1" }, { start: 0, end: 4, value: "I am", tag: "TAG2" }, { start: 5, end: 22, value: "asking a question", tag: "TAG3" }, { start: 14, end: 22, value: "question", tag: "TAG4" }, { start: 14, end: 25, value: "question in", tag: "TAG5" } ] } const color = { outer: "color: #1d39c4; background: #f0f5ff; border-color: #adc6ff;", inner: "background: #adc6ff;", bg: "#f0f5ff" } const createStyledString = (obj) => { let { text, tags } = obj; tags.sort((a, b) => b.start - a.start); // TO KEEP TRACK OF INSERTED TEXT let insertedAmmount = [] tags.forEach(t => { const { start, end, value, tag } = t; // COMPUTE THE REAL START AND END POSITIONS // TAKING INSERTED TEXT INTO ACCOUNT let realStart = start let realEnd = end for(let idx in insertedAmmount){ if(idx < start){ realStart += insertedAmmount[idx] } if(idx <= end){ realEnd += insertedAmmount[idx] } } let pre = `<span contenteditable="false" data-action="${value}---${start}---${end}---${color.bg}---${tag}" unselectable="on" onselectstart="return false;" name="tag" class="outer" style="${color.outer}">` let pos = `<span class="ne-c-inner" unselectable="on" onselectstart="return false;" data-action="${value}---${start}---${end}---${color.bg}---${tag}" style="${color.inner}">${tag}</span></span>` // UPDATE THE INFORMATION ABOUT INSERTED TEXT insertedAmmount[start] = (insertedAmmount[start] || 0) + pre.length insertedAmmount[end] = (insertedAmmount[end] || 0) + pos.length // DON'T INSERT DIRECTLY THE VALUE BUT THE ALREADY EXISTENT TEXT text = text.substring(0, realStart) + pre + text.substring(realStart, realEnd) + pos + text.substring(realEnd) }); return text; } document.body.innerHTML=createStyledString(tagObject)