16

How can I remove all the leading zeroes but leave a final zero if the value only contains zeroes?

for example:

my $number = "0000";

I would like to have:

my $number = "0";

I tried:

$number =~ s/^0*//; 

but this of course removes all the zeroes in this case.

perlfoo
  • 161
  • 1
  • 1
  • 4

8 Answers8

24

This should work:

$number =~ s/^0*(\d+)$/$1/;

0    -> 0
0000 -> 0
0001 -> 1

Edit: turns out that's just a bit too complicated. This should also work:

$number =~ s/0*(\d+)/$1/;

but I'm not sure which is better, depends on the use case.

Do check out the answer from Oesor: it's pretty sweet too, no regex involved.

Community
  • 1
  • 1
Mat
  • 202,337
  • 40
  • 393
  • 406
  • Well, I guess in the first case you will not get the match unless the EOL is immediately preceeded by the number so probably 2) gives more flexibility, whereas the first can also do the work to check the format of the input. – fnokke Apr 15 '11 at 15:32
13

This doesn't need to be done as a regex.

my @nums = qw/ 00000 000 000001 002 00000005 00000064 /;
@nums = map { $_ + 0 } @nums;
Oesor
  • 6,632
  • 2
  • 29
  • 56
  • 7
    I don't think it's a joke, and it actually more directly addresses what may be the unstated underlying problem, canonicalizing the string representation of numbers. – ysth Apr 15 '11 at 15:25
  • This worked too...the data I'm working with is in the form of: $data = "0225 0000 030"; I was using split(" ", $data) then a foreach loop to process. Finishing with a join(). – perlfoo Apr 15 '11 at 15:32
  • So you want to end up with `225 0 30`? Why not just do `$data =~ s/\b0+(\d)/$1/g;`? – Alan Moore Apr 15 '11 at 15:41
  • 2
    No, just a reminder that putting a string through a numerical then string context is going to strip off leading zeros, among other things. It's of course not suited for large numbers due to some of the other stuff that goes on. For example, `perl -E "say q(000000123456789012345678901234567890) + 0"` – Oesor Apr 15 '11 at 18:40
8
$number =~ s/^0+(?=\d)//;

The positive lookahead ensures there's at least one digit left, and using + instead of * means the substitution is skipped if there are no leading zeroes.

If you're trying to normalize groups of numbers in a single string, just use \b instead of ^, and do a global substitution:

my $data = "0225 0000 030";
$data =~ s/\b0+(?=\d)//g;
cjm
  • 61,471
  • 9
  • 126
  • 175
  • ...or `(?<!\d)` if digit groups might be preceded by letters or [connector punctuation](http://www.fileformat.info/info/unicode/category/Pc/list.htm). – Alan Moore Apr 15 '11 at 16:39
2

Just add 0 to the string so that it's implicitly converted to a number:

my $var = '0000035600000';
$var += 0;
Anthony Geoghegan
  • 11,533
  • 5
  • 49
  • 56
jaimebl
  • 59
  • 2
2

Some answers are implicitly assuming there are only digits present or that $number is in fact a number. If this is not the case:

s/^0+(?=.)//s

Or even:

substr($number,0,-1) =~ s/^0+//s
ysth
  • 96,171
  • 6
  • 121
  • 214
  • What changed with lvalue substr? – ikegami Apr 15 '11 at 19:30
  • @ikegami: nothing relevant to this case, I was misremembering. The change was that the length of the lvalue used to stay fixed, so `$n="01"; for (substr($n,0,-1)) { s/^0+//; print }` would print "1" instead of "". – ysth Apr 16 '11 at 01:42
2

If your $number is an integer, another way is to use printf:

for my $number (qw(005 05 5 000 0 500)) {
    printf "%d\n", $number;
}

__END__

5
5
5
0
0
500

Edit: As ysth points out, it works for all integers, not just positive integers as I originally stated.

toolic
  • 57,801
  • 17
  • 75
  • 117
1

You could also use the sprintf function in Perl:

# Input variables
$valuesA = "0";
$valuesB = "00001";
$valuesC = "000.1";
$valuesD = "00010";

# Format number with zero leading zeroes
# $valuesA = sprintf("%0d", $valuesA);
$valuesA = sprintf("%0g", $valuesA);
$valuesB = sprintf("%0g", $valuesB);
$valuesC = sprintf("%0g", $valuesC);
$valuesD = sprintf("%0g", $valuesD);

# Output variables
print "valuesA: $valuesA\n"; # returns "0"
print "valuesB: $valuesB\n"; # returns "1"
print "valuesC: $valuesC\n"; # returns "0.1"
print "valuesD: $valuesD\n"; # returns "10"
Peter
  • 1,224
  • 3
  • 16
  • 28
0

Well if you want to replace all by one just change to s/^0+/0/ ?

However, this will replace all leading 0's by one 0 so if you have leading zeros before numbers you will need Mats construct.

fnokke
  • 1,121
  • 8
  • 18
  • 1
    This will reduce `001` to `01`, which I don't think is what the OP wants. – JSBձոգչ Apr 15 '11 at 14:49
  • 2
    `"001"` should become `"1"`, not `"01"` – sverre Apr 15 '11 at 14:51
  • @JSBangs,ridgerunner,sverre: You are all correct, I should have thought more about he was actually trying to accomplish, but I do not see any of that in the initial statement. I will put my vote on Mat and change * to +. – fnokke Apr 15 '11 at 15:08