Setara dengan String.format di jQuery


Jawaban:


193

The kode sumber untuk ASP.NET AJAX tersedia untuk referensi Anda, sehingga Anda dapat memilih melalui itu dan termasuk bagian-bagian yang Anda ingin terus menggunakan ke file JS yang terpisah. Atau, Anda bisa porting mereka ke jQuery.

Ini adalah fungsi format ...

String.format = function() {
  var s = arguments[0];
  for (var i = 0; i < arguments.length - 1; i++) {       
    var reg = new RegExp("\\{" + i + "\\}", "gm");             
    s = s.replace(reg, arguments[i + 1]);
  }

  return s;
}

Dan inilah ujungnyaDengan dan mulaiDengan fungsi prototipe ...

String.prototype.endsWith = function (suffix) {
  return (this.substr(this.length - suffix.length) === suffix);
}

String.prototype.startsWith = function(prefix) {
  return (this.substr(0, prefix.length) === prefix);
}

2
Sepertinya tidak banyak. Versi JavaScript tidak memiliki semua hal yang memformat angka mewah. blog.stevex.net/index.php/string-formatting-in-csharp
Nosredna

Wow, saya sebenarnya sudah memikirkan hal ini tetapi juga berpikir itu tidak mungkin karena lisensi, tidak tahu mereka merilisnya di bawah Microsoft Permissive Licence, terima kasih banyak untuk ini
Waleed Eissa

23
Lisensi atau tanpa lisensi .. hanya ada satu cara yang tepat untuk menulis sesuatu yang sangat sederhana
adamJLev

1
Membangun (dan kemudian membuang) objek RegEx untuk masing-masing dan setiap argumen setiap format waktu dipanggil mungkin melebih-lebihkan pengumpul sampah.
mckoss

14
Peringatan: Ini akan memformat secara rekursif: jadi jika sudah {0}{1}, {0}akan diganti terlebih dahulu, dan kemudian semua kemunculan {1}dalam teks yang sudah diganti dan format aslinya akan diganti.
Zenexer

147

Ini adalah variasi lebih cepat / sederhana (dan prototipikal) dari fungsi yang diposting Josh:

String.prototype.format = String.prototype.f = function() {
    var s = this,
        i = arguments.length;

    while (i--) {
        s = s.replace(new RegExp('\\{' + i + '\\}', 'gm'), arguments[i]);
    }
    return s;
};

Pemakaian:

'Added {0} by {1} to your collection'.f(title, artist)
'Your balance is {0} USD'.f(77.7) 

Saya menggunakan ini sangat banyak sehingga saya hanya menyamakannya f, tetapi Anda juga dapat menggunakan lebih banyak verbose format. misalnya'Hello {0}!'.format(name)


1
Dengan browser modern, ada pendekatan yang bahkan lebih sederhana: stackoverflow.com/a/41052964/120296
david

3
@david Template string TIDAK sama dengan hal yang sama sekali. Mereka adalah gula sintaksis untuk penggabungan string, yang bagus tetapi tidak sama dengan format. Mereka berjalan secara instan, oleh karena itu, penggantian harus dalam ruang lingkup pada titik definisi. Anda tidak dapat menyimpannya dalam file teks atau database karena ini. Bahkan, satu-satunya cara untuk menyimpannya di mana saja adalah dengan meletakkannya di suatu fungsi. Fungsi string yang diformat membutuhkan penggantian posisi yang tidak peduli tentang nama variabel.
krowe2

131

Banyak fungsi di atas (kecuali milik Julian Jelfs) mengandung kesalahan berikut:

js> '{0} {0} {1} {2}'.format(3.14, 'a{2}bc', 'foo');
3.14 3.14 afoobc foo

Atau, untuk varian yang menghitung mundur dari akhir daftar argumen:

js> '{0} {0} {1} {2}'.format(3.14, 'a{0}bc', 'foo');
3.14 3.14 a3.14bc foo

Inilah fungsi yang benar. Ini adalah varian prototip dari kode Julian Jelfs, yang saya buat sedikit lebih ketat:

String.prototype.format = function () {
  var args = arguments;
  return this.replace(/\{(\d+)\}/g, function (m, n) { return args[n]; });
};

Dan di sini adalah versi yang sedikit lebih maju dari yang sama, yang memungkinkan Anda untuk keluar dari kawat gigi dengan menggandakannya:

String.prototype.format = function () {
  var args = arguments;
  return this.replace(/\{\{|\}\}|\{(\d+)\}/g, function (m, n) {
    if (m == "{{") { return "{"; }
    if (m == "}}") { return "}"; }
    return args[n];
  });
};

Ini berfungsi dengan benar:

js> '{0} {{0}} {{{0}}} {1} {2}'.format(3.14, 'a{2}bc', 'foo');
3.14 {0} {3.14} a{2}bc foo

Berikut ini adalah implementasi bagus lainnya oleh Blair Mitchelmore, dengan banyak fitur tambahan yang bagus: https://web.archive.org/web/20120315214858/http://blairmitchelmore.com/javascript/string.format


Dan satu lagi, yang saya tidak melihat terlalu dekat, tapi yang tampaknya menerapkan format seperti {0: + $ #, 0.00; - $ #, 0.00; 0}: masterdata.dyndns.org/r/string_format_for_javascript
gpvos

Ooh, dan yang menggunakan format interpolasi Python: code.google.com/p/jquery-utils/wiki/…
gpvos

Pelaksanaan format yang saya sebutkan dua komentar up telah pindah ke masterdata.se/r/string_format_for_javascript
gpvos

Catatan: jawaban ianj di tempat lain di halaman ini memungkinkan Anda untuk menggunakan nama daripada parameter numerik. Jika Anda mengubah metodenya menjadi yang menggunakan prototipe, Anda harus mengubah parameter kedua ke fungsi slice.call dari 1 menjadi 0.
gpvos

48

Membuat fungsi format yang mengambil koleksi atau array sebagai argumen

Pemakaian:

format("i can speak {language} since i was {age}",{language:'javascript',age:10});

format("i can speak {0} since i was {1}",'javascript',10});

Kode:

var format = function (str, col) {
    col = typeof col === 'object' ? col : Array.prototype.slice.call(arguments, 1);

    return str.replace(/\{\{|\}\}|\{(\w+)\}/g, function (m, n) {
        if (m == "{{") { return "{"; }
        if (m == "}}") { return "}"; }
        return col[n];
    });
};

5
Yang bagus, semua yang hilang adalah: String.prototype.format = function (col) {format pengembalian (this, col);}
Erik

10
saya lebih suka untuk tidak memperpanjang string
ianj

3
ada kesalahan ketik kecil dalam penggunaan: baris ke-2 harus: format ("saya dapat berbicara {0} sejak saya {1}", 'javascript', 10);
Guillaume Gendre

Mengapa tidak memilih memperpanjang menggunakan string String.prototype?
Kiquenet

36

Ada (agak) opsi resmi: jQuery.validator.format .

Dilengkapi dengan jQuery Validation Plugin 1.6 (setidaknya).
Cukup mirip dengan yang String.Formatditemukan di .NET.

Edit tautan rusak Tetap.



13

Meskipun tidak persis apa yang diminta Q, saya telah membangun yang serupa tetapi menggunakan placeholder yang dinamai bukan bernomor. Saya pribadi lebih suka menyebutkan argumen dan hanya mengirim objek sebagai argumen untuk itu (lebih verbose, tetapi lebih mudah untuk mempertahankan).

String.prototype.format = function (args) {
    var newStr = this;
    for (var key in args) {
        newStr = newStr.replace('{' + key + '}', args[key]);
    }
    return newStr;
}

Berikut ini contoh penggunaan ...

alert("Hello {name}".format({ name: 'World' }));

8

Menggunakan browser modern, yang mendukung EcmaScript 2015 (ES6), Anda dapat menikmati String Template . Alih-alih memformat, Anda dapat langsung menyuntikkan nilai variabel ke dalamnya:

var name = "Waleed";
var message = `Hello ${name}!`;

Perhatikan bahwa string templat harus ditulis menggunakan tanda tik kembali (`).


6

Tidak ada jawaban yang disajikan sejauh ini yang tidak memiliki optimalisasi penggunaan enklosur untuk menginisialisasi sekali dan menyimpan ekspresi reguler, untuk penggunaan selanjutnya.

// DBJ.ORG string.format function
// usage:   "{0} means 'zero'".format("nula") 
// returns: "nula means 'zero'"
// place holders must be in a range 0-99.
// if no argument given for the placeholder, 
// no replacement will be done, so
// "oops {99}".format("!")
// returns the input
// same placeholders will be all replaced 
// with the same argument :
// "oops {0}{0}".format("!","?")
// returns "oops !!"
//
if ("function" != typeof "".format) 
// add format() if one does not exist already
  String.prototype.format = (function() {
    var rx1 = /\{(\d|\d\d)\}/g, rx2 = /\d+/ ;
    return function() {
        var args = arguments;
        return this.replace(rx1, function($0) {
            var idx = 1 * $0.match(rx2)[0];
            return args[idx] !== undefined ? args[idx] : (args[idx] === "" ? "" : $0);
        });
    }
}());

alert("{0},{0},{{0}}!".format("{X}"));

Juga, tidak ada contoh yang menghargai implementasi format () jika sudah ada.


2
rx2 tidak perlu, lihat implementasi saya; Anda memiliki (tanda kurung) di rx1, tetapi jangan gunakan nilai yang mereka berikan ke fungsi bagian dalam. Juga, saya pikir ini adalah optimasi yang jelas dilakukan di mesin Javascript . Apakah Anda yakin browser modern belum melakukan optimasi ini di belakang layar? Perl melakukannya pada tahun 1990. Anda benar bahwa harus ada pembungkus di sekitar fungsi untuk memeriksa apakah sudah diterapkan.
gpvos

1
Juga, pengujian pada (args [idx] === "") terlihat berlebihan bagi saya: sudah dicakup oleh tes pertama pada baris itu, karena tidak terdefinisi! == "".
gpvos

4

Ini milik saya:

String.format = function(tokenised){
        var args = arguments;
        return tokenised.replace(/{[0-9]}/g, function(matched){
            matched = matched.replace(/[{}]/g, "");
            return args[parseInt(matched)+1];             
        });
    }

Bukan bukti peluru tetapi bekerja jika Anda menggunakannya dengan bijaksana.


4

Jauh melewati akhir musim tetapi saya baru saja melihat jawaban yang diberikan dan memiliki nilai pasokan saya:

Pemakaian:

var one = strFormat('"{0}" is not {1}', 'aalert', 'defined');
var two = strFormat('{0} {0} {1} {2}', 3.14, 'a{2}bc', 'foo');

Metode:

function strFormat() {
    var args = Array.prototype.slice.call(arguments, 1);
    return arguments[0].replace(/\{(\d+)\}/g, function (match, index) {
        return args[index];
    });
}

Hasil:

"aalert" is not defined
3.14 3.14 a{2}bc foo

3

Sekarang Anda dapat menggunakan Literal Templat :

var w = "the Word";
var num1 = 2;
var num2 = 3;

var long_multiline_string = `This is very long
multiline templete string. Putting somthing here:
${w}
I can even use expresion interpolation:
Two add three = ${num1 + num2}
or use Tagged template literals
You need to enclose string with the back-tick (\` \`)`;

console.log(long_multiline_string);


3
Saya sangat senang tentang templat literal sampai saya melihat bahwa mereka hanya berfungsi ketika string didefinisikan bersama variabel pengganti. Bagi saya itu membuat mereka sangat tidak berguna; karena satu dan lain alasan, sebagian besar string saya didefinisikan secara terpisah dari kode yang mengisi / menggunakannya.
batu

2

Inilah versi saya yang dapat melarikan diri '{', dan membersihkan tempat-tempat yang belum ditetapkan tersebut.

function getStringFormatPlaceHolderRegEx(placeHolderIndex) {
    return new RegExp('({)?\\{' + placeHolderIndex + '\\}(?!})', 'gm')
}

function cleanStringFormatResult(txt) {
    if (txt == null) return "";

    return txt.replace(getStringFormatPlaceHolderRegEx("\\d+"), "");
}

String.prototype.format = function () {
    var txt = this.toString();
    for (var i = 0; i < arguments.length; i++) {
        var exp = getStringFormatPlaceHolderRegEx(i);
        txt = txt.replace(exp, (arguments[i] == null ? "" : arguments[i]));
    }
    return cleanStringFormatResult(txt);
}
String.format = function () {
    var s = arguments[0];
    if (s == null) return "";

    for (var i = 0; i < arguments.length - 1; i++) {
        var reg = getStringFormatPlaceHolderRegEx(i);
        s = s.replace(reg, (arguments[i + 1] == null ? "" : arguments[i + 1]));
    }
    return cleanStringFormatResult(s);
}

2

Jawaban berikut mungkin yang paling efisien tetapi memiliki peringatan hanya menjadi cocok untuk 1 hingga 1 pemetaan argumen. Ini menggunakan cara tercepat untuk menggabungkan string (mirip dengan stringbuilder: array string, bergabung). Ini kode saya sendiri. Mungkin membutuhkan pemisah yang lebih baik.

String.format = function(str, args)
{
    var t = str.split('~');
    var sb = [t[0]];
    for(var i = 0; i < args.length; i++){
        sb.push(args[i]);
        sb.push(t[i+1]);
    }
    return sb.join("");
}

Gunakan seperti:

alert(String.format("<a href='~'>~</a>", ["one", "two"]));

2
Jawaban yang diterima adalah jawaban terbaik. Saya memberikan jawaban unik yang berguna dalam skenario di mana Anda ingin menekan setiap bit efisiensi yang mungkin (loop panjang) dan Anda memiliki 1: 1 pemetaan argumen. Lebih efisien karena mengganti () dan Regex baru () bersamaan dengan menjalankan regex pasti menggunakan lebih banyak siklus CPU daripada pemisahan tunggal ().
Skychan

Tidak perlu -1. Tidak, ini tidak berlaku secara luas, tetapi dia benar, ini akan sedikit lebih efisien. Sekarang, bagi penulis, sebuah pertanyaan arsitektur: aplikasi seperti apa yang akan menangani set data yang begitu besar pada klien sehingga optimasi semacam ini diperlukan?
Michael Blackburn

Poin bagus Michael Blackburn. Sebagian besar situasi mungkin baik-baik saja. Dalam kasus saya, saya berurusan dengan sejumlah besar data (variasi produk dalam kelompok produk, jadi mungkin ratusan varian) dan pendapat saya adalah karena pengguna biasanya memiliki banyak tab browser terbuka dan setiap situs web cenderung menyedot banyak CPU yang Saya lebih suka implementasi ini untuk menjaga efisiensi tinggi.
Skychan

2

Ini melanggar prinsip KERING, tapi ini solusi singkat:

var button = '<a href="{link}" class="btn">{text}</a>';
button = button.replace('{text}','Authorize on GitHub').replace('{link}', authorizeUrl);

0
<html>
<body>
<script type="text/javascript">
   var str="http://xyz.html?ID={0}&TId={1}&STId={2}&RId={3},14,480,3,38";
   document.write(FormatString(str));
   function FormatString(str) {
      var args = str.split(',');
      for (var i = 0; i < args.length; i++) {
         var reg = new RegExp("\\{" + i + "\\}", "");             
         args[0]=args[0].replace(reg, args [i+1]);
      }
      return args[0];
   }
</script>
</body>
</html>

Ini bagus untuk URI, tetapi untuk penggunaan umum, memiliki satu string berisi format dan komponen sangat rapuh. Bagaimana jika string Anda mengandung koma?
Michael Blackburn

0

Saya tidak bisa mendapatkan jawaban Josh Stodola untuk bekerja, tetapi yang berikut ini berhasil untuk saya. Perhatikan spesifikasi prototype. (Diuji pada IE, FF, Chrome, dan Safari.):

String.prototype.format = function() {
    var s = this;
    if(t.length - 1 != args.length){
        alert("String.format(): Incorrect number of arguments");
    }
    for (var i = 0; i < arguments.length; i++) {       
        var reg = new RegExp("\\{" + i + "\\}", "gm");
        s = s.replace(reg, arguments[i]);
    }
    return s;
}

sbenar-benar harus menjadi clone dari thisagar tidak menjadi metode destruktif, tapi itu tidak benar-benar diperlukan.


Itu bukan metode yang merusak. Ketika s akan dipindahkan dengan nilai kembalinya dari s.replace (), ini tetap tidak tersentuh.
gpvos

0

Memperluas jawaban hebat adamJLev di atas , berikut adalah versi TypeScript:

// Extending String prototype
interface String {
    format(...params: any[]): string;
}

// Variable number of params, mimicking C# params keyword
// params type is set to any so consumer can pass number
// or string, might be a better way to constraint types to
// string and number only using generic?
String.prototype.format = function (...params: any[]) {
    var s = this,
        i = params.length;

    while (i--) {
        s = s.replace(new RegExp('\\{' + i + '\\}', 'gm'), params[i]);
    }

    return s;
};

0

Saya memiliki plunker yang menambahkannya ke prototipe string: string.format Ini tidak hanya sesingkat beberapa contoh lainnya, tetapi jauh lebih fleksibel.

Penggunaannya mirip dengan versi c #:

var str2 = "Meet you on {0}, ask for {1}";
var result2 = str2.format("Friday", "Suzy"); 
//result: Meet you on Friday, ask for Suzy
//NB: also accepts an array

Juga, menambahkan dukungan untuk menggunakan properti nama & objek

var str1 = "Meet you on {day}, ask for {Person}";
var result1 = str1.format({day: "Thursday", person: "Frank"}); 
//result: Meet you on Thursday, ask for Frank

0

Anda juga dapat menutup array dengan penggantian seperti ini.

var url = '/getElement/_/_/_'.replace(/_/g, (_ => this.ar[this.i++]).bind({ar: ["invoice", "id", 1337],i: 0}))
> '/getElement/invoice/id/1337

atau kamu bisa coba bind

'/getElement/_/_/_'.replace(/_/g, (function(_) {return this.ar[this.i++];}).bind({ar: ["invoice", "id", 1337],i: 0}))
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.