4
\$\begingroup\$

Given a string, determine if it is an int, a float or neither.

Examples

  • 123 - int
  • 62727.0033 - float
  • 644c.33 - neither

Your code should output a different value depending on which it is. For example it could return "i" for int, "f" for float and "n" for neither.

Details

The following are floats:

1.00 -0.0 1.0

The following are not floats:

 1e3 1.0ec3 -1e3 1e-3 1e+3 --1.0 +1.0 NaN 1.0.0 1. .1 -001.1

The following are ints:

42 -2 -0

The following are not ints:

042 00

In short, the rule for floats is that it is a sequence of digits following by a . followed by a sequence of digits. Optionally - is prepended. If it starts with 0 then the . must follow directly afterwards.

The rule for ints is that it is a sequence of digits where the first digit is not 0. The only exception is that 0 and -0 are ints.

Either sort of number can have - optionally prepended to it.

You can assume the input will only contain printable-ASCII.

\$\endgroup\$
9
  • 1
    \$\begingroup\$ Why are leading zeros disallowed at all? Seems a bit arbitrary, but it sounds like the challenge is really to detect canonically-formatted int / float. \$\endgroup\$ Commented Mar 13, 2022 at 23:21
  • \$\begingroup\$ @graffe: why is +1.0 not a float in ur mind ? "sequence of digits following by a . followed by a sequence of digits" - this satisfies the rule. while + is optional, and most don't include it, that doesn't make this number any less valid of a float. \$\endgroup\$ Commented Dec 19, 2022 at 12:02
  • \$\begingroup\$ @RAREKpopManifesto I didn't think of it! Is that a valid float in many languages? \$\endgroup\$
    – user108721
    Commented Dec 19, 2022 at 12:03
  • \$\begingroup\$ echo '+1.0' | awk '$++NF = exp($1)' ::::::::::::::::::::::::::::: :::::::::::::::::::::::::::: ::::::::::::::: +1.0 2.71828. :::::::::::::::::::::::::::: :::::::::::::::::::::::: :::::::::::::::::::::::: Even though its effects are transparent by and large, any parser that fails to properly recognize and parse a positive sign, is not worth its salt. \$\endgroup\$ Commented Dec 19, 2022 at 12:04
  • \$\begingroup\$ echo '+1.0' | python3 -c 'import sys, math; [ print(math.exp(float(_))) for _ in sys.stdin ]' 2.718281828459045 \$\endgroup\$ Commented Dec 19, 2022 at 12:09

9 Answers 9

5
\$\begingroup\$

APL (Dyalog Unicode), 46 39 bytes

Anonymous tacit prefix function. Returns 3 for float, 2 for int, and empty list for neither.

≢¨'^-?(0|[1-9]\d*)(\.\d+)?$'⎕S{⍵.Names}

Try it online!

Searches for the PCRE pattern ^-?(0|[1-9]\d*)(\.\d+)?$ then returns the name of the whole match and of each matched sub-pattern. Finally, the length of each (≢¨) list of names is returned. Since floats fill both sub-patterns, we get 3, while ints skip the last sub-pattern and thus give 2. Non-matches give an empty list.

\$\endgroup\$
4
\$\begingroup\$

Python 3.8 (pre-release), 87 bytes

lambda s:"-if"[getattr(re.match(r'-?(0|[1-9]\d*)(\.\d+)?$',s),'lastindex',0)]
import re

Try it online!

Straight-forward regular expression. Python wrapper feels a bit clumsy, though.

Returns 'i','f' and '-'. If we are ok with 1,2 and 0 instead that would save 7 bytes.

Details:

re.match only matches at the beginning, no ^ required. Annoyingly, Python returns two different object types, depending on whether there is a match or not. To work around this we use the cumbersome getattr which allows us to specify a fallback for non existent attributes.

\$\endgroup\$
3
\$\begingroup\$

Haskell, 95.. 61 bytes

f l=[1|(n,_)<-reads l,x<-["-0",show$round n],x==l||l==show n]

Try it online!

  • As pointed out by @Peter Cordes there are floating point issues.
  • Saved 18 Bytes by removing type hint to reads , thanks to @Unrelated String !
  • Thanks to @Wheat Wizard for saving another 8 Bytes by applying do notation!
  • Saved again 6 Bytes by @Wheat Wizard with a great use of list comprehension.

Returns:
[] = neither
[1] = Int
[1,1] = Float

We can return:
"" = neither
"1" = Int
"11" = Float
By adding 2Bytes and building a [Char] list instead of [Int].
Or an integer 0,1 or 2 by applying sum to the result for +3

f l uses list comprehension conditional trick :
If reads finds a number then we use (!) to determine its type.
If it fails it return an empty list , hence list comprehension is empty.

(!) compares value found with input reconverting it to string

We sum to get a consistent value for neither , we would get 0 or empty list

9 Bytes could be saved if we haven't to handle -0

\$\endgroup\$
13
  • 1
    \$\begingroup\$ FP rounding is a problem for converting back to a string to verify canonical form (no leading zeros). In your TIO link, print $ f"3.141592653589793" produces 0, unlike 2 for your shorter test that can apparently round-trip with enough precision. (h-schmidt.net/FloatConverter/IEEE754.html shows that when rounded to the nearest IEEE754 float32, we get 3.1415927410125732421875. Any fixed-width FP format, binary or decimal, will have this problem eventually, with enough significant fractional digits.) \$\endgroup\$ Commented Mar 13, 2022 at 23:36
  • 1
    \$\begingroup\$ IDK what the intent of the question is, whether we should be use algorithms that do work up to some precision limits. (Numbers like 1.3 or 3.14159 also aren't exactly representable as float32 or float64, but your code does work for them by rounding back to the input number of digits (I'm guessing, since I don't know Haskell), which seems like a good attempt.) But OTOH, one could equally say that trying to encode unbounded-length decimal-fraction strings into a fixed-width float is a showstopper design error you were tricked into by the Q. I think it's interesting at least, so +1 from me. \$\endgroup\$ Commented Mar 13, 2022 at 23:40
  • 2
    \$\begingroup\$ @Peter Cordes thanks! Tbh I haven't considered fp imprecision nor the op gave specifications about it( fp errors are usually accepted when a challenge involves that but at the same time this is more about parsing a string so they may not be acceptable), i started with this approach and a pattern matching approach then I developed only this because it was shorter and it seemed more interesting. \$\endgroup\$
    – AZTECCO
    Commented Mar 14, 2022 at 9:11
  • 1
    \$\begingroup\$ @Unrelated String thanks! Still assuming fp imprecisions it works, i tried to cut off the hint but didn't work , probably I messed up a bit on something else \$\endgroup\$
    – AZTECCO
    Commented Mar 14, 2022 at 9:19
  • 1
    \$\begingroup\$ This can be shortened to 69 bytes, however both versions produce the wrong output for -001.1 which should be a float. \$\endgroup\$
    – Wheat Wizard
    Commented Mar 14, 2022 at 10:02
1
\$\begingroup\$

QuadS, 31 bytes

Equivalent of my APL answer.

≢¨⍵
^-?(0|[1-9]\d*)(\.\d+)?$
⍵N

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Retina 0.8.2, 35 bytes

^-?(0|[1-9]\d*)(?<1>\.\d+)?$|.+
$#1

Try it online! Link includes test cases. Outputs 2 for float, 1 for integer and 0 for everything else. Explanation:

^-?(0|[1-9]\d*)(?<1>\.\d+)?$|.+

Try to match an integer with an optional decimal fraction. Capture both the integer and the fraction (if it's present) in capture group 1. If the input is neither then simply match it all without capturing anything.

$#1

Output the number of captures of capture group 1.

\$\endgroup\$
1
\$\begingroup\$

PowerShell, 56 bytes

Takes a single number as a string; outputs 0 for other, 3 for integer, and 4 for float

("$args"-match"^-?(0|[1-9]\d*)(\.\d+)?$")+$matches.Count

Try it online!

PowerShell (Alternate Regex), 56 bytes

("$args"-match"^-?((?!0)\d+|0)(\.\d+)?$")+$matches.Count

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Go, 135 bytes

package n
import."strconv"
func f(s string)byte{if _,e:=Atoi(s)
e==nil{return'i'}
if _,e:=ParseFloat(s,64)
e==nil{return'f'}
return'n'}

Go, 418 bytes

Some people have mentioned that the code above doesn't pass all test cases. I realized that the rules in the question don't actually match rules used by programming languages on what qualifies as an integer or float. For example, the rules say that 1e3 is not a float, but in reality it is:

package main

import (
   "fmt"
   "strconv"
)

func main() {
   f, err := strconv.ParseFloat("1e3", 64)
   fmt.Println(f, err) // 1000 <nil>
}

So I made an edit to handle these rules:

package n
import."strconv"
func f(s string)byte{if s[0]=='0'&&s[1]!='.'{return'n'}
if len(s)>=3&&s[:2]=="-0"&&s[2]!='.'{return'n'}
if s[0]=='-'{}else if s[0]>='0'&&s[0]<='9'{}else{return'n'}
if s[len(s)-1]>='0'&&s[len(s)-1]<='9'{}else{return'n'}
for _,r:=range s{if r=='-'{}else if r=='.'{}else if r>='0'&&r<='9'{}else{return'n'}}
if _,e:=Atoi(s);e==nil{return'i'}
if _,e:=ParseFloat(s,64);e==nil{return'f'}
return'n'}

Test:

package n

import (
   "fmt"
   "testing"
)

type testType struct {
   in string
   out byte
}

var tests = []testType{
   {"+1.0", 'n'}, {"--1.0", 'n'}, {"-0", 'i'}, {"-0.0", 'f'}, {"-001.1", 'n'},
   {"-1e3", 'n'}, {"-2", 'i'}, {".1", 'n'}, {"00", 'n'}, {"042", 'n'},
   {"1.", 'n'}, {"1.0", 'f'}, {"1.0.0", 'n'}, {"1.00", 'f'}, {"1.0ec3", 'n'},
   {"123", 'i'}, {"1e+3", 'n'}, {"1e-3", 'n'}, {"1e3", 'n'}, {"42", 'i'},
   {"62727.0033", 'f'}, {"644c.33", 'n'}, {"NaN", 'n'},
}

func TestNumber(t *testing.T) {
   for _, test := range tests {
      out := f(test.in)
      if out != test.out {
         fmt.Printf("%v %c %c\n", test.in, test.out, out)
      }
   }
}
\$\endgroup\$
5
  • 2
    \$\begingroup\$ Welcome to the site! I believe you do not need to count the package n because you are creating a function, so that should save you some. I also think you can save on the second : be doing your assignments outside the scope of the if. Try it online! \$\endgroup\$
    – Wheat Wizard
    Commented Mar 14, 2022 at 17:53
  • 2
    \$\begingroup\$ You can also include a link to tio in your answer to make it easier to test for other people. I liked tio in my comment, from there you can add more test cases if you'd like and if you hit the link icon at the top you can get either a link to the code, or an already formatted answer including the link, score etc. \$\endgroup\$
    – Wheat Wizard
    Commented Mar 14, 2022 at 17:55
  • 1
    \$\begingroup\$ I would avoid this sort of petty comment, especially since you do not know anything about my experience with golang. If you want to include extra stuff that is fine however you want to play the game is valid, most people play it slightly differently and you are also free to play it that way. The other suggestion still stands however you can make it shorter by reorganizing your declarations and avoiding a :. \$\endgroup\$
    – Wheat Wizard
    Commented Mar 14, 2022 at 21:10
  • \$\begingroup\$ I was assigned this answer as a part of our review queues system, that is why I've taken a particular interest in it. My goal has only been to help you. Our policy on answers failing to meet the output specification is documented here all answers are subject to these rules. \$\endgroup\$
    – Wheat Wizard
    Commented Mar 14, 2022 at 21:53
  • 2
    \$\begingroup\$ You do realise that not only can moderators see deleted comments, we can also see who deleted them? Your accusations that others are deleting your responses and don't know any Go really shift my opinion of you towards "obvious troll", especially taking into account one of your previous answers \$\endgroup\$
    – Jo King
    Commented Mar 15, 2022 at 6:41
0
\$\begingroup\$

Charcoal, 55 bytes

≔⁰ηFS≡ι-≔∨¬η¹⁵η.≔⎇⊖↔⁻⁸η¹⁵¦⁵η0≔⎇›²η⁷|⁸ηη≔|⁹⎇Σιη⁶η§00121η

Try it online! Link is to verbose version of code. Outputs 2 for float, 1 for integer and 0 for everything else. Explanation: Implements a state machine (see below).

≔⁰η

Start in state 0.

FS≡ι

Switch over the input string's characters.

-≔∨¬η¹⁵η

- transitions from state 0 to state 1 and from any other state to state 15.

.≔⎇⊖↔⁻⁸η¹⁵¦⁵η

. transitions from states 7 or 9 to state 5 and from any other state to state 15.

0≔⎇›²η⁷|⁸ηη

0 transitions from states 1 or 2 to state 7 and from any other state to the result of a bitwise OR with 8.

≔|⁹⎇Σιη⁶η

Any other digit transitions by the result of a bitwise OR with 9 and any other character transitions to state 15 (obtained via a bitwise OR of 6 with 9).

§00121η

Look up the acceptance value of the final state, modulo 5. State 13 is reached for floats. State 7 is reached for 0 and state 9 is reached for other integers. States 0, 1, 5 and 15 cover everything else. Transition table:

- . 0 \d X Pattern
0 1 15 7 9 15 ^
1 15 15 7 9 15 ^-
5 15 15 13 13 15 ^-?(0|[1-9]\d+)\.
7 15 5 15 15 15 ^-?0
9 15 5 9 9 15 ^-?[1-9]\d+
13 15 15 13 13 15 ^-?(0|[1-9]\d+)\.\d+
15 15 15 15 15 15
\$\endgroup\$
-1
\$\begingroup\$

Mathematica, 93 bytes

 Which[#~(a=StringMatchQ)~(b=RegularExpression)[c="-?([1-9]\\d*|0)"],0,#~a~b[c<>"\\.\\d+"],1]&

Which, being Mathematica's if-elseif chain. Just tests if the argument matches a regular expression for ints, then floats, all wrapped up in a lambda / pure function.

0 = int
1 = float
Null = neither

Mathematica, 81 bytes

Using the "a different value" Mathematica is fine returning complex symbols:

 #~(a=StringMatchQ)~(b=RegularExpression)[c="-?([1-9]\\d*|0)"]-#~a~b[c<>"\\.\\d+"]&

Parenthesis and square brackets remain for order of operations.

-False + True = int
False - True = float
0 = neither

\$\endgroup\$

Your Answer

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