How to parse integers separated by dots

I decided to parse versions for an application I’m working on. I haven’t used the elm/parser package very much, and ran into something I didn’t understand, and was hoping someone could help me explain. Given this program:

type alias Version =
    ( Int, Int, Int )

parser : Parser Version
parser =
    Parser.succeed (\ma mi pa -> ( ma, mi, pa ))
        |= Parser.int
        |. Parser.symbol "."
        |= Parser.int
        |. Parser.symbol "."
        |= Parser.int

I tried to run Parser.run parser "3.0.0", which resulted in Err [{ col = 1, problem = ExpectingInt, row = 1 }]

the “.”-symbol in combination with integers seem to cause the issue, as everything works great if I try to parse “,”-symbols on a string like “3,0,0”.

Thanks for look at this :sunny:

1 Like

The problem is the way that the Elm parser works for ints is it parses a number, and then treats anything that isn’t an int as invalid (specifically, int is implemented using number), so it ends up parsing 3.0.0 as the floating point number 3.0 and then failing because that’s not an integer.

You probably need to change to parse for digit characters and then later convert those digits into ints to avoid this.

1 Like

I sort of expected this problem, but how do I parse integers in this sort of way?

Tricky!

You could do you own little int parser like this: https://ellie-app.com/gdZyzdvNQR2a1 (This implementation assumes you don’t accept negative numbers).

Though at that point, you might consider an even more basic “parser”: https://ellie-app.com/gdZDxHsJnJVa1

Hope that’s helpful!

3 Likes

Thanks for implementing it for me - I’m still unsure why my implementation is failing, but Igues it has to do with Parser.float or this sort of thing.

Thanks :sunny:

Note, some known related issues with Parser.int: int parser fails on trailing decimal separator · Issue #14 · elm/parser · GitHub

If you replace the . with something else then you can use your parser almost unchanged. E.g.

parser : Parser Version
parser =
    Parser.succeed (\ma mi pa -> ( ma, mi, pa ))
        |= Parser.int
        |. Parser.symbol "|"
        |= Parser.int
        |. Parser.symbol "|"
        |= Parser.int

parse =
  String.replace "." "|"  >> Parser.run parser

 "100.200.300"
    |> parse
1 Like

Yes - like my example using commas :blush: I was more interested in finding out why an integer-parser changes behavior based on a character that has nothing to do with integers AFAIK

I think the parser is trying to give an error in the case where it’s parsing a float instead of int. Thus when it sees your “.” it thinks “oh, this is a float, i must fail!” and does so. It is not technically wrong, but it’s an inconvenient design for this case. It would be nice to have one that just accepts the integer once there are no more numbers. I can recommend reading the source if you want to understand further!

1 Like

There are also some handy helpers for dealing with version strings in this package:

https://package.elm-lang.org/packages/elm/project-metadata-utils/latest/Elm-Version#fromString

3 Likes

Yeah, sorry - I should’ve read the source initially instead of asking. Many thanks tho!

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.