Định dạng chuỗi JavaScript bằng cách sử dụng trình giữ chỗ và đối tượng thay thế?


92

Tôi có một chuỗi với nói: My Name is %NAME% and my age is %AGE%.

%XXX%là trình giữ chỗ. Chúng ta cần thay thế các giá trị ở đó từ một đối tượng.

Đối tượng trông giống như: {"%NAME%":"Mike","%AGE%":"26","%EVENT%":"20"}

Tôi cần phân tích cú pháp đối tượng và thay thế chuỗi bằng các giá trị tương ứng. Vì vậy, đầu ra cuối cùng sẽ là:

Tên tôi là Mike và tôi 26 tuổi.

Toàn bộ điều phải được thực hiện bằng cách sử dụng javascript hoặc jquery thuần túy.


2
Đó là vẻ bề ngoài giống như một đối tượng là một mảng
Joel Coehoorn

3
Bạn đã thử những gì cho đến nay? Bạn đã xem phương thức string .replace () chưa? (Ngoài ra, bạn không có mảng ở đó, bạn có một đối tượng.)
nnnnnn

1
Nó khá là xấu xí. Chắc chắn bạn sẽ được phục vụ tốt như vậy {NAME: "Mike", AGE: 26, EVENT: 20}? Tất nhiên, bạn vẫn yêu cầu các khóa này xuất hiện được liên kết bằng các dấu phần trăm trong chuỗi nhập.
davidchambers

Câu trả lời:


151

Các yêu cầu của câu hỏi ban đầu rõ ràng không thể hưởng lợi từ nội suy chuỗi, vì có vẻ như đó là một quá trình xử lý thời gian chạy của các khóa thay thế tùy ý.

Tuy nhiên , nếu bạn chỉ phải thực hiện nội suy chuỗi, bạn có thể sử dụng:

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

Lưu ý rằng các dấu gạch ngược phân cách chuỗi, chúng là bắt buộc.


Để có câu trả lời phù hợp với yêu cầu của OP cụ thể, bạn có thể sử dụng String.prototype.replace()cho các thay thế.

Mã sau sẽ xử lý tất cả các kết quả phù hợp và không chạm vào các kết quả mà không cần thay thế (miễn là các giá trị thay thế của bạn là tất cả các chuỗi, nếu không, hãy xem bên dưới).

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 .

Nếu một số thay thế của bạn không phải là chuỗi, trước tiên hãy đảm bảo rằng chúng tồn tại trong đối tượng. Nếu bạn có một định dạng như ví dụ, tức là được bao bọc trong các dấu phần trăm, bạn có thể sử dụng intoán tử để đạt được điều này.

jsFiddle .

Tuy nhiên, nếu định dạng của bạn không có định dạng đặc biệt, tức là bất kỳ chuỗi nào và đối tượng thay thế của bạn không có nullnguyên mẫu, hãy sử dụng Object.prototype.hasOwnProperty(), trừ khi bạn có thể đảm bảo rằng không có chuỗi con nào được thay thế tiềm năng của bạn sẽ xung đột với tên thuộc tính trên nguyên mẫu.

jsFiddle .

Ngược lại, nếu chuỗi thay thế của bạn là 'hasOwnProperty', bạn sẽ nhận được một chuỗi bị lộn xộn.

jsFiddle .


Lưu ý thêm, bạn nên được gọi là replacementsan Object, không phải an Array.


2
+1. Đẹp. Mặc dù bạn có thể muốn nói return replacements[all] || allđể bao gồm %NotInReplacementsList%các trường hợp.
nnnnnn

6
Điều này sẽ không hoạt động nếu giá trị thay thế là sai. Vì vậy, tốt hơn là sử dụng câu lệnh trả lại này:return all in params ? params[all] : all;
Michael Härtl,

@ MichaelHärtl Không nên thay thế của bạn tất cả đều là chuỗi sao? Nếu bạn muốn thay thế bằng chuỗi trống, tốt hơn hết hãy kiểm tra bằng các phương tiện khác.
alex

1
@alex Tôi đã gặp trường hợp thay thế cũng có thể là số nguyên và thậm chí 0. Trong trường hợp này, nó không hoạt động.
Michael Härtl

@ MichaelHärtl Đã cập nhật để bao gồm trường hợp đó.
alex

24

Làm thế nào về việc sử dụng các ký tự mẫu ES6?

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

Thông tin thêm về các ký tự mẫu ...


5
Nếu bạn có một đối tượng với các trình giữ chỗ như OP, thì nội suy chuỗi giúp được điều đó như thế nào?
alex

Hoạt động như một sự quyến rũ! Giải pháp thực dụng nhất cho vấn đề giữ chỗ của tôi, hoàn hảo.
BAERUS

Giải pháp này không hoạt động đối với các thiết bị thay thế thời gian chạy
Thierry J.

13

Bạn có thể sử dụng JQuery (jquery.validate.js) để làm cho nó hoạt động dễ dàng.

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

Hoặc nếu bạn chỉ muốn sử dụng tính năng đó, bạn có thể xác định chức năng đó và chỉ cần sử dụng nó như

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

tín dụng cho nhóm jquery.validate.js


1
Bạn chắc chắn sẽ không muốn tải plugin này chỉ vì điều này, nhưng tôi đã sử dụng plugin này để xác thực một biểu mẫu trên trang ... vì vậy cảm ơn vì mẹo này!
nabrown

1
Khá kém hiệu quả để tạo một regex cho mỗi số, tốt hơn là nên so khớp tất cả các số và sau đó thay thế bằng nếu giá trị được tìm thấy trong mảng, có lẽ?
alex

cho những người quan tâm, nó sẽ xảy ra ở đây: github.com/jquery-validation/jquery-validation/blob/master/src/…
Raphael C

1
+ Rất đẹp ... và $.eachbạn có thể làm 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;}, do đó bạn không cần phải bao gồm jquery chỉ cho một mà;)
Larphoid

11

Như với trình duyệt hiện đại, giữ chỗ được hỗ trợ bởi phiên bản mới của Chrome / Firefox, tương tự như chức năng C phong cách printf().

Phần giữ chỗ:

  • %s Chuỗi.
  • %d, %iSố nguyên.
  • %f Số điểm nổi.
  • %o Đối tượng siêu liên kết.

ví dụ

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

BTW, để xem đầu ra:

  • Trong Chrome, sử dụng phím tắt Ctrl + Shift + Jhoặc F12để mở công cụ dành cho nhà phát triển.
  • Trong Firefox, sử dụng phím tắt Ctrl + Shift + Khoặc F12để mở công cụ dành cho nhà phát triển.

@Update - hỗ trợ nodejs

Có vẻ như nodejs không hỗ trợ %f, thay vào đó, có thể sử dụng %dtrong nodejs. Với %dnumber sẽ được in dưới dạng số thực, không chỉ là số nguyên.



5

Bạn có thể sử dụng một chức năng thay thế tùy chỉnh như sau:

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

Bạn có thể thấy nó hoạt động tại đây: http://jsfiddle.net/jfriend00/DyCwk/ .


1
Tuyệt vời, Alex đã làm khá nhiều điều tương tự nhưng với ít dòng mã hơn (mặc dù các toán tử bậc ba có thể chậm hơn if..else).
RobG

Này, tôi đã cho bạn một +1! Cả hai bạn đã làm một chức năng thay thế, của bạn không hoàn toàn giống nhau nhưng khá giống nhau. RegExp của bạn cũng khác, OP sẽ tốt hơn nếu sử dụng %% hoặc $$ hoặc tương tự như các dấu phân cách - một% hoặc% có khả năng xảy ra trong một chuỗi bình thường, nhưng không thể xảy ra gấp đôi.
RobG

4

Nếu bạn muốn làm điều gì đó gần hơn với console.log như thay thế các trình giữ chỗ% s như trong

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

Tôi đã viết cái này

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"/>

bạn sẽ nhận được

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

CẬP NHẬT

Tôi đã thêm một biến thể đơn giản String.prototypehữu ích khi xử lý các phép biến đổi chuỗi, đây là nó:

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

Trong trường hợp đó bạn sẽ làm

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

Hãy thử phiên bản này tại đây


2
Tôi đã thực hiện một biến thể trên hàm của bạn mà không có nguyên mẫu, formatMessage(message: string, values: string[]) { let i = 0; return message.replace(/%\w+%/g, (match, idx) => { return values[i++]; }); } điều này sẽ nhận thông báo đến định dạng và mảng các giá trị thay thế và tìm kiếm%SOME_VALUE%
baku

3

Hiện tại vẫn chưa có giải pháp gốc trong Javascript cho hành vi này. Các mẫu được gắn thẻ là một cái gì đó có liên quan, nhưng không giải quyết được nó.

Ở đây có một cơ cấu lại của giải pháp alex với một đối tượng để thay thế.

Giải pháp sử dụng các hàm mũi têncú pháp tương tự cho các trình giữ chỗ như nội suy Javascript gốc trong các ký tự mẫu ( {}thay vì %%). Ngoài ra, không cần bao gồm dấu phân cách ( %) trong tên của các thay thế.

Có hai vị: trạch tả và gia giảm.

Giải pháp mô tả:

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

Giải pháp giảm:

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


1
Cảm ơn vì điều này, thật tuyệt khi có một giải pháp chung cho chuỗi giữ chỗ và một đối tượng để hợp nhất thành nó như thế này
Carlos P

@CarlosP, đó là ý tưởng, để có một giải pháp chung. Nhưng tôi nghĩ nó phải là một cái gì đó bản địa của ngôn ngữ, vì đó là một trường hợp sử dụng phổ biến.
AMS777

2

Điều này cho phép bạn làm chính xác điều đó

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

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

Bằng cách làm như sau:

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

// My username is tjcafferkey on Git

2
Nhưng vì bạn có thể làm điều đó trong es6 nên có lẽ hơi quá mức cần thiết?
IonicBurger

1
Điều này cho phép bạn lưu trữ chuỗi ở một nơi trong một định dạng và sau đó thay thế các mục tương ứng chỉ bằng một hàm. Đó là kiến ​​thức của tôi không thể làm với các nghĩa đen mẫu es6. Một cách sử dụng cho điều này sẽ ví dụ như các chuỗi dịch, nơi bạn sẽ sử dụng chuỗi ở nơi khác và đưa các giá trị mong muốn vào đó.
Johan Persson

2

Đây là một cách khác để thực hiện việc này bằng cách sử dụng các nghĩa đen của mẫu es6 động trong thời gian chạy.

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


1

Ví dụ nhanh:

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

Đầu ra là:

jack đã 40 tuổi


7
Điều đó thật tuyệt, trừ khi bạn muốn làm gì đó ngoài việc đăng nhập vào bảng điều khiển.
alex

13
điều đó không nên console.log?
drzaus

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

Tôi đã viết một đoạn mã cho phép bạn định dạng chuỗi dễ dàng.

Sử dụng chức năng này.

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

Thí dụ

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

Đầu ra

Tên tôi là Mike và tôi 26 tuổi

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.