Búsqueda de sitios web

jquery - ¿Formatear una cadena de JavaScript usando marcadores de posición y un objeto de sustituciones?


Tengo una cadena que dice: Mi nombre es %NAME% y mi edad es %AGE%.

%XXX% son marcadores de posición. Necesitamos sustituir valores allí desde un objeto.

El objeto se ve así: {"%NAME%":"Mike","%AGE%":"26","%EVENT%":"20"}

Necesito analizar el objeto y reemplazar la cadena con los valores correspondientes. De modo que la salida final será:

Mi nombre es Mike y mi edad es 26.

Todo esto tiene que hacerse usando JavaScript puro o jQuery.

Respuesta #1

Los requisitos de la pregunta original claramente no podían beneficiarse de la interpolación de cadenas, ya que parece que es un procesamiento en tiempo de ejecución de claves de reemplazo arbitrarias.

Sin embargo, si solo tuvieras que hacer interpolación de cadenas, puedes usar:

const str = `My name is ${replacements.name} and my age is ${replacements.age}.`

Observe las comillas invertidas que delimitan la cadena, son necesarias.

Para una respuesta que se ajuste al requisito particular del OP, podrías usar String.prototype.replace() para los reemplazos.

El siguiente código manejará todos los emparejamientos y no tocará los que no tengan un reemplazo (siempre que todos sus valores de reemplazo sean cadenas, si no, vea más abajo).

var replacements = {"%NAME%":"Mike","%AGE%":"26","%EVENT%":"20"},
    str = 'My Name is %NAME% and my age is %AGE%.';

str = str.replace(/%\w+%/g, function(all) {
   return replacements[all] || all;
});

jsFiddle.

Si algunas de tus reemplazos no son cadenas, asegúrate de que existan en el objeto primero. Si tienes un formato como el del ejemplo, es decir, envuelto en signos de porcentaje, puedes usar el operador in para lograr esto.

jsFiddle.

Sin embargo, si tu formato no tiene un formato especial, es decir, cualquier cadena, y tu objeto de reemplazos no tiene un prototipo null, utiliza Object.prototype.hasOwnProperty(), a menos que puedas garantizar que ninguna de tus posibles subcadenas reemplazadas entrará en conflicto con los nombres de propiedades en el prototipo.

jsFiddle.

De lo contrario, si tu cadena de reemplazo fuera 'hasOwnProperty', obtendrías una cadena resultante desordenada.

jsFiddle.

Como nota al margen, deberías llamar replacements a un Object, no a un Array.

Respuesta #2

¿Qué tal usar literales de plantilla de ES6?

var a = "cat";
var b = "fat";
console.log(`my ${a} is ${b}`); //notice back-ticked string

Más sobre literales de plantilla...

Respuesta #3

Actualmente todavía no hay una solución nativa en Javascript para este comportamiento. Las plantillas con etiquetas son algo relacionado, pero no lo resuelven.

Aquí hay una refactorización de la solución de Alex con un objeto para reemplazos.

La solución utiliza funciones flecha y una syntaxis similar para los marcadores como la interpolación nativa de Javascript en literales de plantilla ({} en lugar de %%). Además, no es necesario incluir delimitadores (%) en los nombres de los reemplazos.

Hay dos sabores (tres con la actualización): descriptivo, reducido, reducido elegante con grupos.

Solución descriptiva:

const stringWithPlaceholders = 'My Name is {name} and my age is {age}.';

const replacements = {
  name: 'Mike',
  age: '26',
};

const string = stringWithPlaceholders.replace(
  /{\w+}/g,
  placeholderWithDelimiters => {
    const placeholderWithoutDelimiters = placeholderWithDelimiters.substring(
      1,
      placeholderWithDelimiters.length - 1,
    );
    const stringReplacement = replacements[placeholderWithoutDelimiters] || placeholderWithDelimiters;
    return stringReplacement;
  },
);

console.log(string);

Solución reducida:

const stringWithPlaceholders = 'My Name is {name} and my age is {age}.';

const replacements = {
  name: 'Mike',
  age: '26',
};

const string = stringWithPlaceholders.replace(/{\w+}/g, placeholder =>
  replacements[placeholder.substring(1, placeholder.length - 1)] || placeholder
);

console.log(string);

ACTUALIZACIÓN 2020-12-10

Solución reducida elegante con grupos, como sugirió @Kade en los comentarios:

const stringWithPlaceholders = 'My Name is {name} and my age is {age}.';

const replacements = {
  name: 'Mike',
  age: '26',
};

const string = stringWithPlaceholders.replace(
  /{(\w+)}/g, 
  (placeholderWithDelimiters, placeholderWithoutDelimiters) =>
    replacements[placeholderWithoutDelimiters] || placeholderWithDelimiters
);

console.log(string);

ACTUALIZACIÓN 2021-01-21

Admitir cadena vacía como reemplazo, como sugirió @Jesper en los comentarios:

const stringWithPlaceholders = 'My Name is {name} and my age is {age}.';

const replacements = {
  name: 'Mike',
  age: '',
};

const string = stringWithPlaceholders.replace(
  /{(\w+)}/g, 
  (placeholderWithDelimiters, placeholderWithoutDelimiters) =>
  replacements.hasOwnProperty(placeholderWithoutDelimiters) ? 
    replacements[placeholderWithoutDelimiters] : placeholderWithDelimiters
);

console.log(string);

Respuesta #4

Puedes usar JQuery (jquery.validate.js) para que funcione fácilmente.

$.validator.format("My name is {0}, I'm {1} years old",["Bob","23"]);

O si solo quieres usar esa característica, puedes definir esa función y simplemente usarla así

function format(source, params) {
    $.each(params,function (i, n) {
        source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n);
    })
    return source;
}
alert(format("{0} is a {1}", ["Michael", "Guy"]));

crédito al equipo de jquery.validate.js

Respuesta #5

Al igual que con los navegadores modernos, el marcador de posición es compatible con la nueva versión de Chrome/Firefox, similar a la función estilo C printf().

Marcadores de posición:

  • %s Cadena.
  • %d,%i Número entero.
  • %f Número de punto flotante.
  • Hipervínculo de objeto %o.

p. ej.

console.log("generation 0:\t%f, %f, %f", a1a1, a1a2, a2a2);

Por cierto, para ver el resultado:

  • En Chrome, usa el atajo Ctrl + Shift + J o F12 para abrir la herramienta de desarrollador.
  • En Firefox, usa el atajo Ctrl + Shift + K o F12 para abrir la herramienta de desarrollo.

@Actualización - soporte de nodejs

Parece que nodejs no soporta %f, en su lugar, se podría usar %d en nodejs. Con %d el número se imprimirá como número de punto flotante, no solo como entero.

Respuesta #6

Solo usa replace()

var values = {"%NAME%":"Mike","%AGE%":"26","%EVENT%":"20"};
var substitutedString = "My Name is %NAME% and my age is %AGE%.".replace("%NAME%", $values["%NAME%"]).replace("%AGE%", $values["%AGE%"]);

Artículos relacionados