# How to use elm/parser to parse Int's followed by a period (like in IP Addresses)?

**URL:** <https://discourse.elm-lang.org/t/how-to-use-elm-parser-to-parse-ints-followed-by-a-period-like-in-ip-addresses/2829>\
**Category:** Learn\
**Created:** [December 27, 2018, 10:01am UTC](https://discourse.elm-lang.org/t/how-to-use-elm-parser-to-parse-ints-followed-by-a-period-like-in-ip-addresses/2829 "2018-12-27T10:01:42Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![petergao](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/petergao/32/1657_2.png) [@petergao](https://discourse.elm-lang.org/u/petergao)\
**Post date:** [December 27, 2018, 10:01am UTC](https://discourse.elm-lang.org/t/how-to-use-elm-parser-to-parse-ints-followed-by-a-period-like-in-ip-addresses/2829/1 "2018-12-27T10:01:42Z")

</div>

The parser I’m struggling to make work is this snippet:

```auto
parseIP : Parser IPAddress
parseIP =
  succeed IPAddress
    |= int
    |. symbol "."
    |= int
    |. symbol "."
    |= int
    |. symbol "."
    |= int

```

This parser looks reasonable on first blush, but the parser fails as `|= int` complains that there’s a period following the number and returns the `ExpectingInt` error. This is problematic in my use case as each component of an IP Address is an int, but also it’s delimited by a period.

I tried to wrap my head around the [elm/parser](https://package.elm-lang.org/packages/elm/parser/latest/Parser) docs, including using the [number](https://package.elm-lang.org/packages/elm/parser/latest/Parser#number) API to no avail. I’m pretty much stumped at this point on how to return an `int` from the parser when that `int` is followed by a `.` ☹.

Here’s an Ellie-app demonstrating my (not working with period & working with comma) parsers in action:  
[https://ellie-app.com/4h3ffMB25DHa1](https://ellie-app.com/4h3ffMB25DHa1)

---

<div class="post-metadata">

**Author:** ![malaire](https://avatars.discourse-cdn.com/v4/letter/m/b782af/32.png) [@malaire](https://discourse.elm-lang.org/u/malaire)\
**Post date:** [December 27, 2018, 10:59am UTC](https://discourse.elm-lang.org/t/how-to-use-elm-parser-to-parse-ints-followed-by-a-period-like-in-ip-addresses/2829/2 "2018-12-27T10:59:24Z")

</div>

In my code I decided to just replace `"."` with `":"` before parsing as a simple work-around.

---

<div class="post-metadata">

**Author:** ![dmy](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dmy/32/702_2.png) [@dmy](https://discourse.elm-lang.org/u/dmy)\
**Post date:** [December 27, 2018, 11:14am UTC](https://discourse.elm-lang.org/t/how-to-use-elm-parser-to-parse-ints-followed-by-a-period-like-in-ip-addresses/2829/3 "2018-12-27T11:14:45Z")

</div>

Look at [getChompedString](https://package.elm-lang.org/packages/elm/parser/latest/Parser#getChompedString) comment:

> Sometimes parsers like `int` or `variable` cannot do exactly what you need. The “chomping” family of functions is meant for that case!

So I would use `getChompedString`, `chompWhile` and `andThen` to parse and validate each part:

```auto
type alias IPv4 =
    { a : Int
    , b : Int
    , c : Int
    , d : Int
    , mask : Int
    }

segment : Parser Int
segment =
    getChompedString (chompWhile Char.isDigit)
        |> andThen checkSegment

checkSegment : String -> Parser Int
checkSegment str =
    case String.toInt str of
        Just n ->
            if n >= 0 && n <= 255 then
                succeed n

            else
                problem "invalid segment value"

        Nothing ->
            problem "segment is not a number"

mask : Parser Int
mask =
    getChompedString (chompWhile Char.isDigit)
        |> andThen checkMask

checkMask : String -> Parser Int
checkMask str =
    case String.toInt str of
        Just n ->
            if n >= 0 && n <= 32 then
                succeed n

            else
                problem "invalid subnet mask"

        Nothing ->
            problem "subnet mask is not a number"

ipv4 : Parser IPv4
ipv4 =
    succeed IPv4
        |= segment
        |. symbol "."
        |= segment
        |. symbol "."
        |= segment
        |. symbol "."
        |= segment
        |. symbol "/"
        |= mask

```

This way, you are also sure that a parsed IPv4 is valid:

[https://ellie-app.com/4h5PrzTLJDBa1](https://ellie-app.com/4h5PrzTLJDBa1)

* * *

You could also define an `intRange` parser to factorize some code:

```auto
intRange : Int -> Int -> Parser Int
intRange from to =
    getChompedString (chompWhile Char.isDigit)
        |> andThen (checkRange from to)

checkRange : Int -> Int -> String -> Parser Int
checkRange from to str =
    case String.toInt str of
        Just n ->
            if n >= from && n <= to then
                succeed n

            else
                rangeProblem from to

        Nothing ->
            rangeProblem from to

rangeProblem : Int -> Int -> Parser a
rangeProblem from to =
    problem <|
        String.join " "
            [ "expected a number between"
            , String.fromInt from
            , "and"
            , String.fromInt to
            ]

ipv4 : Parser IPv4
ipv4 =
    succeed IPv4
        |= intRange 0 255
        |. symbol "."
        |= intRange 0 255
        |. symbol "."
        |= intRange 0 255
        |. symbol "."
        |= intRange 0 255
        |. symbol "/"
        |= intRange 0 32

```

[https://ellie-app.com/4h5VXKJSyDpa1](https://ellie-app.com/4h5VXKJSyDpa1)

---

<div class="post-metadata">

**Author:** ![xilnocas](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/xilnocas/32/1336_2.png) [@xilnocas](https://discourse.elm-lang.org/u/xilnocas)\
**Post date:** [December 27, 2018, 5:52pm UTC](https://discourse.elm-lang.org/t/how-to-use-elm-parser-to-parse-ints-followed-by-a-period-like-in-ip-addresses/2829/4 "2018-12-27T17:52:15Z")

</div>

I ran into the same exact thing a couple weeks ago, trying to parse IP addresses and getting the unexpected behavior from the `int` parser. There’s [an issue on `elm/parser`](https://github.com/elm/parser/issues/14) about it too.

I personally think this is a bug, but I haven’t really thought through the implications of trying to fix it.

---

<div class="post-metadata">

**Author:** ![petergao](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/petergao/32/1657_2.png) [@petergao](https://discourse.elm-lang.org/u/petergao)\
**Post date:** [December 29, 2018, 11:56pm UTC](https://discourse.elm-lang.org/t/how-to-use-elm-parser-to-parse-ints-followed-by-a-period-like-in-ip-addresses/2829/5 "2018-12-29T23:56:01Z")

</div>

Thank you @dmy! Breaking it up like that was exactly what I needed to understand how Parsers in Elm work 😊!

I made a final modification based on your code to allow both IPv4 + Mask and only IPv4 by using `oneOf`:

```elm
ipv4 : Parser IPv4
ipv4 =
    succeed IPv4
        |= intRange 0 255
        |. symbol "."
        |= intRange 0 255
        |. symbol "."
        |= intRange 0 255
        |. symbol "."
        |= intRange 0 255
        |= oneOf
            [ map (\_ -> 32) end
            , succeed identity
                |. symbol "/"
                |= intRange 0 32
            ]

```

[https://ellie-app.com/4jcMBV2f47xa1](https://ellie-app.com/4jcMBV2f47xa1)

---

<div class="post-metadata">

**Author:** ![dmy](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dmy/32/702_2.png) [@dmy](https://discourse.elm-lang.org/u/dmy)\
**Post date:** [December 30, 2018, 9:49am UTC](https://discourse.elm-lang.org/t/how-to-use-elm-parser-to-parse-ints-followed-by-a-period-like-in-ip-addresses/2829/6 "2018-12-30T09:49:33Z")

</div>

> [@petergao](#):
>
> ```auto
> |= oneOf
> [ map (\_ -> 32) end
> , succeed identity
> |. symbol "/"
> |= intRange 0 32
> ]
> 
> ```

Note that the first branch of your `oneOf` requires the end of the string, preventing other parsers after, but the second does not, which seems inconsistent.

You may want instead something like:

```auto
        |= oneOf
            [ succeed identity
                |. symbol "/"
                |= intRange 0 32
            , succeed 32
            ]

```

[https://ellie-app.com/4jpNLQDqJ5Ra1](https://ellie-app.com/4jpNLQDqJ5Ra1)

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)\
**Post date:** [January 9, 2019, 9:49am UTC](https://discourse.elm-lang.org/t/how-to-use-elm-parser-to-parse-ints-followed-by-a-period-like-in-ip-addresses/2829/7 "2019-01-09T09:49:36Z")

</div>

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