Formatieren Sie eine JavaScript-Zeichenfolge mit Platzhaltern und einem Objekt mit Ersetzungen?


91

Ich habe eine Zeichenfolge mit sagen: My Name is %NAME% and my age is %AGE%.

%XXX%sind Platzhalter. Wir müssen dort Werte durch ein Objekt ersetzen.

Objekt sieht aus wie: {"%NAME%":"Mike","%AGE%":"26","%EVENT%":"20"}

Ich muss das Objekt analysieren und die Zeichenfolge durch entsprechende Werte ersetzen. Die endgültige Ausgabe lautet also:

Mein Name ist Mike und ich bin 26 Jahre alt.

Das Ganze muss entweder mit reinem Javascript oder mit jquery gemacht werden.


2
Das sieht eher nach einem Objekt als nach einem Array aus
Joel Coehoorn

3
Was hast du bisher versucht? Haben Sie sich die Methode string .replace () angesehen ? (Außerdem haben Sie dort kein Array, Sie haben ein Objekt.)
nnnnnn

1
Das ist ziemlich hässlich. Sicherlich würden Sie genauso gut bedient sein {NAME: "Mike", AGE: 26, EVENT: 20}? Natürlich müssen diese Schlüssel weiterhin mit Prozentzeichen in der Eingabezeichenfolge versehen sein.
Davidchambers

Antworten:


144

Die Anforderungen der ursprünglichen Frage konnten eindeutig nicht von der Zeichenfolgeninterpolation profitieren, da es sich anscheinend um eine Laufzeitverarbeitung beliebiger Ersatzschlüssel handelt.

Allerdings , wenn Sie nur String - Interpolation zu tun haben, können Sie:

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

Beachten Sie die Backticks, die die Zeichenfolge begrenzen. Sie sind erforderlich.


Für eine Antwort, die den Anforderungen des jeweiligen OP entspricht, können Sie diese String.prototype.replace()als Ersatz verwenden.

Der folgende Code behandelt alle Übereinstimmungen und berührt keine ohne Ersatz (solange Ihre Ersatzwerte alle Zeichenfolgen sind, falls nicht, siehe unten).

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 .

Wenn einige Ihrer Ersetzungen keine Zeichenfolgen sind, stellen Sie sicher, dass sie zuerst im Objekt vorhanden sind. Wenn Sie ein Format wie das Beispiel haben, dh in Prozentzeichen eingeschlossen, können Sie den inOperator verwenden, um dies zu erreichen.

jsFiddle .

Wenn Ihr Format jedoch kein spezielles Format hat, dh keine Zeichenfolge, und Ihr Ersatzobjekt keinen nullPrototyp hat, verwenden Sie es Object.prototype.hasOwnProperty(), es sei denn, Sie können garantieren, dass keine Ihrer potenziell ersetzten Teilzeichenfolgen mit den Eigenschaftsnamen des Prototyps kollidiert.

jsFiddle .

Andernfalls würden Sie, wenn Ihre Ersatzzeichenfolge 'hasOwnProperty'wäre, eine resultierende durcheinandergebrachte Zeichenfolge erhalten.

jsFiddle .


Als Randnotiz sollten Sie replacementsein Object, nicht ein genannt werden Array.


2
+1. Nett. Obwohl Sie vielleicht sagen möchten return replacements[all] || all, um %NotInReplacementsList%Fälle abzudecken .
nnnnnn

5
Dies funktioniert nicht, wenn der Ersatzwert falsch ist. Daher ist es besser, diese Rückgabeerklärung zu verwenden:return all in params ? params[all] : all;
Michael Härtl

@ MichaelHärtl Sollten Ihre Ersetzungen nicht alle Saiten sein? Wenn Sie durch eine leere Zeichenfolge ersetzen möchten, sollten Sie dies mit anderen Mitteln überprüfen.
alex

1
@alex Ich hatte die Situation, in der Ersetzungen auch ganze Zahlen sein könnten, und sogar 0. In diesem Fall hat es nicht funktioniert.
Michael Härtl

@ MichaelHärtl Aktualisiert, um diesen Fall abzudecken.
Alex

23

Wie wäre es mit ES6-Vorlagenliteralen?

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

Mehr über Vorlagenliterale ...


5
Wenn Sie ein Objekt mit Platzhaltern wie dem OP haben, wie hilft die String-Interpolation dabei?
Alex

Klappt wunderbar! Die pragmatischste Lösung für meine Platzierungsprobleme, perfekt.
BAERUS

Diese Lösung funktioniert nicht für Laufzeitersetzungen
Thierry J.

12

Sie können JQuery (jquery.validate.js) verwenden, damit es problemlos funktioniert.

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

Oder wenn Sie nur diese Funktion verwenden möchten, können Sie diese Funktion definieren und einfach so verwenden

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"]));

Gutschrift an das Team von jquery.validate.js


1
Sie möchten dieses Plugin definitiv nicht nur dafür laden, aber ich verwende es bereits, um ein Formular auf der Seite zu validieren ... also danke für den Tipp!
Nabrown

1
Es ist ziemlich ineffizient, für jede Zahl einen regulären Ausdruck zu erstellen. Es ist besser, alle Zahlen abzugleichen und dann zu ersetzen, wenn der Wert im Array gefunden wurde.
Alex


1
+ sehr schön ... und für $.eachSie könnte machen, String.prototype.format=function(p){var s=this,r=function(v,i){s=s.replace(new RegExp("\\{"+i+"\\}","g"),v);};p.forEach(r);return s;}damit Sie jquery nicht nur für diese einschließen müssen;)
Larphoid

11

Wie bei einem modernen Browser wird der Platzhalter von der neuen Version von Chrome / Firefox unterstützt, ähnlich wie bei der C-Funktion printf().

Platzhalter:

  • %s String.
  • %d, %iGanzzahl.
  • %f Gleitkommazahl.
  • %o Objekt-Hyperlink.

z.B

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

Übrigens, um die Ausgabe zu sehen:

  • Verwenden Sie in Chrome die Verknüpfung Ctrl + Shift + Joder F12, um das Entwicklertool zu öffnen.
  • Verwenden Sie in Firefox die Verknüpfung Ctrl + Shift + Koder F12, um das Entwicklertool zu öffnen.

@Update - Unterstützung von nodejs

Scheint, dass NodeJS nicht unterstützen %f, sondern %din NodeJS verwendet werden könnten. Mit %dNummer wird als Gleitkommazahl gedruckt, nicht nur als Ganzzahl.



5

Sie können eine benutzerdefinierte Ersetzungsfunktion wie folgt verwenden:

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

function substitute(str, data) {
    var output = str.replace(/%[^%]+%/g, function(match) {
        if (match in data) {
            return(data[match]);
        } else {
            return("");
        }
    });
    return(output);
}

var output = substitute(str, replaceData);

Sie können sehen, dass es hier funktioniert: http://jsfiddle.net/jfriend00/DyCwk/ .


1
Cool, Alex hat so ziemlich genau das Gleiche getan, aber in weniger Codezeilen (obwohl ternäre Operatoren wahrscheinlich langsamer sind als wenn ... sonst).
RobG

Hey, ich habe dir eine +1 gegeben! Sie haben beide eine Ersetzungsfunktion ausgeführt, Ihre ist nicht genau gleich, aber ziemlich ähnlich. Ihr RegExp ist auch anders. Das OP ist besser dran, wenn Sie %% oder $$ oder ähnliches als Trennzeichen verwenden. Ein einzelnes% oder% tritt normalerweise in einer Zeichenfolge auf, aber Doppelungen sind unwahrscheinlich.
RobG

4

Wenn Sie etwas näher an console.log tun möchten, z. B.% s Platzhalter wie in ersetzen

>console.log("Hello %s how are you %s is everything %s?", "Loreto", "today", "allright")
>Hello Loreto how are you today is everything allright?

Ich habe das geschrieben

function log() {
  var args = Array.prototype.slice.call(arguments);
  var rep= args.slice(1, args.length);
  var i=0;
  var output = args[0].replace(/%s/g, function(match,idx) {
    var subst=rep.slice(i, ++i);
    return( subst );
  });
   return(output);
}
res=log("Hello %s how are you %s is everything %s?", "Loreto", "today", "allright");
document.getElementById("console").innerHTML=res;
<span id="console"/>

Sie erhalten

>log("Hello %s how are you %s is everything %s?", "Loreto", "today", "allright")
>"Hello Loreto how are you today is everything allright?"

AKTUALISIEREN

Ich habe eine einfache Variante hinzugefügt String.prototype, die beim Umgang mit String-Transformationen nützlich ist. Hier ist sie:

String.prototype.log = function() {
    var args = Array.prototype.slice.call(arguments);
    var rep= args.slice(0, args.length);
    var i=0;
    var output = this.replace(/%s|%d|%f|%@/g, function(match,idx) {
      var subst=rep.slice(i, ++i);
      return( subst );
    });
    return output;
   }

In diesem Fall werden Sie tun

"Hello %s how are you %s is everything %s?".log("Loreto", "today", "allright")
"Hello Loreto how are you today is everything allright?"

Versuchen Sie diese Version hier


2
Ich habe eine Variation Ihrer Funktion ohne Prototypen vorgenommen. formatMessage(message: string, values: string[]) { let i = 0; return message.replace(/%\w+%/g, (match, idx) => { return values[i++]; }); } Dies %SOME_VALUE%
erfordert eine

2

So können Sie genau das tun

NPM: https://www.npmjs.com/package/stringinject

GitHub: https://github.com/tjcafferkey/stringinject

Gehen Sie wie folgt vor:

var str = stringInject("My username is {username} on {platform}", { username: "tjcafferkey", platform: "GitHub" });

// My username is tjcafferkey on Git

2
Aber da Sie es in es6 tun können, ist das wahrscheinlich ein bisschen übertrieben?
IonicBurger

1
Auf diese Weise können Sie die Zeichenfolge an einem Ort in einem Format speichern und zu einem späteren Zeitpunkt die entsprechenden Elemente mit nur einer Funktion ersetzen. Das ist meines Wissens mit es6-Template-Literalen nicht möglich. Eine Verwendung hierfür wären beispielsweise Übersetzungszeichenfolgen, bei denen Sie die Zeichenfolge an anderer Stelle verwenden und dort die gewünschten Werte einfügen.
Johan Persson

2

Als schnelles Beispiel:

var name = 'jack';
var age = 40;
console.log('%s is %d yrs old',name,age);

Die Ausgabe ist:

Jack ist 40 Jahre alt


6
Das ist großartig, es sei denn, Sie möchten etwas anderes tun, als es in der Konsole zu protokollieren.
Alex

13
sollte nicht so sein console.log?
Drzaus

2

Hier ist eine andere Möglichkeit, dies zu tun, indem es6-Vorlagenliterale zur Laufzeit dynamisch verwendet werden.

const str = 'My name is ${name} and my age is ${age}.'
const obj = {name:'Simon', age:'33'}


const result = new Function('const {' + Object.keys(obj).join(',') + '} = this.obj;return `' + str + '`').call({obj})

document.body.innerHTML = result


0
const stringInject = (str = '', obj = {}) => {
  let newStr = str;
  Object.keys(obj).forEach((key) => {
    let placeHolder = `#${key}#`;
    if(newStr.includes(placeHolder)) {
      newStr = newStr.replace(placeHolder, obj[key] || " ");
    }
  });
  return newStr;
}
Input: stringInject("Hi #name#, How are you?", {name: "Ram"});
Output: "Hi Ram, How are you?"

0

Ich habe einen Code geschrieben, mit dem Sie Zeichenfolgen einfach formatieren können.

Verwenden Sie diese Funktion.

function format() {
    if (arguments.length === 0) {
        throw "No arguments";
    }
    const string = arguments[0];
    const lst = string.split("{}");
    if (lst.length !== arguments.length) {
        throw "Placeholder format mismatched";
    }
    let string2 = "";
    let off = 1;
    for (let i = 0; i < lst.length; i++) {
        if (off < arguments.length) {
            string2 += lst[i] + arguments[off++]
        } else {
            string2 += lst[i]
        }
    }
    return string2;
}

Beispiel

format('My Name is {} and my age is {}', 'Mike', 26);

Ausgabe

Mein Name ist Mike und ich bin 26 Jahre alt


0

Derzeit gibt es in Javascript noch keine native Lösung für dieses Verhalten. Mit Tags versehene Vorlagen sind verwandt, lösen sie jedoch nicht.

Hier gibt es einen Refaktor von Alex 'Lösung mit einem Objekt zum Ersetzen.

Die Lösung verwendet Pfeilfunktionen und eine ähnliche Syntax für die Platzhalter wie die native Javascript- Interpolation in Vorlagenliteralen ( {}anstelle von %%). Es ist auch nicht erforderlich, Trennzeichen ( %) in die Namen der Ersetzungen aufzunehmen.

Es gibt zwei Geschmacksrichtungen: beschreibend und reduziert.

Beschreibende Lösung:

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);

Reduzierte Lösung:

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);

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.