in reply to Using Regular Expressions to Simulate sprintf() function - One Liner Challenge

First a couple of points that may or may not be obvious:

I quickly threw together a regex (included below) just for my amusement, but then got somewhat confused by the specification and the various interpretations so far. If nothing else this is an interesting exercise in both how different people will interpret the same request, and how many different tests are needed to check the behaviour of even this simple concept. I've added the samples suggested by Incognito and jeffa, as well as one of my own. I haven't bothered to fix my solution, but as you can see, none duplicated sprintf.

value|precision sprintf Incognito Albannach jeffa '123.45678'|3: 123.457 123.456 123.456 123 '12.4'|1: 12.4 12.4 12.4 12 ''|0: 0 '3.14'|5: 3.14000 3.14000 3.14000 00003.14 '1'|5: 1.00000 1.00000 1.00000 00001 '.5'|0: 1 '10'|5: 10.00000 10.00000 10.00000 00010 '12.45435'|0: 12 12 12 12 '100'|5: 100.00000 100.00000 100.00000 00100 '3.'|0: 3 3 3 3 '1000'|5: 1000.00000 1000.00000 1000.00000 01000 '12.56'|0: 13 12 12 12
was produced by
use strict; #use warnings; # sprintf doesn't like nulls as values my %test = ( '' => 0, '.5' => 0, 1 => 0, '3.' => 0, 100 => 4, 12.4 => 1, 12.56 => 0, 12.45435 => 0, 123.45678 => 3, 3.14 => 5, 1 => 5, 10 => 5, 100 => 5, 1000 => 5, ); printf('value|precision'."%12s"x4 ."\n", qw(sprintf Incognito Albannac +h jeffa)); while (my ($v,$p)= each %test) { printf("%14s:","'$v'|$p"); printf("%12s"x4 ."\n", sprintf("%.${p}f", $v), Incognito($v,$p), Albannach($v,$p), jeffa( +$v,$p) ); } sub Albannach { my($val, $pre) = @_; $val =~ s/(\d*)(\.?)(\d*)/"$1".($pre?'.':'').substr($3.'0'x$pre, 0, +$pre)/e; $val; } sub Incognito { my ($strValue,$strPrecision) = @_; # Pad the number with a bunch of zeros $strValue =~ s/^(\d*)\.?(\d*)$/${1}.${2}000000000/; # Remove all but the first '$strPrecision' digits that immediately # trail the decimal point. my $strDefaultPrecision = 2; $strPrecision = ($strPrecision >= 0) ? $strPrecision : $strDefaultPr +ecision; if ($strPrecision == 0) { $strValue =~ s/^(\d*)\.?\d*$/$1/; } else { $strValue =~ s/^(\d*\.\d{$strPrecision})\d*$/$1/; } $strValue; } sub jeffa { my ($str,$pad) = @_; my ($add,$right); ($str,$right) = split('\.',$str,2); $right = ($right) ? ".$right" : ''; $add = $pad - length($str); return $str if $add < 1; return ('0' x $add) . $str . $right; }

--
I'd like to be able to assign to an luser

Replies are listed 'Best First'.
Re: Re: Using Regular Expressions to Simulate sprintf() function - One Liner Challenge
by Incognito (Pilgrim) on Nov 07, 2001 at 00:05 UTC

    Yes, good point... We're not really simulating sprintf(), but just the part where we take a number and add a decimal place at one part of a number and format it to our liking...

    I think a lot of people didn't notice that the Perl code was just a snippet of what was in the actual function, and that I didn't provide the entire thing... if we examine the JavaScript version, we will notice that it handles the special cases:

    strValue += ""; // Convert any digits to string if (! strValue) { strValue = "0"; } // Convert empty string to 0 // Set any non-numeric values to 0 if (! strValue.match (/^\d+\.?$|\d+\.?\d*$|\d*\.?\d+$/)) { strValue += "0"; } // Add a leading 0 to any numbers starting with a decimal point if (strValue.match (/^\./)) { strValue = "0" + strValue; }

    So what we really have (without actually provided the entire function :) is:

    value|precision sprintf Incognito Albannach jeffa r +ob_au '123.45678'|3: 123.457 123.456 123.456 123 12 +3.457 '12.4'|1: 12.4 12.4 12.4 12 + 12.4 ''|0: 0 0 + 0 '3.14'|5: 3.14000 3.14000 3.14000 00003.14 3. +14000 '1'|5: 1.00000 1.00000 1.00000 00001 1. +00000 '.5'|0: 0 0 + 1 '10'|5: 10.00000 10.00000 10.00000 00010 10. +00000 '12.45435'|0: 12 12 12 12 + 12 '100'|5: 100.00000 100.00000 100.00000 00100 100. +00000 '3.'|0: 3 3 3 3 + 3 '1000'|5: 1000.00000 1000.00000 1000.00000 01000 1000. +00000 '12.56'|0: 13 12 12 12 + 13