Soru Printf / String.Format için JavaScript eşdeğeri


C / PHP'nin iyi bir JavaScript eşdeğerini arıyorum printf() veya C # / Java programcıları için String.Format() (IFormatProvider .NET için.

Temel gereksinim, şimdilik rakamlar için bin ayırıcı biçimidir, ancak birçok kombinasyonu (tarihler dahil) ele alan bir şey iyi olacaktır.

Microsoft'un farkına varıyorum ajax kütüphane bir sürümü sağlar String.Format()ama bu çerçevenin tüm yükünü istemiyoruz.


1610
2018-01-12 20:02


Menşei


Aşağıdaki tüm mükemmel cevapların yanı sıra, buna bir göz atmak isteyebilirsiniz: stackoverflow.com/a/2648463/1712065 Hangi IMO, bu soruna en etkili çözümdür. - Annie
Yazdım ucuz olan C-benzeri bir printf sözdizimi kullanır. - Braden Best
var search = [$ scope.dog, "1"]; var url = vsprintf ("Toprak / Hizmetler / dogSearch.svc / FindMe /% s /% s";, arama); *** Düğüm için modülünüzü "npm install sprintf-js" ile alabilirsiniz. - Jenna Leaf


Cevaplar:


Deneyin JavaScript için sprintf ().


GüncelleştirmeTamam, eğer basit bir formatlama yöntemini kendi başınıza yapmak istiyorsanız, yedekleri art arda yapmayın ama aynı anda yapın.

Önceki değiştirmenin bir değiştirme dizesi de bunun gibi bir biçim dizisi içerdiğinde, bahsedilen diğer tekliflerin çoğu başarısız olduğu için başarısız olur:

"{0}{1}".format("{1}", "{0}")

Normalde çıkışın olmasını beklersiniz. {1}{0} ama gerçek çıktı {1}{1}. Bunun yerine, tıpkı bir korku hikayesi önerisi.


687



Yine taşındı: epeli.github.com/underscore.string - Maksymilian Majer
Eğer sadece bazı basit bir dizi-string dönüşüm istenirse, num.toFixed() yöntem yeterli olabilir! - heltonbiker
@MaksymilianMajer, kitlesel olarak farklı bir şey gibi görünüyor. - Evan Carroll
@EvanCarroll haklısın. O zaman ben yorumunu yazdım. sprintf() for JavaScript mevcut değildi. underscore.string dayalı sprintf dışında daha fazla özellik var sprintf() for JavaScript uygulanması. Bunun dışında kütüphane tamamen farklı bir projedir. - Maksymilian Majer
@MaksymilianMajer doğru, sadece bu cevabın öldüğünü ve bağlantının bozulduğunu söyledi. Tamamen temizlenmesi gerekiyor. - Evan Carroll


Önceden önerilen çözümler üzerinde bina:

// First, checks if it isn't implemented yet.
if (!String.prototype.format) {
  String.prototype.format = function() {
    var args = arguments;
    return this.replace(/{(\d+)}/g, function(match, number) { 
      return typeof args[number] != 'undefined'
        ? args[number]
        : match
      ;
    });
  };
}

"{0} is dead, but {1} is alive! {0} {2}".format("ASP", "ASP.NET")

çıktılar

ASP öldü, ancak ASP.NET yaşıyor! ASP {2}


Değiştirmemeyi tercih ederseniz Stringprototip:

if (!String.format) {
  String.format = function(format) {
    var args = Array.prototype.slice.call(arguments, 1);
    return format.replace(/{(\d+)}/g, function(match, number) { 
      return typeof args[number] != 'undefined'
        ? args[number] 
        : match
      ;
    });
  };
}

Size daha tanıdık geliyor:

String.format('{0} is dead, but {1} is alive! {0} {2}', 'ASP', 'ASP.NET');

aynı sonuçla:

ASP öldü, ancak ASP.NET yaşıyor! ASP {2}


1279



|| trick [sayı] 0 ise hile çalışmaz. Açık olup olmadığını () görmek için (if ler [sayı] === undefined) açık bir şekilde yapmalısınız. - fserb
kestirme ifadesinin başka bir ifadesinde, neden "'{' + sayı + '}" yerine "eşleşme" yapmıyoruz. eşleşme bu dizgeye eşit olmalıdır. - mikeycgto
@ckozl Kodunuz reformat cevabı geçersiz kılar. Kodun çıktısını değiştirir. Lütfen düzenlemeleri uygulamadan önce kodunuzu test edin. Teşekkür ederim. - fearphage
@ckozl - Lütfen bu cevabın formatını, onu bırakan kişinin iradesine karşı tekrar tekrar atmayın. Bunu ertesi gün için kilitliyorum ve bunu neden yaptığınızı açıklamak isterseniz, lütfen bunu yapın Meta. - Brad Larson♦
(!String.prototype.format) daha yeni tarayıcıların gelip web sitenizi uyumsuz bir şekilde çözebileceği anlamına geldiğinden, polifilizlerle uğraşmadıkça kontrol kötü bir fikirdir format yöntem. Onu kaldırmanızı öneriyorum. - Simon Lindholm


Bu komik çünkü Stack Overflow'un aslında kendi formatlama fonksiyonu var. String prototip denir formatUnicorn. Dene! Konsola gidin ve şöyle bir şey yazın:

"Hello, {name}, are you feeling {adjective}?".formatUnicorn({name:"Gabriel", adjective: "OK"});

Firebug

Bu çıktıyı alırsınız:

Hello, Gabriel, are you feeling OK?

Nesneleri, dizileri ve dizeleri argüman olarak kullanabilirsiniz! Kodunu aldım ve yeni bir versiyonunu üretmek için String.prototype.format:

String.prototype.formatUnicorn = String.prototype.formatUnicorn ||
function () {
    "use strict";
    var str = this.toString();
    if (arguments.length) {
        var t = typeof arguments[0];
        var key;
        var args = ("string" === t || "number" === t) ?
            Array.prototype.slice.call(arguments)
            : arguments[0];

        for (key in args) {
            str = str.replace(new RegExp("\\{" + key + "\\}", "gi"), args[key]);
        }
    }

    return str;
};

Zeki dikkat Array.prototype.slice.call(arguments) çağrı - bu, dizeleri veya sayıları olan tek bir JSON stili nesnesi olmayan argümanları atarsanız, C # 'yı alırsınız demektir String.Format davranış neredeyse tam olarak.

"a{0}bcd{1}ef".formatUnicorn("foo", "bar"); // yields "aFOObcdBARef"

O yüzden Array'ler slice içinde ne varsa zorlayacak arguments Içine Arraybaşlangıçta olsun olmasın ve key her dizi öğesinin bir dizgeye (örn. "0") indeksli olması (0, 1, 2 ...) "\\{0\\}" ilk regexp deseniniz için).

Temiz.


366



Stackoverflow gelen kod ile stackoverflow bir soruya cevap vermek için oldukça güzel, +1 - Sneakyness
@JamesManning İntikam küresel bayrağa izin verir (g), aynı anahtarı bir kereden fazla değiştirebilir. Yukarıdaki örnekte, kullanabilirsiniz {name} Aynı cümle içinde birden çok kez ve hepsinin yerini aldılar. - Greggg
@ DineiA.Rockenbach ama kod for (arg in args)  adında global bir değişken tanımlayacak arg. Eğer kullanmıyorsan var arg İlk satırda, o zaman kullanmalısınız for(var arg in args) Küresel değişkeni tanımlamaktan kaçınmak. - RainChen
Bu dürüst olmak gerekirse çok kırılgan görünüyor. Örneğin ne olur? name olduğu "blah {adjective} blah"? - sam hocevar
@ruffin “biraz hiperbolik”? Kullanıcı verilerini biçim dizeleri olarak yorumlamaktan kandırılan kod bir bütün güvenlik açıkları kategorisi. % 98,44 vasatın ötesinde. - sam hocevar


JavaScript'te Sayı Biçimlendirme

Nasıl yapılacağını umuyordum bu soru sayfasına var format numaraları JavaScript'te, henüz başka bir kütüphane sunmadan. İşte bulduğum şey:

Kayan noktalı sayıların yuvarlanması

Eşdeğeri sprintf("%.2f", num) JavaScript olarak görünüyor num.toFixed(2), hangi biçimler num yuvarlama ile 2 ondalık basamağa (ancak bkz. @ ars265’in yorumu Math.round altında).

(12.345).toFixed(2); // returns "12.35" (rounding!)
(12.3).toFixed(2); // returns "12.30" (zero padding)

Üstel form

Eşdeğeri sprintf("%.2e", num) olduğu num.toExponential(2).

(33333).toExponential(2); // "3.33e+4"

Onaltılı ve diğer üsler

B tabanındaki sayıları yazdırmak için, num.toString(B). JavaScript, 2 ile 36 arasındaki tabanlara otomatik dönüşümü destekler (ek olarak, bazı tarayıcılarda base64 kodlaması için sınırlı destek).

(3735928559).toString(16); // to base 16: "deadbeef"
parseInt("deadbeef", 16); // from base 16: 3735928559

Referans Sayfaları

JS numarası biçimlendirmesinde hızlı eğitim

ToFixed için Mozilla başvuru sayfası () (toPrecision (), toExponential (), toLocaleString (), ... ile bağlantıları olan)


288



Buradaki garip bir beyaz alan bırakmak yerine, sayı değişmezini parantez içine almak daha iyi olmaz mıydı? - rmobis
Bu muhtemelen daha iyi görünüyor, doğru. Ama benim amacım sadece sözdizimi hatası tuzağına işaret etmek. - rescdsk
Eski bir tarayıcı kullanıyorsanız veya eski tarayıcıları destekliyorsanız, yalnızca bir yan not, bazı tarayıcılar toFixed'i yanlış uyguladı, MathFix'i toFixed yerine kullanmak daha iyi bir çözüm. - ars265
@Raphael_ ve @rescdsk: .. ayrıca çalışır: 33333..toExponential(2); - Peter Jaric
Veya (33333). İçinExponential (2) - Jonathan


ES6'dan itibaren kullanabilirsiniz şablon dizeleri:

let soMany = 10;
console.log(`This is ${soMany} times easier!`);
// "This is 10 times easier!

Şablon dizelerinin farkında olun backticks tarafından çevrili `(tek) tırnak yerine.

Daha fazla bilgi için:

https://developers.google.com/web/updates/2015/01/ES6-Template-Strings

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings

Not: Desteklenen tarayıcıların listesini bulmak için mozilla sitesini kontrol edin.


170



Şablon dizgileriyle ilgili sorun, derhal idam edilmek gibi gözüktüğü ve i18n gibi bir dizgi tablosunu tamamen değersiz hale getirdikleri görülüyor. Dizeyi erken tanımlayamıyorum ve daha sonra ve / veya tekrar tekrar kullanmak için parametreleri sağladım. - Tustin2121
@ Tustin2121 Haklısınız, bir değişkene atanacak şekilde inşa edilmiş değilsiniz, bu biraz zihin-çözgü, ama bir işlevde saklarsanız, sicil dizeleri 'anında-yürütme tenatcies ile çalışmak için yeterince kolaydır. Görmek jsfiddle.net/zvcm70pa - inanutshellus
@ Tustin2121, bir şablon dizgisi veya eski stil dizgi birleştirme kullanımı arasında aynı şey için şeker arasında hiçbir fark yoktur. Basit bir işlevde eski bir stil dize üretecini sarmalı ve aynı şey dize şablonları ile iyi çalışır. const compile = (x, y) => `I can call this template string whenever I want.. x=${x}, y=${y}` ... compile(30, 20) - cchamberlain
Bu çözüm, değişken olarak iletilen biçim dizesi için çalışmaz (örneğin sunucudan) - user993954
@inanutshellus Şablonunuzun işlevi, yürütüldüğü makinede tanımlanmışsa iyi çalışır. Bildiğim kadarıyla, bir işlevi JSON olarak geçiremezsiniz, bu yüzden bir veritabanında şablon işlevlerini saklamak iyi çalışmaz. - styfle


jsxt, Zippo

Bu seçenek daha iyi uyuyor.

String.prototype.format = function() {
    var formatted = this;
    for (var i = 0; i < arguments.length; i++) {
        var regexp = new RegExp('\\{'+i+'\\}', 'gi');
        formatted = formatted.replace(regexp, arguments[i]);
    }
    return formatted;
};

Bu seçenekle dizeleri şu şekilde değiştirebilirim:

'The {0} is dead. Don\'t code {0}. Code {1} that is open source!'.format('ASP', 'PHP');

Kodunuzla, ikinci {0} değiştirilemez. ;)


168



Bunu beğendim, çünkü format formatlarını global olarak değiştiriyor. - Jarrod Dixon♦
gist.github.com/1049426 Örneğini bu yaklaşımla güncelledim. Varsa yerel uygulamayı kaydetme, dizgeleştirme, vb. Dahil olmak üzere çok sayıda fayda. Normal ifadeleri kaldırmayı denedim, ancak global değiştirme için gereken türden bir yardımcı. : - / - tbranyen
jsxt ne yazık ki GPL lisanslı - AndiDog
for döngüsünde bir değişkeni bildirmezsiniz - brielov


Bu basit işlevi kullanıyorum:

String.prototype.format = function() {
    var formatted = this;
    for( var arg in arguments ) {
        formatted = formatted.replace("{" + arg + "}", arguments[arg]);
    }
    return formatted;
};

String.format'a çok benzer:

"{0} is dead, but {1} is alive!".format("ASP", "ASP.NET")

91



niye ya +=? formatted = this.replace("{" + arg + "}", arguments[arg]); - guilin 桂林
Bence kod hala doğru değil. Doğru olan biri gibi olmalı Filipiz gönderildi. - wenqiang
Referans için, for...in Bu kodun beklediği gibi her tarayıcıda çalışmaz. Bazı tarayıcılarda içerecek tüm sayılabilir özellikler arasında geçiş yapar. arguments.lengthVe diğerlerinde argümanları bile hiç içermezler. Her durumda Object.prototype eklenir, muhtemelen herhangi bir ekleme gruba dahil edilecektir. Kod bir standart kullanmalıdır for döngü yerine for...in. - cHao
Önceki bir yedek de bir biçim dizesi içeriyorsa bu başarısız olur: "{0} is dead, but {1} is alive!".format("{1}", "ASP.NET") === "ASP.NET is dead, but ASP.NET is alive!" - Gumbo
Değişken arg küreseldir. Bunun yerine şunu yapmalısınız: for (var arg in arguments) { - Pauan


İşte bir en az sprintf'in JavaScript'te uygulanması: sadece "% s" ve "% d" yapar, ancak uzatılması için alan bıraktım. OP için işe yaramaz, ancak Google'dan gelen bu ileti dizisinde rastlanan diğer kişiler bundan yararlanabilir.

function sprintf() {
    var args = arguments,
    string = args[0],
    i = 1;
    return string.replace(/%((%)|s|d)/g, function (m) {
        // m is the matched format, e.g. %s, %d
        var val = null;
        if (m[2]) {
            val = m[2];
        } else {
            val = args[i];
            // A switch statement so that the formatter can be extended. Default is %s
            switch (m) {
                case '%d':
                    val = parseFloat(val);
                    if (isNaN(val)) {
                        val = 0;
                    }
                    break;
            }
            i++;
        }
        return val;
    });
}

Örnek:

alert(sprintf('Latitude: %s, Longitude: %s, Count: %d', 41.847, -87.661, 'two'));
// Expected output: Latitude: 41.847, Longitude: -87.661, Count: 0

Önceki cevaplarda benzer çözümlerin aksine, bu tüm ikameleri yapar tek seferdeBu yüzden daha önce değiştirilen değerlerin parçalarını değiştirmeyecektir.


48





İçin node.js kullanıcılar var util.format printf benzeri işlevlere sahip olan:

util.format("%s world", "Hello")

47



Bu, Node değeri olarak% x değerini desteklemiyor. - Max Krohn


Kimsenin kullanmadığına şaşırdım reduceBu, yerel özlü ve güçlü bir JavaScript işlevi.

ES6 (EcmaScript2015)

String.prototype.format = function() {
  return [...arguments].reduce((p,c) => p.replace(/%s/,c), this);
};

console.log('Is that a %s or a %s?... No, it\'s %s!'.format('plane', 'bird', 'SOman'));

<ES6

function interpolate(theString, argumentArray) {
    var regex = /%s/;
    var _r=function(p,c){return p.replace(regex,c);}
    return argumentArray.reduce(_r, theString);
}

interpolate("%s, %s and %s", ["Me", "myself", "I"]); // "Me, myself and I"

Nasıl çalışır:

azaltmak bir biriktiriciye ve dizideki her bir öğeye (soldan sağa) bir işlevi tek bir değere düşürmek için uygular.

var _r= function(p,c){return p.replace(/%s/,c)};

console.log(
  ["a", "b", "c"].reduce(_r, "[%s], [%s] and [%s]") + '\n',
  [1, 2, 3].reduce(_r, "%s+%s=%s") + '\n',
  ["cool", 1337, "stuff"].reduce(_r, "%s %s %s")
);


36



İşte, basitleştirilmiş oluşturmak için bu yaklaşımı kullanan bir sürüm. printf fonksiyon: jsfiddle.net/11szrbx9 - Dem Pilafian
Ve burada bir satırda ES6 kullanan başka bir tane var: (...a) => {return a.reduce((p: string, c: any) => p.replace(/%s/, c)); - Bhyd
İhtiyaç yok String.prototype.format ES6’da: ((a,b,c)=>`${a}, ${b} and ${c}`)(...['me', 'myself', 'I']) (Bu, örneğinize daha uygun olması için biraz fazlalık olduğunu unutmayın) - Tino
Her biri için yedek işlevleri uygulamanız gerekecek printf'tür tanımlayıcıları ve doldurma önekleri için mantık içerir. Biçim dizgisini mantıklı bir şekilde yinelemek, burada küçük bir meydan okuma gibi görünüyor, imho. Yine de, sadece dize değiştirmeleri gerekiyorsa, temiz bir çözüm. - collapsar


JavaScript programcıları String.prototype.sprintf dosyasını https://github.com/ildar-shaimordanov/jsxt/blob/master/js/String.js. Aşağıda örnek:

var d = new Date();
var dateStr = '%02d:%02d:%02d'.sprintf(
    d.getHours(), 
    d.getMinutes(), 
    d.getSeconds());

30



code.google.com bir ölü bağlantıdır - Jason Morgan
@JasonMorgan, GitHub'da çalışma bağlantısını paylaştım. Düzeltilen yanıtı görün. - jsxt