11
\$\begingroup\$

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

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

6 Answers 6

4
\$\begingroup\$

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 @+.

\$\endgroup\$
0
2
\$\begingroup\$

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.

\$\endgroup\$
0
2
\$\begingroup\$

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>

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

ES6, 102 180 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.

\$\endgroup\$
4
  • \$\begingroup\$ Try spread instead of split t=[...s] \$\endgroup\$
    – edc65
    Jan 18, 2016 at 17:55
  • \$\begingroup\$ @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... \$\endgroup\$
    – Neil
    Jan 18, 2016 at 19:31
  • \$\begingroup\$ I think you can save 1 byte: Replace t[--l]==0 with t[--l]<1. \$\endgroup\$ Jan 18, 2016 at 20:47
  • \$\begingroup\$ @insertusernamehere Thanks! \$\endgroup\$
    – Neil
    Jan 19, 2016 at 0:03
0
\$\begingroup\$

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:

Try before buy1

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

\$\endgroup\$
0
0
\$\begingroup\$

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(p=s+m;*p=='0';++p);     // trim leading zeros
    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)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.