จัดรูปแบบสตริง JavaScript โดยใช้ตัวยึดตำแหน่งและวัตถุแทนหรือไม่


92

ฉันมีสตริงที่พูดว่า: My Name is %NAME% and my age is %AGE%.

%XXX%เป็นตัวยึดตำแหน่ง เราจำเป็นต้องแทนที่ค่าจากวัตถุ

วัตถุดูเหมือนว่า: {"%NAME%":"Mike","%AGE%":"26","%EVENT%":"20"}

ฉันต้องการแยกวิเคราะห์วัตถุและแทนที่สตริงด้วยค่าที่เกี่ยวข้อง ดังนั้นผลลัพธ์สุดท้ายจะเป็น:

ฉันชื่อไมค์และฉันอายุ 26

สิ่งทั้งหมดจะต้องทำโดยใช้ javascript หรือ jquery ที่บริสุทธิ์


2
ดูเหมือนวัตถุมากกว่าอาร์เรย์
Joel Coehoorn

3
คุณได้ลองทำอะไรมาบ้าง? คุณได้ดูวิธีสตริง. replace () แล้วหรือยัง? (นอกจากนี้คุณยังไม่มีอาร์เรย์คุณมีวัตถุ)
nnnnnn

1
น่าเกลียดทีเดียว แน่นอนคุณจะได้รับบริการเช่นกัน{NAME: "Mike", AGE: 26, EVENT: 20}? คุณยังคงต้องการให้คีย์เหล่านี้ปรากฏขึ้นโดยเครื่องหมายเปอร์เซ็นต์ในสตริงอินพุตแน่นอน
davidchambers

คำตอบ:


152

ข้อกำหนดของคำถามเดิมไม่สามารถใช้ประโยชน์จากการแก้ไขสตริงได้อย่างชัดเจนเนื่องจากดูเหมือนว่าเป็นการประมวลผลรันไทม์ของคีย์ทดแทนโดยพลการ

อย่างไรก็ตามหากคุณต้องทำการแก้ไขสตริงคุณสามารถใช้:

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

สังเกตแบ็กติกที่คั่นสตริงซึ่งเป็นสิ่งจำเป็น


สำหรับคำตอบที่ตรงกับความต้องการของ OP คุณสามารถใช้String.prototype.replace()สำหรับการเปลี่ยนได้

รหัสต่อไปนี้จะจัดการการจับคู่ทั้งหมดและไม่แตะต้องโดยไม่มีการแทนที่ (ตราบใดที่ค่าการแทนที่ของคุณเป็นสตริงทั้งหมดหากไม่เป็นเช่นนั้นโปรดดูด้านล่าง)

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

หากการแทนที่บางรายการของคุณไม่ใช่สตริงตรวจสอบให้แน่ใจว่ามีอยู่ในวัตถุก่อน หากคุณมีรูปแบบดังตัวอย่างเช่นมีเครื่องหมายเปอร์เซ็นต์คุณสามารถใช้ตัวinดำเนินการเพื่อให้บรรลุสิ่งนี้

jsFiddle

อย่างไรก็ตามหากรูปแบบของคุณไม่มีรูปแบบพิเศษเช่นสตริงใด ๆ และอ็อบเจ็กต์การแทนที่ของคุณไม่มีnullต้นแบบให้ใช้Object.prototype.hasOwnProperty()เว้นแต่คุณจะสามารถรับประกันได้ว่าสตริงย่อยที่ถูกแทนที่ที่เป็นไปได้ของคุณจะไม่ขัดแย้งกับชื่อคุณสมบัติบนต้นแบบ

jsFiddle

มิฉะนั้นหากสตริงแทนที่ของคุณเป็น'hasOwnProperty'คุณจะได้รับผลลัพธ์ที่ยุ่งเหยิงสตริง

jsFiddle


ตามหมายเหตุด้านข้างคุณควรเรียกว่าreplacementsan Objectไม่ใช่Array.


2
+1. ดี. แม้ว่าคุณอาจต้องการพูดreturn replacements[all] || allให้ครอบคลุม%NotInReplacementsList%กรณีต่างๆ
nnnnnn

6
สิ่งนี้จะไม่ทำงานหากค่าการแทนที่เป็นเท็จ ดังนั้นจึงควรใช้คำสั่งส่งคืนนี้:return all in params ? params[all] : all;
Michael Härtl

@ MichaelHärtlการแทนที่ของคุณไม่ควรเป็นสตริงหรือไม่? หากคุณต้องการแทนที่ด้วยสตริงว่างให้ตรวจสอบด้วยวิธีอื่นดีกว่า
alex

1
alex @ 0ฉันมีสถานการณ์ที่เปลี่ยนยังอาจเป็นจำนวนเต็มและแม้กระทั่ง ในกรณีนี้ไม่ได้ผล
Michael Härtl

@ MichaelHärtlอัปเดตเพื่อให้ครอบคลุมกรณีดังกล่าว
alex

24

แล้วการใช้ตัวอักษรเทมเพลต ES6 เป็นอย่างไร?

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

ข้อมูลเพิ่มเติมเกี่ยวกับตัวอักษรเทมเพลต ...


5
หากคุณมีวัตถุที่มีตัวยึดตำแหน่งเช่น OP การแก้ไขสตริงจะช่วยได้อย่างไร
alex

ใช้งานได้เหมือนมีเสน่ห์! วิธีแก้ปัญหาในเชิงปฏิบัติส่วนใหญ่สำหรับปัญหาการยึดตำแหน่งของฉันสมบูรณ์แบบ
BAERUS

วิธีนี้ใช้ไม่ได้กับการเปลี่ยนรันไทม์
Thierry J.

13

คุณสามารถใช้ JQuery (jquery.validate.js) เพื่อให้ทำงานได้อย่างง่ายดาย

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

หรือหากคุณต้องการใช้เพียงคุณสมบัตินั้นคุณสามารถกำหนดฟังก์ชันนั้นและใช้งานได้เช่น

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

เครดิตทีม jquery.validate.js


1
แน่นอนคุณไม่ต้องการโหลดปลั๊กอินนี้เพื่อสิ่งนี้ แต่ฉันใช้สิ่งนี้เพื่อตรวจสอบความถูกต้องของแบบฟอร์มบนหน้าอยู่แล้ว ... ขอบคุณสำหรับเคล็ดลับ!
nabrown

1
ค่อนข้างไม่มีประสิทธิภาพในการสร้าง regex สำหรับแต่ละหมายเลขมันจะดีกว่าถ้าจับคู่ตัวเลขทั้งหมดแล้วแทนที่หากพบค่าในอาร์เรย์หรือไม่?
alex

สำหรับผู้ที่สนใจสามารถดูได้ที่นี่: github.com/jquery-validation/jquery-validation/blob/master/src/…
Raphael C

1
+ ดีมาก ... และสำหรับ$.eachคุณสามารถทำได้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;}ดังนั้นคุณไม่จำเป็นต้องรวม jquery ไว้สำหรับสิ่งนั้นเท่านั้น;)
Larphoid

11

เช่นเดียวกับเบราว์เซอร์ที่ทันสมัยยึดได้รับการสนับสนุนโดยรุ่นใหม่ของ Chrome / Firefox, printf()เช่นเดียวกับฟังก์ชั่นสไตล์ซี

ตัวยึดตำแหน่ง:

  • %s สตริง
  • %d, %iเลขจำนวนเต็ม.
  • %f เลขจุดลอย
  • %o การเชื่อมโยงหลายมิติของวัตถุ

เช่น

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

BTW เพื่อดูผลลัพธ์:

  • ใน Chrome ให้ใช้ทางลัดCtrl + Shift + JหรือF12เพื่อเปิดเครื่องมือสำหรับนักพัฒนา
  • ใน Firefox ใช้ทางลัดCtrl + Shift + KหรือF12เพื่อเปิดเครื่องมือสำหรับนักพัฒนา

@Update - รองรับ nodejs

ดูเหมือนว่า nodejs จะไม่รองรับ%fแต่สามารถใช้%dใน nodejs ได้ ด้วย%dตัวเลขจะถูกพิมพ์เป็นตัวเลขลอยไม่ใช่แค่จำนวนเต็ม


6

เพียงแค่ใช้ 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%"]);

3
บังคับ "โปรดใช้ MDN เป็นข้อมูลอ้างอิง": developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
mu สั้นเกินไป

2
ขอบคุณสำหรับคนตบ - ชื่นชม;)
hafichuk

5

คุณสามารถใช้ฟังก์ชันการแทนที่แบบกำหนดเองได้ดังนี้:

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

คุณสามารถดูได้ทำงานที่นี่: http://jsfiddle.net/jfriend00/DyCwk/


1
เจ๋งมากอเล็กซ์ทำสิ่งเดียวกัน แต่ใช้โค้ดน้อยลง (แม้ว่าตัวดำเนินการที่เกี่ยวข้องจะช้ากว่า if.else)
RobG

เฮ้ฉันให้ +1! คุณทั้งคู่ทำหน้าที่แทนที่ของคุณไม่เหมือนกัน แต่ค่อนข้างคล้ายกัน RegExp ของคุณก็แตกต่างกันเช่นกัน OP จะดีกว่าถ้าใช้ %% หรือ $$ หรือคล้ายกันเป็นตัวคั่น -% เดียวหรือ% มีแนวโน้มที่จะเกิดขึ้นในสตริงตามปกติ แต่ไม่น่าจะเกิดขึ้นเป็นสองเท่า
RobG

4

หากคุณต้องการทำบางสิ่งที่ใกล้เคียงกับ console.log เช่นการแทนที่ตัวยึดตำแหน่ง% s เช่นใน

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

ฉันเขียนสิ่งนี้

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

คุณจะได้รับ

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

อัปเดต

ฉันได้เพิ่มตัวแปรง่ายๆที่String.prototypeมีประโยชน์เมื่อจัดการกับการแปลงสตริงแล้วนี่คือ:

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

ในกรณีนี้คุณจะทำ

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

ลองรุ่นนี้ที่นี่


2
ฉันสร้างรูปแบบในฟังก์ชันของคุณโดยไม่มีต้นแบบformatMessage(message: string, values: string[]) { let i = 0; return message.replace(/%\w+%/g, (match, idx) => { return values[i++]; }); } ซึ่งจะใช้ข้อความในการจัดรูปแบบและอาร์เรย์ของค่าแทนที่และค้นหา%SOME_VALUE%
baku

4

ขณะนี้ยังไม่มีโซลูชันดั้งเดิมใน Javascript สำหรับพฤติกรรมนี้ เทมเพลตที่ติดแท็กเป็นสิ่งที่เกี่ยวข้อง แต่อย่าแก้ปัญหา

ที่นี่มี refactor ของโซลูชันของ alexพร้อมกับวัตถุสำหรับเปลี่ยน

โซลูชันนี้ใช้ฟังก์ชันลูกศรและไวยากรณ์ที่คล้ายกันสำหรับตัวยึดตำแหน่งเป็นการแก้ไข Javascript ดั้งเดิมในตัวอักษรเทมเพลต ( {}แทน%%) นอกจากนี้ไม่จำเป็นต้องใส่ตัวคั่น ( %) ในชื่อของการแทนที่

มีสองรสชาติ: บรรยายและลด

วิธีการอธิบาย:

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

โซลูชันที่ลดลง:

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
ขอบคุณสำหรับสิ่งนี้เป็นเรื่องดีที่มีโซลูชันทั่วไปสำหรับสตริงตัวยึดตำแหน่งและวัตถุที่จะรวมเข้าด้วยกันเช่นนี้
Carlos P

@CarlosP นั่นคือความคิดที่จะมีวิธีแก้ปัญหาทั่วไป แต่ฉันคิดว่ามันควรเป็นสิ่งที่มาจากภาษาเนื่องจากเป็นกรณีการใช้งานทั่วไป
AMS777

1
สามารถทำให้ง่ายขึ้นอีกเล็กน้อยโดยใช้กลุ่ม regex ดังนี้stringWithPlaceholders.replace(/{(\w+)}/g, (fullMatch, group1) => replacements[group1] || fullMatch )
Kade

2

สิ่งนี้ช่วยให้คุณทำอย่างนั้นได้

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

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

โดยดำเนินการดังต่อไปนี้:

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

// My username is tjcafferkey on Git

2
แต่เนื่องจากคุณสามารถทำได้ใน es6 ซึ่งอาจจะมากเกินไป?
IonicBurger

1
วิธีนี้ช่วยให้คุณจัดเก็บสตริงไว้ในที่เดียวในรูปแบบเดียวจากนั้นในภายหลังแทนที่รายการที่เกี่ยวข้องโดยใช้เพียงฟังก์ชันเดียว นั่นคือความรู้ของฉันไม่สามารถทำกับตัวอักษรเทมเพลต es6 ได้ การใช้งานสำหรับสิ่งนี้เช่นสตริงการแปลซึ่งคุณจะใช้สตริงที่อื่นและฉีดค่าที่ต้องการที่นั่น
Johan Persson

2

นี่เป็นอีกวิธีหนึ่งในการดำเนินการนี้โดยใช้ตัวอักษรเทมเพลต es6 แบบไดนามิกที่รันไทม์

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

เป็นตัวอย่างสั้น ๆ :

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

ผลลัพธ์คือ:

แจ็คอายุ 40 ปี


7
เยี่ยมมากเว้นแต่คุณต้องการทำอะไรบางอย่างนอกเหนือจากบันทึกลงในคอนโซล
alex

13
ไม่ควรอย่างนั้น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

ฉันได้เขียนโค้ดที่ช่วยให้คุณจัดรูปแบบสตริงได้อย่างง่ายดาย

ใช้ฟังก์ชันนี้

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

ตัวอย่าง

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

เอาต์พุต

ฉันชื่อไมค์และฉันอายุ 26

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.