Tengo un texto largo y una matriz que contiene algunos objetos. cada objeto tiene una clave de inicio y una clave de finalización. Lo que estoy tratando de hacer es resaltar el texto, solo en los índices que obtengo de la matriz.
Escribí este código:
function HighlightRange(text: any, start: any, end: any, color: any) { return ( text.substring(0, start) + `<span style="background-color: ${color}">` + text.substring(start, end) + `</span>` + text.substring(end) ); }Funciona perfectamente si solo tengo un objeto en la matriz. La cuestión es que cuando lo uso, cambia el texto y ahora tiene una longitud mayor y el resaltado ahora necesita obtener la nueva longitud para resaltar el rango exacto.
Intenté eso:
value?.input_spans.map((value: any, key: any) => { newString = HighlightRange( originalTextArea, value.start, value.end, "lightgreen" ); });¿Es posible iterar sobre todos los objetos y resaltar todo el texto de principio a fin sin cambiar la longitud del texto?
Este es uno de los raros casos de uso de .reduceRight() . Como menciona @Robert Sabitz, comenzar desde el final de la cadena mantendría sus índices de interés sin cambios.
var prg = document.getElementById("lorem"), btn = document.getElementById("btn"), ixs = [{start:28, end:39}, {start:101, end:111}], clr = "lightgreen"; function highlighter(str,ixs,color){ return ixs.reduceRight( (s,ix) => `${s.slice(0, ix.start)}<span style="background-color:${color}">${s.slice(ix.start,ix.end)}</span>${s.slice(ix.end)}` , str ); } btn.addEventListener("click", _ => prg.innerHTML = highlighter(prg.textContent,ixs,clr)); <p id="lorem">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus tincidunt dictum sapien, sit amet vestibulum ex tempus eget. Ut vitae.</p> <button id="btn">Highlight</button>Simplemente itere desde el final de los elementos para resaltar (similar a eliminar elementos de la matriz sin actualizar el índice). De esta manera, los índices desde el principio se mantendrán correctos.
El problema aquí surge con el resaltado anidado/superpuesto. Si ese es tu caso, entonces hay que hacerlo uno por uno.
Ejemplo
const spansToHighlight = value?.input_spans if (!spansToHighlight) { return } let highlightedText = originalTextArea for (let i = spansToHighlight.length - 1; i >= 0; i++) { highlightedText = HighlightRange( highlightedText , value.start, value.end, "lightgreen" ); }