Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.javascript > #14625

Re: Placing 'zeros' in front of a number ?

Message-ID <1623778.oMNUckLgyt@PointedEars.de> (permalink)
From Thomas 'PointedEars' Lahn <PointedEars@web.de>
Organization PointedEars Software (PES)
Date 2012-06-23 19:47 +0200
Subject Re: Placing 'zeros' in front of a number ?
Newsgroups comp.lang.javascript
References <a4ht2oFf7iU1@mid.individual.net> <68f86607-2127-46c8-b59d-a0b010335f32@googlegroups.com> <js1amg$mv1$1@dont-email.me>
Followup-To comp.lang.javascript

Followups directed to: comp.lang.javascript

Show all headers | View raw


Gregor Kofler wrote:

> Am 2012-06-22 05:18, Michael Haufe (TNO) meinte:
>> On Thursday, June 21, 2012 7:37:43 PM UTC-5, Mel Smith wrote:
>> [...]
>>>      I've got a bunch of numbers (in string format), that I want to
>>>      convert
>>> to strings of a standard length of four characters:
>>>
>>>      e.g.,    '1'     >>> '0001'
>>>               '10'    >>> '0010'
>>>             '123'    >>> '0123'
>>>             '4567'  >>> '4567'    // leave as is for length of 4
>> [...]
>>
>> Perhaps something like this:
>>
>> String.prototype.padLeft = function(ch,len){
>>      return Array(Math.max(0, len - this.length + 1)).join(ch) + this;
>> }
> 
> Or
> 
> String.prototype.lpad = function(len, fchar) {
>    var i = len-this.length, pad = "", f = fchar || " ";
>    while(i--) { pad += f; }
>    return pad+this;
> };
> 
> In a completely un-scientific benchmark in Firefox and Chromium this 
> solution is about twice as fast (the difference becomes less with very 
> long paddings). In any case I would change your order of arguments since 
> "len" is in any case a required argument, whereas "ch" can be set to a 
> default value.

Having reviewed these two solutions (see below), I still prefer mine (in 
JSX:string.js@244):

/**
 * Non-breaking space
 */
var CH_NBSP = "\xA0";

/**
 * @param s : optional string
 *   Input string.  If omitted and the calling object
 *   is a String object, it is used instead.
 * @param n : optional number = 1
 *   Length of the resulting string.  The default is 1,
 *   i.e. if the input string is empty, "0" is returned
 *   if c is <code>'0'</code>.
 * @param c : optional string = CH_NBSP
 *   Character string to use for padding.  The default
 *   is one non-breaking space.
 * @param bRight : optional boolean = false
 *   If <code>true</code>, s is padded on the right,
 *   otherwise on the left.
 * @param iStart : optional number
 *   Assume that s is iStart characters long.
 * @return string
 *   The padded input string so that its length is n.
 */
var pad = jsx.string.pad = function(s, n, c, bRight, iStart) {
  var constr;
  if ((constr = this.constructor) && constr == String
      && typeof s != "string")
  {
    s = this;
  }
  
  if (!n)
  {
    n = 1;
  }
  
  if (!c)
  {
    c = CH_NBSP;
  }
  
  if (typeof s != "string")
  {
    s = String(s);
  }
  
  if (typeof iStart == "undefined")
  {
    iStart = s.length;
  }
  
  if (n <= iStart)
  {
    return s;
  }
  
  var a = [];
  var missingLength = n - iStart + 1;
  
  if (typeof a.join == "function"
      && (missingLength > -1) && (missingLength < Math.pow(2, 32)))
  {
    a.length = missingLength;
    var rep = a.join(c);
    if (bRight)
    {
      s += rep;
    }
    else
    {
      s = rep + s;
    }
  }
  else
  {
    while (iStart < n)
    {
      if (bRight)
      {
        s += c;
      }
      else
      {
        s = c + s;
      }
  
      iStart++;
    }
  }

  return s;
};  

for which there is

/**
 * @param s : optional string
 *   Input string.  If omitted and the calling object
 *   is a String object, it is used instead.
 * @param n : optional number
 *   Length of the resulting string.  The default is 1,
 *   i.e. if the input string is empty, "0" is returned.
 * @return string
 *   Input string with leading zeros so that
 *   its length is @{(n)}.
 * @see
 *   #pad(string, number, string)
 */
function leadingZero(s, n)
{
  var c;
  if ((c = this.constructor) && c == String && typeof s != "string")
  {
    s = this;
  }
   
  return pad(s, n, "0");
}

here.

jsx.string.pad() being used by leadingZero() scores over the two solutions 
above in several respects:

- It can be, but does not have to be, transferred to String instances or
  String prototypes for use as a method (one might even consider using
  `instanceof' now in case someone wants to inherit from String.prototype). 
  This makes it directly applicable to non-string values.  Both solutions
  above can only be used with objects inheriting from String.prototype.

- It does not pad if there is nothing to pad.  Both solutions above do that.

- It has no dependency on the run-time values of `Array' and `Math.max',
  so overwriting those properties should not be able to stop it from
  working.  Michael's solution depends on both.

- It minimizes method calls, which are expensive.  Michael's solution uses
  several method calls.  Gregor's uses none, but at the price of repeated
  non-native string concatenation when not necessary.

- It avoids repetitive non-native concatenation, which is expensive with
  long strings.  Michael's solution avoids that too, but at the price
  of not being able to work with len > Math.pow(2, 32) - 1.

- It works efficiently with len smaller than or equal to
  Math.pow(2, 32) - 1, but also works with greater values.

- It can handle awkward values.  Gregor's solution hangs in an endless loop
  when passed a len < this.length.  Michael's handles that problem with
  Math.max().

- It can handle literal 0 (any convertible false-value, really) as pad
  value.  Gregor's solution would default to a space character then.

- It pads with one *non-breaking* space by default.  With Michael's
  you have to be explicit, Gregor's defaults to a space.

- It is backwards-compatible to a large degree:

  + It uses a loop where is no Array.prototype.join() or the padding
    length does not fit.  

  + It does not depend on a single numeric argument to `Array' designating
    the array length.  This was a concern with earlier JavaScript versions –
    but then again those versions also did not support the Array initializer
    that I am using now.  I am not aware of other implementations copying
    the non-conforming behavior, although there may be some.

  Michael's solution is not backwards-compatible.  Gregor's is more
  backwards-compatible than mine, but at the price of insufficient
  fallbacks and reduced speed in the worst case.

- It can pad either left or right which makes it useful for an sprintf()
  implementation.  The solutions above require an extra implementation
  for padding right-hand side.

- It is not depend on the string length of the value to be padded.
  Apparently sometimes it is useful to let the string length of a value
  appear longer or shorter than it actually is (I do not remember the
  use-case right now, but I am sure there was one).  You can pass a value
  for iStart (don't ask) to tell jsx.string.pad() that the actual string
  length does not matter.

Constructive comments and suggestions are welcome.  (I know it still spoils 
the global namespace a bit.  This will be fixed but is kept until depending 
code has been fixed.)

However: All our solutions fail to achieve properly left-padding string 
representations of negative numbers.  (Since fixing that would require yet 
another parameter for jsx.string.pad() – to keep it general –, perhaps it is 
time now to support a second `options' parameter; whenever it is not a 
number, try accessing the properties of the referred object for options.)


PointedEars
-- 
var bugRiddenCrashPronePieceOfJunk = (
    navigator.userAgent.indexOf('MSIE 5') != -1
    && navigator.userAgent.indexOf('Mac') != -1
)  // Plone, register_function.js:16

Back to comp.lang.javascript | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread


Thread

Placing 'zeros' in front of a number ? "Mel Smith" <med_cutout_syntel@aol.com> - 2012-06-21 18:37 -0600
  Re: Placing 'zeros' in front of a number ? Gene Wirchenko <genew@ocis.net> - 2012-06-21 18:59 -0700
  Re: Placing 'zeros' in front of a number ? "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2012-06-21 20:18 -0700
    Re: Placing 'zeros' in front of a number ? "Mel Smith" <med_cutout_syntel@aol.com> - 2012-06-21 22:51 -0600
    Re: Placing 'zeros' in front of a number ? Gregor Kofler <usenet@gregorkofler.com> - 2012-06-22 10:34 +0200
      Re: Placing 'zeros' in front of a number ? Scott Sauyet <scott.sauyet@gmail.com> - 2012-06-22 04:49 -0700
        Re: Placing 'zeros' in front of a number ? "Mel Smith" <med_cutout_syntel@aol.com> - 2012-06-22 08:39 -0600
        Re: Placing 'zeros' in front of a number ? "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2012-06-22 13:05 -0700
        Re: Placing 'zeros' in front of a number ? Gene Wirchenko <genew@ocis.net> - 2012-06-22 14:10 -0700
      Re: Placing 'zeros' in front of a number ? "Evertjan." <exxjxw.hannivoort@inter.nl.net> - 2012-06-22 22:58 +0000
        Re: Placing 'zeros' in front of a number ? Hans-Georg Michna <hans-georgNoEmailPlease@michna.com> - 2012-06-23 18:47 +0200
          Re: Placing 'zeros' in front of a number ? "Evertjan." <exxjxw.hannivoort@inter.nl.net> - 2012-06-23 21:44 +0000
            Re: Placing 'zeros' in front of a number ? "Mel Smith" <med_cutout_syntel@aol.com> - 2012-06-23 16:48 -0600
        Re: Placing 'zeros' in front of a number ? "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2012-06-23 16:56 -0700
      Re: Placing 'zeros' in front of a number ? Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2012-06-23 19:47 +0200
        Re: Placing 'zeros' in front of a number ? Gregor Kofler <usenet@gregorkofler.com> - 2012-06-23 20:52 +0200
          Re: Placing 'zeros' in front of a number ? Gregor Kofler <usenet@gregorkofler.com> - 2012-06-23 21:01 +0200
        Re: Placing 'zeros' in front of a number ? "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2012-06-23 17:05 -0700
          Re: Placing 'zeros' in front of a number ? Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2012-06-24 03:51 +0200
            Re: Placing 'zeros' in front of a number ? "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2012-06-25 20:19 -0700
              Re: Placing 'zeros' in front of a number ? Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2012-06-26 09:04 +0200
                Re: Placing 'zeros' in front of a number ? "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2012-06-26 08:32 -0700
                Re: Placing 'zeros' in front of a number ? Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2012-06-26 22:12 +0200
                Re: Placing 'zeros' in front of a number ? "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2012-06-30 13:41 -0700
              Re: Placing 'zeros' in front of a number ? Dr J R Stockton <reply1226@merlyn.demon.co.uk.not.invalid> - 2012-06-27 19:34 +0100
  Re: Placing 'zeros' in front of a number ? Dr J R Stockton <reply1225@merlyn.demon.co.uk.not.invalid> - 2012-06-23 20:00 +0100

csiph-web