Últimamente he estado trabajando en un proyecto en el que necesito poder anotar una oración en índices específicos usando vainilla javascript. Por ejemplo: El perro corre muy rápido.
La entrada con la que tengo que trabajar se parece a esto:
[ {beginIndex: 4, endIndex: 7, style: "bold"}, {beginIndex: 5, endIndex: 7, style: "italics"}, {beginIndex: 13, endIndex: 19, style: "italics"}, ]
El desafío al que me enfrento es cuando tengo que lidiar con índices superpuestos (como se ve en el índice 0 y 1 de la matriz anterior).
Pensé que la mejor manera de manejar la superposición sería reestructurar la matriz de esta manera:
[ {beginIndex: 4, endIndex: 5, style: "bold"}, {beginIndex: 5, endIndex: 7, style: "italics bold"}, {beginIndex: 13, endIndex: 19, style: "italics"}, ]
Y luego use la matriz para crear dinámicamente un html simple que se vea así:
<span>The <span class="bold">d</span><span class="bold italics">og</span> runs <span class="italics">really</span> fast.</span>
Pasé algunas horas tratando de descubrir cómo tomar la entrada y luego generar una salida que maneje los índices superpuestos. Siento que este debería ser un ejercicio de CS bastante simple, pero parece que no puedo encontrar la manera de hacerlo. ¿Alguien tiene algún consejo sobre cómo manejar esta situación. ¿O si esta es la mejor manera de anotar texto usando vanilla js y html?
Esta imagen ilustra lo que estoy buscando. 3 entradas que identifican algunos índices para anotar, y la cuarta línea sería la salida, combinando todas las anotaciones en una sola línea.
Recomiendo dividir cada rango en operaciones que eliminen o agreguen un rasgo. Luego puedes ordenarlos por índice:
const ranges = [ {beginIndex: 4, endIndex: 7, style: "bold"}, {beginIndex: 5, endIndex: 7, style: "italics"}, {beginIndex: 13, endIndex: 19, style: "italics"}, ]; const operations = ranges.flatMap(range => [ {index: range.beginIndex, style: range.style, enable: true}, {index: range.endIndex, style: range.style, enable: false}, ]); operations.sort((a, b) => a.index - b.index); const fragment = document.createDocumentFragment(); const container = document.createElement("span"); const text = "The dog runs really fast."; let lastIndex = 0; for (const op of operations) { if (lastIndex !== op.index) { fragment.appendChild(container.cloneNode(true)) .textContent = text.substring(lastIndex, op.index); lastIndex = op.index; } container.classList.toggle(op.style, op.enable); } fragment.appendChild(container).textContent = text.substring(lastIndex); document.body.appendChild(fragment);
.bold { font-weight: bold; } .italics { font-style: italic; }
Sin embargo, tenga cuidado con lo que representan esos índices. El código anterior usa substring
, que opera en unidades de código UTF-16; otras opciones comunes son unidades de código UTF-8 (bytes) o valores escalares Unicode. ¡Pruebe su código en emoji si corresponde! ✨
No estoy seguro de que sea la mejor manera, pero para lograr lo que quieres lograr, algo como esto convertiría tu matriz de formato...
const formattingArray = [ {beginIndex: 4, endIndex: 7, style: "bold"}, {beginIndex: 5, endIndex: 7, style: "italics"}, {beginIndex: 13, endIndex: 19, style: "italics"}, ] // assumes array is already sorted by beginIndex let outputFormattingArray = []; for ( let i = 0; i < formattingArray.length; i++ ) { if ( formattingArray.length > i + 1 && formattingArray[i].endIndex > formattingArray[i + 1].beginIndex ) { outputFormattingArray.push( { beginIndex: formattingArray[i].beginIndex, endIndex: formattingArray[i + 1].beginIndex, style: formattingArray[i].style } ); outputFormattingArray.push( { beginIndex: formattingArray[i + 1].beginIndex, endIndex: formattingArray[i].endIndex, style: 'bold italics' } ); outputFormattingArray.push( { beginIndex: formattingArray[i].endIndex, endIndex: formattingArray[i + 1].endIndex, style: formattingArray[i].style } ); i++; } else { outputFormattingArray.push( formattingArray[i] ); } } console.log( outputFormattingArray );
Sin embargo, para ser honesto, puede ser mejor asegurarse de que la entrada no incluya etiquetas superpuestas y arrojar un error si lo hace. HTML en sí mismo no permitiría la superposición de etiquetas de esa manera, ¿por qué debería hacerlo usted? pueden formatear fácilmente los datos para que se ajusten a una verificación de validación y seguir formateándolos de la forma que sea necesaria.