Trim and Count the Decimals

In this challenge, you will write a program to output how many decimal places are in the input string and trim the input if needed.

Examples

-12.32
2

32
0

3231.432
3

-34.0
0 -34

023
0 23

00324.230
2 324.23

10
0

00.3
1 0.3

0
0

-04.8330
3 -4.833


Rules

• Input will be a string which can be taken through, STDIN, function arguments or the closest equivalent
• Output can be through function return, STDOUT, or the closest equivalent.
• There is no limit on the size for the input integer except for your languages maximum string length.
• If the input has any unnecessary (leading or trailing) zeros:
1. You should take them out
2. Output the amount of decimal place in the new number
3. Output the new number separated by a separator (e.g. space, newline, comma)
• Input will always match this RegEx: -?\d+(\.\d+)?, or if you don't speak RegEx:
• There could be a - at the beginning implying a negative number. Then there will be at least one digit. Then there could be... a . and some more digits.
• To check if an input is valid, check here
• No Regex

This is so shortest code in bytes wins

• Maybe add a test case with minus sign and leading zeros? Commented Jan 17, 2016 at 22:48
• Is it allowed to output the final number regardless whether it was trimmed or not? Commented Jan 17, 2016 at 22:52
• @insertusernamehere no you can only output the second number if it has been trimmed Commented Jan 17, 2016 at 22:59
• You may want to add a test case/example for a single 0. Commented Jan 17, 2016 at 23:01
• -1 for the pointless regex restriction. Commented Jan 18, 2016 at 19:10

Python 2, 165 180 bytes

At first I was thinking about writing my first Pyth program, got it to count the digits after the potential comma. But then I got quite annoyed, I don't know how you'd enjoy that language, guess it's just for winning purposes. Anyway here's my solution (edited since it didn't work for large numbers):

def t(i):
o,a='',i
while a[-1]=='0':
a=a[:-1]
while a[0]=='0':
a=a[1:]
if a[-1]=='.':a=a[:-1]
if'.'in a:o=str(len(a)-a.index('.')-1)
else:o='0'
if a!=i:o+=" "+a
print o


In case anybody wants to build on my work in Pyth: ~b@+cz"."" "1Wq@b_1"0"~b<b_1)plrb6 To see where you're at, you might want to insert a p between @+.

05AB1E, 23 bytes (non-competitive)

Damn, I was so close. Python parses very large floats using scientific notation, so I fixed this bug in the interpreter. However, this was done after the challenge and my submission is therefore non-competitive.

Code:

DÞ'.¡0Üg,\DÞ0Ü'.ÜDrQ_i,


Explanation:

D                       # Duplicate top of the stack, or input when empty
Þ                      # Convert to float
'.¡                   # Split on '.' (decimal point)
0Ü                 # Remove trailing zeroes
g                # Get the length
,               # Output top of the stack (the length)
\              # Discard the top item
D             # Duplicate top of the stack
Þ            # Convert to float
0Ü          # Remove trailing zeroes
'.Ü       # Remove trailing dots
D      # Duplicate top of the stack
r     # Reverse the stack
Q_i, # If not equal, print top of the stack


Uses the ISO 8859-1 encoding.

JavaScript (ES6), 156 162

Edit Fixed bug for '-0' - thx @Fez Vrasta Edit 2 6 bytes saved thx @Neil

It's a mess, but it's 100% string based - no limit due to numeric types

s=>(l=k=p=t=0,[...s].map(c=>++t&&c=='.'?p=t:+c&&(l=t,k=k||t)),m=p>l?p-1:p?l:t,k=k>p&&p?p-2:k-1,r=(s<'0'?'-':'')+s.slice(k,m),(p&&m>p?m-p:0)+(r!=s?' '+r:''))


Less golfed

f=s=>
(
// All values are position base 1, so that 0 means 'missing'
// k position of first nonzero digit
// l position of last non zero digit
// p position of decimal point
// t string length
l=k=p=t=0,
// Analyze input string
[...s].map((c,i)=>c=>++t&&c=='.'?p=t:+c&&(l=t,k=k||t)),
// m position of last digits in output
// if the point is after the last nz digit, must keep the digits up to before the point
// else if point found, keep  up to l, else it's a integer: keep all
m=p>l?p-1:p?l:t,
// the start is the first nonzero digit for an integer
// but if there is a point must be at least 1 char before the point
k=k>p&&p?p-2:k-1,
// almost found result : original string from k to m
r=(s<'0'?'-':'')+s.slice(k,m), // but eventually prepend a minus
(p&&m>p?m-p:0) // number of decimal digits
+(r!=s?' '+r:'') // append the result if it's different from input
)


Test

F=s=>(l=k=p=t=0,[...s].map(c=>++t&&c=='.'?p=t:+c&&(l=t,k=k||t)),m=p>l?p-1:p?l:t,k=k>p&&p?p-2:k-1,r=(s<'0'?'-':'')+s.slice(k,m),(p&&m>p?m-p:0)+(r!=s?' '+r:''))

console.log=x=>O.textContent+=x+'\n';
// Test cases
;[['-12.32','2'],['32','0'],['3231.432','3'],['-34.0','0 -34']
,['023','0 23'],['00324.230','2 324.23'],['10','0'],['00.3','1 0.3']
,['0','0'],['-0','0'],['-04.8330','3 -4.833']]
.forEach(t=>{
var i=t[0],k=t[1],r=F(i);
console.log((k==r?'OK ':'KO ')+i+' -> '+r)})

function test(){var i=I.value,r=F(i);R.textContent=r;}
test()
input { width:90% }
input,span { font-family: sans-serif; font-size:14px }
Input: <input id=I oninput='test()' value='-000000098765432112345.67898765432100000'>
Output: <span id=R></span><br>
Test cases<br>
<pre id=O></pre>

• Seems like both mine and your answers have problems with -0 as input.. we should output 0, not 0 0 Commented Jan 18, 2016 at 11:11
• Yes, thanks for pointing out Commented Jan 18, 2016 at 12:04
• @FezVrasta fixed Commented Jan 18, 2016 at 14:10
• Does c=='.'?p=t:+c&&(l=t,k=k||t) work to save you a byte?
– Neil
Commented Jan 18, 2016 at 16:53
• I think you might be able to save some more by using t=l=k=p=0 and ++t&&c=='.' etc.
– Neil
Commented Jan 18, 2016 at 16:56

ES6, 102180 177 bytes

s=>(t=s.replace(/(-?)0*(\d+(.\d*[1-9])?).*/,"$1$2"),d=t.length,d-=1+t.indexOf('.')||d,t!=s?d+' '+t:d)


s=>{t=[...s];for(m=t[0]<'0';t[+m]==0&&t[m+1]>'.';)t[m++]='';r=l=t.length;for(r-=1+t.indexOf('.')||l;t[--l]<1&&r;r--)t[l]='';t[l]<'0'?t[l]='':0;t=t.join;return t!=s?r+' '+t:r}


Edit: Saved 3 bytes thanks to @edc65; saved 1 byte thanks to insertusernamehere.

• Try spread instead of split t=[...s] Commented Jan 18, 2016 at 17:55
• @edc65 I spend ages trying to golf it back down after having to rewrite it and you go and find a 3 byte saving in a flash...
– Neil
Commented Jan 18, 2016 at 19:31
• I think you can save 1 byte: Replace t[--l]==0 with t[--l]<1. Commented Jan 18, 2016 at 20:47
– Neil
Commented Jan 19, 2016 at 0:03

PHP 7, 142 bytes

I somehow managed to squeeze everything into a single print statement:

<?=strlen((explode('.',$t=trim('-'==($_=$argv[1])[0]?$n=$_=trim($_,'-'):$_,0)))[1]).($t!==$_?($n?' -':' ').('.'==$t[0]?0:'').trim($t,'.'):'');


Runs from command line, like:

\$ php trimandcount.php "-04833.010"


Demo

See all test cases including a very long one (62 characters) in action:

1 Hover over the box below "Output for 7.0.0" to see all results.

C++, 180 bytes

int f(char*s,char*&p){int m=*s=='-',n=0;for(p=s+m;*p=='0';++p);for(;*++s-'.'&&*s;);p-=p==s;if(*s){for(;*++s;)++n;for(;*--s=='0';--n)*s=0;*s*=n>0;}if(m&&*p-'0'|n)*--p='-';return n;}


This is portable C++, that makes no assumptions of character encoding, and includes no libraries (not even the Standard Library).

Input is passed in s. The number of decimal places is returned; the string is modified in-place and the new start is returned in p.

By rights, I should return a size_t, but instead I'm going to claim that you should compile this for an OS that limits the size of strings to half the range of int. I think that's reasonable; it counts more than 2 billion decimal places on 32-bit architectures.

Explanation

int f(char*s, char*&p){
int m=*s=='-', n=0;
for(;*++s-'.'&&*s;);        // advance to decimal point
p-=p==s;                    // back up if all zeros before point
if(*s){
for(;*++s;)++n;          // count decimal places
for(;*--s=='0';--n)*s=0; // back up and null out trailing zeros
*s*=n>0;                 // don't end with a decimal point
}
if(m&&*p-'0'|n)*--p='-';    // reinstate negative sign
return n;
}


Test program

#include <cstring>
#include <cstdio>
int main(int argc, char **argv)
{
for (int i = 1;  i < argc;  ++i) {
char buf[200];
strcpy(buf, argv[i]);
char *s;
int n = f(buf, s);
printf("%10s ==> %-10s (%d dp)\n", argv[i], s, n);
}
}


Test output

    -12.32 ==> -12.32     (2 dp)
32 ==> 32         (0 dp)
3231.432 ==> 3231.432   (3 dp)
-34.0 ==> -34        (0 dp)
023 ==> 23         (0 dp)
00324.230 ==> 324.23     (2 dp)
10 ==> 10         (0 dp)
00.3 ==> 0.3        (1 dp)
-04.8330 ==> -4.833     (3 dp)
-00.00 ==> 0          (0 dp)
-00 ==> 0          (0 dp)
000 ==> 0          (0 dp)
0.00 ==> 0          (0 dp)
-0.3 ==> -0.3       (1 dp)
5 ==> 5          (0 dp)
-5 ==> -5         (0 dp)