ما يعادل printf/String.Format في جافا سكريبت


أبحث عن مكافئ جيد في JavaScript لدالة C/PHP printf() أو لمبرمجي C#/Java، String.Format() (IFormatProvider لنظام .NET).

متطلبي الأساسي هو تنسيق الفواصل للأرقام في الوقت الحالي، لكن شيء يتعامل مع الكثير من التركيبات (بما في ذلك التواريخ) سيكون جيدًا.

أدرك أن مكتبة أجاكس من مايكروسوفت توفر نسخة من String.Format()، لكننا لا نريد كل العبء الثقيل لهذا الإطار.

الإجابة رقم 1

جافا سكريبت الحالية

من ES6 فصاعدًا يمكنك استخدام سلاسل القوالب:

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

انظر إجابة كيم أدناه للتفاصيل.


إجابة أقدم

جرب sprintf() لجافا سكريبت.


إذا كنت تريد حقًا القيام بطريقة التنسيق البسيط بنفسك، فلا تقم بالاستبدالات بشكل متتابع بل قم بها في وقت واحد.

لأن معظم الاقتراحات الأخرى المذكورة تفشل عندما تحتوي سلسلة الاستبدال السابقة أيضًا على تسلسل تنسيق مثل هذا:

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

عادةً ما تتوقع أن يكون الإخراج {1}{0} لكن الإخراج الفعلي هو {1}{1}. لذا قم بعمل استبدال متزامن بدلاً من ذلك كما في اقتراح fearphage.

الإجابة رقم 2

بناءً على الحلول المقترحة سابقًا:

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

المخرجات

ASP مات، لكن ASP.NET حي! ASP {2}

إذا كنت تفضل عدم تعديل نموذج String:

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

يعطيك الأكثر ألفة بكثير:

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

بالنتيجة نفسها:

ASP ميت، لكن ASP.NET حي! ASP {2}

الإجابة رقم 3

من المضحك أن Stack Overflow لديها في الواقع دالتها الخاصة لتنسيق بروتوتايب String تسمى formatUnicorn. جربها! ادخل إلى وحدة التحكم واكتب شيئًا مثل:

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

ستحصل على هذا الإخراج:

Hello, Gabriel, are you feeling OK?

يمكنك استخدام الكائنات والمصفوفات والسلاسل كوسائط! لقد حصلت على شفرته وأعدت صياغتها لإنتاج إصدار جديد من 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;
};

لاحظ الاستدعاء الذكي Array.prototype.slice.call(arguments) -- هذا يعني أنه إذا قمت بإدخال arguments التي هي سلاسل أو أرقام، وليس كائنًا واحدًا على شكل JSON، فستحصل على سلوك String.Format في C# تقريبًا بالضبط.

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

ذلك لأن Array وslice ستجبر أي شيء موجود في arguments على أن يصبح Array، سواء كان أصلاً كذلك أم لا، وkey سيكون الفهرس (0, 1, 2...) لكل عنصر في المصفوفة محوَّلًا إلى نص (مثلاً "0"، إذًا "\\{0\\}" لنمط التعبير النمطي الأول الخاص بك).

منظم.

الإجابة رقم 4

تنسيق الأرقام في جافاسكريبت

وصلت إلى صفحة الأسئلة هذه آملاً في معرفة كيفية تنسيق الأعداد في جافا سكريبت، دون إدخال مكتبة جديدة أخرى. إليكم ما وجدته:

تقريب الأعداد العشرية

المكافئ لـ sprintf("%.2f", num) في JavaScript يبدو أنه num.toFixed(2)، الذي يقوم بتنسيق num إلى منزلتين عشريتين، مع التقريب (ولكن انظر تعليق @ars265 حول Math.round أدناه).

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

الصيغة الأسية

ما يعادل sprintf("%.2e", num) هو num.toExponential(2).

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

النظام الست عشري وأنظمة العد الأخرى

لطباعة الأرقام بالأساس B، جرّب num.toString(B). يدعم JavaScript التحويل التلقائي من وإلى الأساسات من 2 إلى 36 (بالإضافة إلى أن بعض المتصفحات تدعم بشكل محدود ترميز base64).

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

صفحات المراجع

دليل سريع حول تنسيق الأرقام في جافا سكريبت

صفحة مرجعية في موزيلا لـ toFixed() (مع روابط لـ toPrecision()، toExponential()، toLocaleString()، ...)

الإجابة رقم 5

من ES6 فصاعدًا يمكنك استخدام سلاسل القوالب:

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

كن على علم بأن سلاسل القوالب محاطة بعلامات الاقتباس العكسية ` بدلًا من علامات الاقتباس (المفردة).

لاحظ أن السلسلة تتمدد فورًا بمجرد تعريفك للسلسلة.

لمزيد من المعلومات:

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

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

ملاحظة: تحقق من موقع موزيلا للعثور على قائمة المتصفحات المدعومة.

الإجابة رقم 6

jsxt، Zippo

هذا الخيار الأنسب.

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

بهذه الخيار يمكنني استبدال سلاسل مثل هذه:

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

مع الكود الخاص بك لن يتم استبدال {0} الثاني. ;)

الإجابة رقم 7

بالنسبة لمستخدمي Node.js، هناك util.format الذي يمتلك وظيفة مشابهة لـ printf:

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

الإجابة رقم 8

أستخدم هذه الوظيفة البسيطة:

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

هذا مشابه جدًا لـ string.format:

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

الإجابة رقم 9

أنا مندهش أن لا أحد استخدم reduce، هذه دالة جافاسكريبت أصلية وموجزة وقوية.

ES6 (إكما سكريبت 2015)

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"

كيف يعمل:

reduce يطبق دالة على المجمع وكل عنصر في المصفوفة (من اليسار إلى اليمين) لتقليصه إلى قيمة واحدة.

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

الإجابة رقم 10

إليكم تنفيذ حد أدنى لدالة sprintf في جافاسكريبت: فهي تدعم فقط "%s" و "%d"، لكنني تركت مساحة لتوسيعها. إنه غير مفيد للسائل الأصلي، لكن قد يستفيد منه الآخرون الذين يصادفون هذا الموضوع قادمين من جوجل.

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

مثال :

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

على عكس الحلول المماثلة في الردود السابقة، هذا الحل يقوم بكل الاستبدالات في خطوة واحدة، لذلك لن يستبدل أجزاء من القيم التي تم استبدالها مسبقًا.

الإجابة رقم 11

3 طرق مختلفة لتنسيق سلسلة جافاسكريبت

هناك ثلاث طرق مختلفة لتنسيق السلسلة عن طريق استبدال العناصر النائبة بقيمة المتغير.

  1. استخدام الحرف النمطي (العلامات العكسية ``)

    let name = 'John';
    let age = 30;
    // using backticks
    console.log(`${name} is ${age} years old.`);
    // John is 30 years old.
  2. استخدام الربط

let name = 'John';
let age = 30;
// using concatenation
console.log(name + ' is ' + age + ' years old.');
// John is 30 years old.
  1. إنشاء دالة تنسيق خاصة

String.prototype.format = function () {
  var args = arguments;
  return this.replace(/{([0-9]+)}/g, function (match, index) {
    // check if the argument is there
    return typeof args[index] == 'undefined' ? match : args[index];
  });
};


console.log('{0} is {1} years old.'.format('John', 30));

الإجابة رقم 12

يمكن لمبرمجي جافا سكريبت استخدام String.prototype.sprintf على https://github.com/ildar-shaimordanov/jsxt/blob/master/js/String.js. فيما يلي مثال:

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

الإجابة رقم 13

أريد أن أشارك حلي لـ 'المشكلة'. لم أعِد اختراع العجلة لكنني أحاول إيجاد حل بناءً على ما يقوم به JavaScript بالفعل. الميزة هي أنك تحصل على كل التحويلات الضمنية مجانًا. تعيين خاصية prototype $لـ String يعطي صياغة جميلة ومختصرة جدًا (انظر الأمثلة أدناه). قد لا تكون هذه الطريقة الأكثر فعالية، ولكن في معظم الحالات المتعلقة بالإخراج لا يجب أن تكون مُحسنة للغاية.

String.form = function(str, arr) {
    var i = -1;
    function callback(exp, p0, p1, p2, p3, p4) {
        if (exp=='%%') return '%';
        if (arr[++i]===undefined) return undefined;
        exp  = p2 ? parseInt(p2.substr(1)) : undefined;
        var base = p3 ? parseInt(p3.substr(1)) : undefined;
        var val;
        switch (p4) {
            case 's': val = arr[i]; break;
            case 'c': val = arr[i][0]; break;
            case 'f': val = parseFloat(arr[i]).toFixed(exp); break;
            case 'p': val = parseFloat(arr[i]).toPrecision(exp); break;
            case 'e': val = parseFloat(arr[i]).toExponential(exp); break;
            case 'x': val = parseInt(arr[i]).toString(base?base:16); break;
            case 'd': val = parseFloat(parseInt(arr[i], base?base:10).toPrecision(exp)).toFixed(0); break;
        }
        val = typeof(val)=='object' ? JSON.stringify(val) : val.toString(base);
        var sz = parseInt(p1); /* padding size */
        var ch = p1 && p1[0]=='0' ? '0' : ' '; /* isnull? */
        while (val.length<sz) val = p0 !== undefined ? val+ch : ch+val; /* isminus? */
       return val;
    }
    var regex = /%(-)?(0?[0-9]+)?([.][0-9]+)?([#][0-9]+)?([scfpexd%])/g;
    return str.replace(regex, callback);
}

String.prototype.$ = function() {
    return String.form(this, Array.prototype.slice.call(arguments));
}

إليك بعض الأمثلة:

String.format("%s %s", [ "This is a string", 11 ])
console.log("%s %s".$("This is a string", 11))
var arr = [ "12.3", 13.6 ]; console.log("Array: %s".$(arr));
var obj = { test:"test", id:12 }; console.log("Object: %s".$(obj));
console.log("%c", "Test");
console.log("%5d".$(12)); // '   12'
console.log("%05d".$(12)); // '00012'
console.log("%-5d".$(12)); // '12   '
console.log("%5.2d".$(123)); // '  120'
console.log("%5.2f".$(1.1)); // ' 1.10'
console.log("%10.2e".$(1.1)); // '   1.10e+0'
console.log("%5.3p".$(1.12345)); // ' 1.12'
console.log("%5x".$(45054)); // ' affe'
console.log("%20#2x".$("45054")); // '    1010111111111110'
console.log("%6#2d".$("111")); // '     7'
console.log("%6#16d".$("affe")); // ' 45054'

الإجابة رقم 14

بالإضافة إلى إجابة zippoxer، أستخدم هذه الدالة:

String.prototype.format = function () {
    var a = this, b;
    for (b in arguments) {
        a = a.replace(/%[a-z]/, arguments[b]);
    }
    return a; // Make chainable
};

var s = 'Hello %s The magic number is %d.';
s.format('world!', 12); // Hello World! The magic number is 12.

لدي أيضًا نسخة غير نموذجية أستخدمها في الغالب بسبب بنيتها الشبيهة بلغة جافا:

function format() {
    var a, b, c;
    a = arguments[0];
    b = [];
    for(c = 1; c < arguments.length; c++){
        b.push(arguments[c]);
    }
    for (c in b) {
        a = a.replace(/%[a-z]/, b[c]);
    }
    return a;
}
format('%d ducks, 55 %s', 12, 'cats'); // 12 ducks, 55 cats

تحديث ES 2015

كل الأشياء الجديدة الرائعة في ES 2015 تجعل هذا أسهل بكثير:

function format(fmt, ...args){
    return fmt
        .split("%%")
        .reduce((aggregate, chunk, i) =>
            aggregate + chunk + (args[i] || ""), "");
}

format("Hello %%! I ate %% apples today.", "World", 44);
// "Hello World, I ate 44 apples today."

لقد فكرت أنه بما أن هذا، مثل النسخ القديمة، لا يقوم بتحليل الحروف فعليًا، فقد يكون من الأفضل استخدام رمز واحد %%. هذا له فائدة أنه واضح ولا يجعل استخدام رمز واحد % صعبًا. ومع ذلك، إذا كنت بحاجة إلى %% لسبب ما، فستحتاج إلى استبداله بنفسه:

format("I love percentage signs! %%", "%%");
// "I love percentage signs! %%"

الإجابة رقم 15

+1 Zippo مع استثناء أن جسم الدالة يجب أن يكون كما يلي وإلا فإنه يضيف السلسلة الحالية في كل تكرار:

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

الإجابة رقم 16

أستخدم مكتبة صغيرة تُسمى String.format لجافاسكريبت والتي تدعم معظم قدرات سلسلة التنسيق (بما في ذلك تنسيق الأرقام والتواريخ)، وتستخدم بناء جملة .NET. النص البرمجي نفسه أصغر من 4 كيلوبايت، لذا فهو لا يخلق الكثير من الحمل الزائد.

الإجابة رقم 17

سأضيف اكتشافاتي الخاصة التي وجدتها منذ أن سألت:

  • number_format (لتنسيق الفواصل للآلاف/تنسيق العملة)
  • sprintf (نفس المؤلف كما ذُكر أعلاه)

لسوء الحظ، يبدو أن sprintf لا يتعامل مع تنسيق فاصل الآلاف مثل تنسيق السلاسل في .NET.

الإجابة رقم 18

إذا كنت تبحث عن التعامل مع فاصل الآلاف، يجب عليك حقًا استخدام toLocaleString() من فئة الأرقام في JavaScript لأنه سيقوم بتنسيق السلسلة وفقًا لمنطقة المستخدم.

يمكن لفئة JavaScript Date تنسيق التواريخ والأوقات المحلية.

الإجابة رقم 19

أنيق جدًا:

String.prototype.format = function (){
    var args = arguments;
    return this.replace(/\{\{|\}\}|\{(\d+)\}/g, function (curlyBrack, index) {
        return ((curlyBrack == "{{") ? "{" : ((curlyBrack == "}}") ? "}" : args[index]));
    });
};

// Usage:
"{0}{1}".format("{1}", "{0}")

الفضل يعود إلى (رابط معطل) https://gist.github.com/0i0/1519811

الإجابة رقم 20

لقد كتب مشروع PHPJS تطبيقات جافا سكريبت للعديد من دوال PHP. بما أن دالة sprintf() في PHP هي في الأساس نفسها دالة printf() في C، فإن تطبيقهم لها في جافا سكريبت يجب أن يلبي احتياجاتك.