如何用前导零填充值?


394

在JavaScript中建议零填充值的推荐方法是什么?我想我可以构建一个自定义函数以将零填充到类型转换值上,但是我想知道是否还有更直接的方法可以做到这一点?

注意: “零填充”是指该词在数据库中的含义(其中数字5的6位零填充表示为“ 000005”)。


确实没有足够的信息来回答。“零填充”的最常见实例可能是在日期前加零:5/1/2008> 05/01/2008。你是这个意思吗?
三联画

6
对于节点应用程序,请使用npm install sprintf-js,并在您需要的文件中要求它:sprintf('%0d6', 5);
Droogans 2014年

function padWithZeroes(n, width) { while(n.length<width) n = '0' + n; return n;} ......假设n不是消极的
圣保罗

@Paolo如果n为数字,则该功能不起作用。您需要在n之前将n转换为String才能while访问n.length
Nick F

1
一个没有Math或While循环或库的班轮?mynum = "0".repeat((n=6-mynum.toString().length)>0?n:0)+mynum;
亚当·沃特森

Answers:


224

敬请读者注意!

正如评论者所指出的那样,此解决方案是“聪明的”,而且通常就像聪明的解决方案一样,它占用大量内存并且相对较慢。如果您担心性能,请不要使用此解决方案!

可能已过时:自ECMAScript 3.1起,ECMAScript2017包含 String.prototype.padStart Number.prototype.toLocaleString。例:

var n=-0.1;
n.toLocaleString('en', {minimumIntegerDigits:4,minimumFractionDigits:2,useGrouping:false})

...将输出“ -0000.10”。

// or 
const padded = (.1+"").padStart(6,"0");
`-${padded}`

...将输出“ -0000.1”。

您只需一个简单的功能

function zeroFill( number, width )
{
  width -= number.toString().length;
  if ( width > 0 )
  {
    return new Array( width + (/\./.test( number ) ? 2 : 1) ).join( '0' ) + number;
  }
  return number + ""; // always return a string
}

如果您想保留名称空间或其他内容,可以将其烘烤到库中。就像jQuery的extend一样


1
现在,您只需要处理50.1234之类的数字,下面便是我的解决方案的可读版本!但是,我确实假设我们只是填充,而不是整体填充。
coderjoe

7
每次想填充值时,都不喜欢创建新数组。读者应注意,如果他们大量执行这些操作(例如,在每秒执行1000次此类操作的node.js服务器上),则可能会对内存和GC产生潜在影响。@ profitehlolz的回答似乎是更好的解决方案。)
broofa 2012年

6
这不适用于负值:zeroFill(-10,7)->“ 0000-10”
digitalbath 2012年

2
以下是三个最重要答案中的性能衡量指标:jsperf.com/left-zero-pad
tomsmeding 2014年

12
从ECMAScript 2017开始,有一个内置功能padStart
Tomas Nikodym

321

简单的方法。您可以为填充板添加字符串乘法并将其转换为函数。

var pad = "000000";
var n = '5';
var result = (pad+n).slice(-pad.length);

作为功​​能,

function paddy(num, padlen, padchar) {
    var pad_char = typeof padchar !== 'undefined' ? padchar : '0';
    var pad = new Array(1 + padlen).join(pad_char);
    return (pad + num).slice(-pad.length);
}
var fu = paddy(14, 5); // 00014
var bar = paddy(2, 4, '#'); // ###2

95
这是一个非常好的解决方案,据我所知。为了清楚起见,这是我用来按时间格式填充分钟的一个简单版本:('0'+ minutes).slice(-2)
Luke Ehresman

17
这比使用while循环的实现慢5倍:gist.github.com/4382935
andrewrk

42
这有一个致命的缺陷,具有比预期更大的数字-这是一个非常普遍的现象。例如,paddy (888, 2)产量88888符合要求。此答案也不处理负数。
Brock Adams

8
@ BrockAdams,zerofill通常用于固定宽度的数字/格式设置情况-因此,我认为在尝试进行2位数的数字填充时,如果给出3位数的数字,则实际上不太可能(甚至没有问题)。
Seaux

1
(“ 000000” + somenum).substr(-6,6),其中零的数目和-6,6对应于填充宽度。相同的想法,但切片少了一个参数;不知道切片比subtr快还是慢。当然,我的解决方案不需要变量分配。
slartibartfast 2014年

315

我不敢相信这里有所有复杂的答案...只需使用:

var zerofilled = ('0000'+n).slice(-4);

27
很好,除了负数和大于4位的数字。
wberry

12
@wberry并不是要用于生产就绪的代码,而只是对解决当前问题的基础知识的简单说明。同样,很容易确定一个数字是正数还是负数,并在需要时添加适当的符号,因此我不想将简单的例子与此相联系。同样,使一个函数采用一个数字长度作为arg并使用它而不是我的硬编码值也一样容易。
Seaux

5
@Seaux,您说:“无法相信所有复杂的答案”,然后在评论时开始向自己解释复杂性。这意味着您了解从某些角度看您的答案并不完美。因此很复杂。
Om Shankar

2
@OmShankar的“复杂答案”,我不是指解释性或详细的答案(尽管我的答案不是很明显,但本网站上鼓励这样做),而是包含了不必要的代码复杂性的答案。
Seaux

7
我喜欢这个答案。在我自己的特定情况下,我知道数字始终为正,并且永远不超过3位,当您填充前导0且您的输入众所周知时,通常就是这种情况。真好!
Patrick Chu

110

实际上,我最近不得不提出类似的建议。我认为必须有一种不使用循环的方法。

这就是我想出的。

function zeroPad(num, numZeros) {
    var n = Math.abs(num);
    var zeros = Math.max(0, numZeros - Math.floor(n).toString().length );
    var zeroString = Math.pow(10,zeros).toString().substr(1);
    if( num < 0 ) {
        zeroString = '-' + zeroString;
    }

    return zeroString+n;
}

然后只需使用它提供一个零填充数字:

> zeroPad(50,4);
"0050"

如果数字大于填充,则数字将扩展到填充之外:

> zeroPad(51234, 3);
"51234"

小数也可以!

> zeroPad(51.1234, 4);
"0051.1234"

如果您不介意污染全局名称空间,则可以将其直接添加到Number中:

Number.prototype.leftZeroPad = function(numZeros) {
    var n = Math.abs(this);
    var zeros = Math.max(0, numZeros - Math.floor(n).toString().length );
    var zeroString = Math.pow(10,zeros).toString().substr(1);
    if( this < 0 ) {
        zeroString = '-' + zeroString;
    }

    return zeroString+n;
}

而且,如果您希望保留小数,请在填充中占用空间:

Number.prototype.leftZeroPad = function(numZeros) {
    var n = Math.abs(this);
    var zeros = Math.max(0, numZeros - n.toString().length );
    var zeroString = Math.pow(10,zeros).toString().substr(1);
    if( this < 0 ) {
        zeroString = '-' + zeroString;
    }

    return zeroString+n;
}

干杯!



XDR提出了对数变化形式,表现似乎更好。

警告:如果num等于零(例如zeropad(0,2)),此函数将失败

function zeroPad (num, numZeros) {
    var an = Math.abs (num);
    var digitCount = 1 + Math.floor (Math.log (an) / Math.LN10);
    if (digitCount >= numZeros) {
        return num;
    }
    var zeroString = Math.pow (10, numZeros - digitCount).toString ().substr (1);
    return num < 0 ? '-' + zeroString + an : zeroString + an;
}

说到性能,Tomsmeding 比较了前3个答案(其中4个是对数变化)。猜猜哪个主要胜过其他两个?:)


9
很好,我喜欢它的可读性和鲁棒性。我唯一要更改的是numZeros参数名称,因为它具有误导性。这不是您要添加的零的数量,而是该数量应该的最小长度。更好的名字是numLength甚至length
有意义的2012年

13
+1。与投票较高的答案不同,此答案处理负数,并且在溢出时不返回严重错误!
Brock Adams

10
以下是三个最重要答案中的性能衡量指标:jsperf.com/left-zero-pad
tomsmeding 2014年

4
通过使用对数,我将该答案的性能提高了100%以上。请在http://jsperf.com/left-zero-pad/10
XDR 2014年

2
原始解决方案更好,如果num可以为零,对数变化将不起作用...
Ondra C.15.17.15,10

69

这是我过去最多填充7个字符的数字。

("0000000" + number).slice(-7)

对于大多数人来说,这种方法可能就足够了。

编辑:如果要使其更通用,可以执行以下操作:

("0".repeat(padding) + number).slice(-padding)

编辑2:请注意,自ES2017起,您可以使用String.prototype.padStart

number.toString().padStart(padding, "0")

严重的是,这对于大数和负数失败。 number = 123456789,例如上面的代码。
Brock Adams

对于某些情况,此解决方案是最好的解决方案!我不知道为什么我们以前没有提出这个建议。场景是:您有一个始终为正的数字(如Brock所述),并且您知道它所用的字符数不会超过您的限制。在我们的案例中,我们有一个分数存储在Amazon SDB中。如您所知,SDB无法比较数字,因此所有分数都必须补零。这是非常容易和有效的!
克里斯蒂安

4
抱歉,我应该提到这对负数不起作用。我认为这是针对更常见的正数的情况。至少可以满足我的需求!
chetbox

再次需要这个,并意识到您不需要new String。您可以只使用字符串文字。
chetbox 2016年

3
(new Array(padding + 1).join("0")可以替换为"0".repeat(padding)
Pavel

34

现代浏览器现在支持padStart,您现在只需执行以下操作:

string.padStart(maxLength, "0");

例:

string = "14";
maxLength = 5; // maxLength is the max string length, not max # of fills
res = string.padStart(maxLength, "0");
console.log(res); // prints "00014"


@Flimm随时将其编辑成答案:)它写于4年前,所以我确定现在情况已经变了
Sterling Archer

27

不幸的是,对于这个问题有很多不必要的复杂建议,通常涉及编写您自己的函数来进行数学或字符串操作或调用第三方实用程序。但是,在基本的JavaScript库中只有一种代码行就有一种标准的方法。可能需要将这一行代码包装在一个函数中,以避免必须指定您永远不想更改的参数,例如本地名称或样式。

var amount = 5;

var text = amount.toLocaleString('en-US',
{
    style: 'decimal',
    minimumIntegerDigits: 3,
    useGrouping: false
});

这将为文本产生值“ 005”。您还可以使用Number的toLocaleString函数将零填充到小数点的右侧。

var amount = 5;

var text = amount.toLocaleString('en-US',
{
    style: 'decimal',
    minimumFractionDigits: 2,
    useGrouping: false
});

这将为文本产生值“ 5.00”。将useGrouping更改为true以使用数千个逗号分隔符。

请注意,使用toLocaleString()with localesoptionsarguments 是在ECMA-402中而不是在ECMAScript中单独标准化的。截至今天,某些浏览器仅实现基本支持,即toLocaleString()可以忽略任何参数。

完整的例子


哇,这是一个超级干净的解决方案,可以在node.js中使用。
jishi

阅读简介时,我笑了起来-“不需要复杂的建议”。在所有工程学科中,软件开发都需要权衡取舍。我自己尝试了这种“标准方式”,并对其进行了计时。它肯定可以工作,但是我绝不会选择将其用于任何重复性应用程序,因为与许多其他“本地滚动”解决方案相比,它的速度很慢。
bearvarine

1
没错,许多内置的JavaScript函数在遍历大量数据时表现不佳,但是我认为您不应该为此使用JavaScript,即使是像Node.js这样的服务器端也是如此。如果您有大量数据要处理服务器端,则应使用更好的平台,例如.NET或Java。如果要处理要显示给最终用户的客户端数据,则应只处理当前要呈现给最终用户屏幕的数据。例如,仅渲染表格的可见行,而不处理其他道路的数据。
丹尼尔·巴拉巴拉斯

21

如果事先知道填充数不超过某个值,那么还有另一种方法可以不循环:

var fillZeroes = "00000000000000000000";  // max number of zero fill ever asked for in global

function zeroFill(number, width) {
    // make sure it's a string
    var input = number + "";  
    var prefix = "";
    if (input.charAt(0) === '-') {
        prefix = "-";
        input = input.slice(1);
        --width;
    }
    var fillAmt = Math.max(width - input.length, 0);
    return prefix + fillZeroes.slice(0, fillAmt) + input;
}

此处的测试用例:http : //jsfiddle.net/jfriend00/N87mZ/


@BrockAdams-修复了您提到的两种情况。如果数字已经和填充宽度一样宽,则不添加填充。
jfriend00

谢谢; +1。但是,负数与通常的约定略有不同。例如,在您的测试用例中,-88应该屈服"-00088"
布罗克·亚当斯

1
@BrockAdams -我不知道是否调用zeroFill(-88, 5)应产生-00088-0088?我猜这取决于您是否希望width参数是数字的整个宽度还是仅数字的数量(不包括负号)。实现者只需删除--width代码行即可轻松地将行为切换为不包括负号。
jfriend00

19

快速而肮脏的方式:

y = (new Array(count + 1 - x.toString().length)).join('0') + x;

对于x = 5和count = 6,您将拥有y =“ 000005”


1
我得到了y="0005"与上述情况,y = (new Array(count + 1 - x.toString().length)).join('0') + x;是什么给了我y="000005"
forforf

3
@OrrSiloni:最短的代码解决方案实际上是('0000'+n).slice(-4)
Seaux

14

这是我想出的一项快速功能来完成这项工作。如果有人有更简单的方法,请随时分享!

function zerofill(number, length) {
    // Setup
    var result = number.toString();
    var pad = length - result.length;

    while(pad > 0) {
        result = '0' + result;
        pad--;
    }

    return result;
}

我认为不会有“更简单”的解决方案-它始终是某种功能。我们可能会进行算法讨论,但是到最后,您仍然会得到一个零填充数字的函数。
彼得·贝利

我的一般建议是使用“ for”循环,因为它们在ECMAScript语言(ActionScript 1-3和JavaScript)中通常更稳定,速度更快
cwallenpoole

或者,完全跳过迭代;)
彼得·贝利

功能更简单?可能不是。一个不循环?这是可能的...尽管该算法并非完全无关紧要。
coderjoe

1
哇,以上所有评论几乎都是错误的。@profitehlolz的解决方案更简单并且适合于内联(不需要是一个函数)。同时,for.vs。while性能差异不足以引起关注:jsperf.com/fors-vs-while/34
broofa 2012年

12

在这里聚会晚了,但是我经常使用此结构来进行一些值的临时填充,该值n已知为正十进制:

(offset + n + '').substr(1);

哪里offset是10 ^^位数字。

例如,填充到5位数字,其中n = 123:

(1e5 + 123 + '').substr(1); // => 00123

十六进制版本稍微冗长一些:

(0x100000 + 0x123).toString(16).substr(1); // => 00123

注意1:我也喜欢@profitehlolz的解决方案,它是使用slice()的漂亮的负索引功能的字符串版本。


12

我真的不知道为什么,但是没有人以最明显的方式做到这一点。这是我的实现。

功能:

/** Pad a number with 0 on the left */
function zeroPad(number, digits) {
    var num = number+"";
    while(num.length < digits){
        num='0'+num;
    }
    return num;
}

原型:

Number.prototype.zeroPad=function(digits){
    var num=this+"";
    while(num.length < digits){
        num='0'+num;
    }
    return(num);
};

非常简单,我看不出有什么方法可以如此简单。由于某种原因,我在SO上看过很多次了,人们只是试图不惜一切代价避免“ for”和“ while”循环。对于这种琐碎的8位填充,使用正则表达式可能会花费更多的周期。




9

数学的力量!

x =要填充的整数
y =要填充的零个数

function zeroPad(x, y)
{
   y = Math.max(y-1,0);
   var n = (x / Math.pow(10,y)).toFixed(y);
   return n.replace('.','');  
}

9

我没有看到任何人指出这样的事实,当您使用带有负数的String.prototype.substr()时,它从右边开始计数。

OP的问题的一个线性解决方案,即数字5的6位零填充表示为:

console.log(("00000000" + 5).substr(-6));

概括地说,我们将得到:

function pad(num, len) { return ("00000000" + num).substr(-len) };

console.log(pad(5, 6));
console.log(pad(45, 6));
console.log(pad(345, 6));
console.log(pad(2345, 6));
console.log(pad(12345, 6));


8

经过很长很长一段时间的测试,在这个问题答案中发现了15种不同的功能/方法,我现在知道哪一种是最好的(最灵活,最快)。

我从这个问题的答案中选取了15个函数/方法,并编写了一个脚本来测量执行100个打击垫所需的时间。每个垫垫会的数量92000零。看起来确实如此,确实如此,但它为您提供了函数缩放的好主意。

我使用的代码可以在这里找到:https : //gist.github.com/NextToNothing/6325915

随时自行修改和测试代码。

为了获得最通用的方法,您必须使用循环。这是因为,如果数量很多,其他人很可能会失败,而这将成功。

那么,要使用哪个循环?好吧,那将是一个while循环。一for环依然很快,但while环只是稍快(几毫秒) -和清洁。

像这样的答案WilcoAleksandar ToplekVitim.us将完美地完成工作。

就个人而言,我尝试了另一种方法。我试图使用递归函数来填充字符串/数字。它的工作方式比连接数组的方法要好,但是仍然不如for循环快。

我的职能是:

function pad(str, max, padder) {
  padder = typeof padder === "undefined" ? "0" : padder;
  return str.toString().length < max ? pad(padder.toString() + str, max, padder) : str;
}

无论是否设置了padding变量,都可以使用我的函数。像这样:

pad(1, 3); // Returns '001'
// - Or -
pad(1, 3, "x"); // Returns 'xx1'

就个人而言,在测试之后,我会使用带有while循环的方法,例如Aleksandar ToplekVitim.us。但是,我将对其进行一些修改,以便您能够设置填充字符串。

因此,我将使用以下代码:

function padLeft(str, len, pad) {
    pad = typeof pad === "undefined" ? "0" : pad + "";
    str = str + "";
    while(str.length < len) {
        str = pad + str;
    }
    return str;
}

// Usage
padLeft(1, 3); // Returns '001'
// - Or -
padLeft(1, 3, "x"); // Returns 'xx1'

您还可以通过使用以下代码将其用作原型函数:

Number.prototype.padLeft = function(len, pad) {
    pad = typeof pad === "undefined" ? "0" : pad + "";
    var str = this + "";
    while(str.length < len) {
        str = pad + str;
    }
    return str;
}

// Usage
var num = 1;

num.padLeft(3); // Returns '001'
// - Or -
num.padLeft(3, "x"); // Returns 'xx1'

我将其放在jsfiddle中,以便他人对其进行测试,并添加了您的代码版本:jsfiddle.net/kevinmicke/vnvghw7y/2您的版本始终具有很高的竞争力,有时甚至是最快的。感谢您的详尽测试。
kevinmicke,2015年

8

第一个参数是任何实数,第二个参数是一个正整数,指定小数点左边的最小位数,第三个参数是一个可选的正整数,指定小数点右边的数字。

function zPad(n, l, r){
    return(a=String(n).match(/(^-?)(\d*)\.?(\d*)/))?a[1]+(Array(l).join(0)+a[2]).slice(-Math.max(l,a[2].length))+('undefined'!==typeof r?(0<r?'.':'')+(a[3]+Array(r+1).join(0)).slice(0,r):a[3]?'.'+a[3]:''):0
}

所以

           zPad(6, 2) === '06'
          zPad(-6, 2) === '-06'
       zPad(600.2, 2) === '600.2'
        zPad(-600, 2) === '-600'
         zPad(6.2, 3) === '006.2'
        zPad(-6.2, 3) === '-006.2'
      zPad(6.2, 3, 0) === '006'
        zPad(6, 2, 3) === '06.000'
    zPad(600.2, 2, 3) === '600.200'
zPad(-600.1499, 2, 3) === '-600.149'


8

这是ES6解决方案。

function pad(num, len) {
  return '0'.repeat(len - num.toString().length) + num;
}
alert(pad(1234,6));


显然,最优雅的解决方案是将其修改为避免2个字符串转换:const numStr = String(num)return '0'.repeat(len - numStr.length) + numStr;
ngryman

8

在所有现代浏览器中,您都可以使用

numberStr.padStart(numberLength, "0");

function zeroFill(num, numLength) {
  var numberStr = num.toString();

  return numberStr.padStart(numLength, "0");
}

var numbers = [0, 1, 12, 123, 1234, 12345];

numbers.forEach(
  function(num) {
    var numString = num.toString();
    
    var paddedNum = zeroFill(numString, 5);

    console.log(paddedNum);
  }
);

这是MDN参考https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/padStart


5

并不是说这个问题需要更多答案,但是我想我会添加一个简单的lodash版本。

_.padLeft(number, 6, '0')


1
更好:var zfill = _.partialRight(_.padStart, '0');
Droogans '16

3
有些人可能会抗议“我不想使用lodash”,但由于您只能安装以下功能npm install --save lodash.padleft,因此它已不再是有效的论点:,然后import padLeft from 'lodash.padleft'忽略_.
Andy

5

执行此操作的最新方法要简单得多:

var number = 2
number.toLocaleString(undefined, {minimumIntegerDigits:2})

output: "02"


(8).toLocaleString(undefined, {minimumIntegerDigits: 5})"00.008"根据我的语言环境为我返回。
le_m


4

这不是本地语言,但可能是最快的...

zeroPad = function (num, count) {
    var pad = (num + '').length - count;
    while(--pad > -1) {
        num = '0' + num;
    }
    return num;
};

我想你想做pad = count - (num + '').length。负数处理不好,但除此之外,还不错。+1
尼克

3

我的解决方案

Number.prototype.PadLeft = function (length, digit) {
    var str = '' + this;
    while (str.length < length) {
        str = (digit || '0') + str;
    }
    return str;
};

用法

var a = 567.25;
a.PadLeft(10); // 0000567.25

var b = 567.25;
b.PadLeft(20, '2'); // 22222222222222567.25

3

为什么不使用递归?

function padZero(s, n) {
    s = s.toString(); // in case someone passes a number
    return s.length >= n ? s : padZero('0' + s, n);
}

padZero(223,3)失败,显示为“ 0223”
Serginho

好吧,我假设使用字符串作为第一个参数调用此函数。但是,我修复了它。
lex82

2

一些猴子补丁也有效

String.prototype.padLeft = function (n, c) {
  if (isNaN(n))
    return null;
  c = c || "0";
  return (new Array(n).join(c).substring(0, this.length-n)) + this; 
};
var paddedValue = "123".padLeft(6); // returns "000123"
var otherPadded = "TEXT".padLeft(8, " "); // returns "    TEXT"

1
-1 Monkeypatching javascript中的顶级命名空间是不好的做法。
杰里米·沃尔

2
适用于Object和Array对象,但String不错
Rodrigo

2
function pad(toPad, padChar, length){
    return (String(toPad).length < length)
        ? new Array(length - String(toPad).length + 1).join(padChar) + String(toPad)
        : toPad;
}

pad(5, 0, 6) = 000005

pad('10', 0, 2) = 10 // don't pad if not necessary

pad('S', 'O', 2) = SO

...等等。

干杯


我认为应该更像是:var s = String(toPad); return (s.length < length) ? new Array(length - s.length + 1).join('0') + s : s;如果您修复它,我将取消我的反对票。
提请2012年

@drewish感谢您理解,我同意您的编辑(硬编码的0join char:除外)-答案已更新。
Madbreaks'5

我认为最好将字符串存储到一个临时变量中。我在这里做了一些基准测试:jsperf.com/padding-with-memoization,它也获得了在“新数组”中使用new的基准,new的结果无处不在,但拟态化似乎是一种方法。
drewish

2

最简单,最直接的解决方案,你会发现。

function zerofill(number,length) {
    var output = number.toString();
    while(output.length < length) {
      output = '0' + output;
    }
    return output;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.