我正在寻找一个良好的JavaScript等价物来替代C/PHP中的printf()
或对于C#/Java程序员,String.Format()
(.NET使用 IFormatProvider
)。
我的基本要求是数字的千位分隔符格式,但能处理许多组合(包括日期)的东西会更好。
我意识到微软的Ajax库提供了一个版本的String.Format()
,但我们不想要整个框架的开销。
我正在寻找一个良好的JavaScript等价物来替代C/PHP中的printf()
或对于C#/Java程序员,String.Format()
(.NET使用 IFormatProvider
)。
我的基本要求是数字的千位分隔符格式,但能处理许多组合(包括日期)的东西会更好。
我意识到微软的Ajax库提供了一个版本的String.Format()
,但我们不想要整个框架的开销。
有三种不同的方式来通过替换占位符为变量值来格式化一个字符串。
Using template literal (backticks ``)
let name = 'John';
let age = 30;
// using backticks
console.log(`${name} is ${age} years old.`);
// John is 30 years old.
Using concatenation
let name = 'John';
let age = 30;
// using concatenation
console.log(name + ' is ' + age + ' years old.');
// John is 30 years old.
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));
Array.prototype.forEach
)向旧引擎进行后移时才使用。请参见[MDN上的警告](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain#implicit_constructors_of_literals)。虽然与`printf`不完全对称,但`util.format`可能是op正在寻找的最佳选择。 - SubfuzionJavaScript程序员可以在https://github.com/ildar-shaimordanov/jsxt/blob/master/js/String.js使用String.prototype.sprintf。以下是示例:
var d = new Date();
var dateStr = '%02d:%02d:%02d'.sprintf(
d.getHours(),
d.getMinutes(),
d.getSeconds());
我想分享一下我的“问题”解决方案。我没有重新发明轮子,而是尝试找到基于JavaScript已有的东西的解决方案。优点是,你可以免费获得所有隐式转换。设置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'
在 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.
我也有一个非原型版本,因为它具有类似Java的语法,所以我更经常使用它:
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中所有酷炫的新功能使这变得更加容易:
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! %%"
+1 Zippo的唯一区别在于,函数主体需要如下所示,否则它会在每次迭代时附加当前字符串:
String.prototype.format = function() {
var formatted = this;
for (var arg in arguments) {
formatted = formatted.replace("{" + arg + "}", arguments[arg]);
}
return formatted;
};
'The {0} is dead. Don\'t code {0}. Code {1} that is open source!'.format('ASP', 'PHP');
结果变成了 The ASP is dead. Don't code {0}. Code PHP that is open source!
. 还有一件事,for(arg in arguments)
在IE中不起作用。我用for (arg = 0; arg <arguments.length; arg++)
代替了它。 - samarjit samantafor...in
在某些浏览器中不能按照此代码的期望工作。它会循环遍历所有可枚举属性,其中在某些浏览器中将包括 arguments.length
,而在其他浏览器中甚至不包括参数本身。无论如何,如果添加了Object.prototype
,任何添加的内容都可能被包含在其中。代码应该使用标准的 for
循环,而不是 for...in
。 - cHao我使用一个名为JavaScript的String.format的小型库,它支持大多数格式字符串功能(包括数字和日期格式),并使用.NET语法。脚本本身小于4 kB,因此不会产生太多开销。
我将添加自己的发现,这是我提出问题后发现的:
不幸的是,似乎 sprintf 不像 .NET 的字符串格式化那样处理千分位分隔符格式化。
非常优雅:
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}")
{{0}}
以及像 {0}{1}.format("{1}", "{0}")
这样的东西的函数。应该放在最顶部! - JuanString.prototype.format = function() {
var newStr = this, i = 0;
while (/%s/.test(newStr))
newStr = newStr.replace("%s", arguments[i++])
return newStr;
}
然后我调用它:
"<h1>%s</h1><p>%s</p>".format("Header", "Just a test!");
String.padStart
。 (请参见https://dev59.com/jXE85IYBdhLWcg3wnU-p) - Nor.Z