¿Existe un método rápido de expresión regular o similar que pueda tomar una cadena y analizarla en bits que no estén entre corchetes dobles (llamémoslos "estáticos") y bits que estén entre corchetes dobles (llamémoslos "dinámicos")?
Por ejemplo, ingrese:
Lorem {{ipsum dolor sit}} amet, {consectetur} adipiscing {{elit}}.
Salida requerida:
[ { type: "static", value: "Lorem " }, { type: "dynamic", value: "ipsum dolor sit" }, { type: "static", value: " amet, {consectetur} adipiscing " }, { type: "dynamic", value: "elit" }, { type: "static", value: "." }, ]
Mi mejor intento hasta ahora ha sido usar /\{*([^{}]+)\}*/g
como una expresión regular y recorrer usando while
y exec
pero identifica incorrectamente cualquier número de corchetes como valores dinámicos, como se muestra aquí:
function templateParser(string) { const re = /\{*([^{}]+)\}*/g; const output = []; while (true) { const match = re.exec(string); if (!match) { break; } const [templateItem, templateKey] = match; output.push({ type: templateItem === templateKey ? "static" : "dynamic", value: templateItem === templateKey ? templateItem : templateKey }); } return output; } console.log( templateParser( "Lorem {{ipsum dolor sit}} amet, {consectetur} adipiscing {{elit}}." ) );
Para distinguir {{
this
}}
de that
, una idea para capturar this
pero hacer coincidir that
.
{{(.*?)}}|.+?(?={{|$)
{{
o hasta el final .Vea esta demostración en regex101 o la demostración de JS en tio.run
Usando exec
, sus valores se pueden establecer fácilmente de acuerdo, por ejemplo m[1]!=null
( primer grupo coincidente). Por supuesto, esto está relacionado con sus datos de muestra. Asumiendo que no hay anidamiento y sin adivinar nada más.
Editar: la otra respuesta merece el crédito por usar la anticipación positiva. Usando esa expresión regular, la solución completa sería:
Array.from(s.matchAll(/{{(.*?)}}|.+?(?={{|$)/g)) .map(e=>({type: e[1] ? 'dynamic' : 'static', value: e[1] ?? e[0]}))
o usando grupos de captura con nombre:
Array.from(s.matchAll(/{{(?<dynamic>.*?)}}|(?<static>.+?)(?={{|$)/g)) .flatMap(e=>Object.entries(e.groups)) .filter(e=>e[1]).map(e=>({type: e[0], value: e[1]}))
Respuesta anterior:
let s = `Lorem {{ipsum dolor sit}} amet, {consectetur} adipiscing {{elit}}.`; let result = [{a: 0, b: 0}, ...Array.from(s.matchAll(/{{.*?}}/g)) .map(e=>({a: e.index, b: e.index+e[0].length}))] .map((e, i, arr) => [ {type: 'dynamic', a: ea, b: eb}, {type: 'static', a: eb, b: i===arr.length-1 ? s.length : arr[i+1].a} ]) .flat().map(o=>({type: o.type, value: s.substring(oa, ob)})) .filter(e=>e.value.length>0) .map(o=>o.type==='static' ? o : {type: 'dynamic', value: o.value.substring(2, o.value.length-2)});
Lo que hace es encontrar todas las cadenas contenidas entre llaves dobles y luego asignarlas a una matriz de objetos con índices de inicio y fin a
y b
.
Esos serán los rangos dinámicos. Luego llenamos los espacios en la matriz para obtener los rangos estáticos.
Finalmente, borramos los rangos vacíos y recortamos las llaves dobles de las cadenas dinámicas.
Ahora que sé más sobre lo que está tratando de hacer, esto puede ayudar:
let mystring = 'test {{hello}} goodbye {{foo}} bar {foobar}'; let regex = /{{(.*?)}}/g; console.log( mystring.match( regex ) );
producción
["{{hello}}", "{{foo}}"]
hace una coincidencia diferida de cada cadena que tiene corchetes dobles, coloca las coincidencias en una matriz. Luego, podría reemplazar esas subcadenas con versiones modificadas que incluyan las etiquetas jsx o algo similar.
https://jsfiddle.net/u7gkz341/
Editar:
let mystring = 'test {{hello}} goodbye {{foo}} bar {foobar}'; let regex = /{{(.*?)}}/g; let match; let lastMatchIndex = 0; let results = []; while ( ( match = regex.exec( mystring ) ) !== null ) { results.push( mystring.substring( lastMatchIndex, match.index ) ); // adds static content up until match results.push( match[1] ); // adds dynamic matched content lastMatchIndex = regex.lastIndex; } results.push( mystring.substring( lastMatchIndex ) ); // adds static remainder of string console.log( results );