So I’d use elm/parser for this.
That 19.000200.00
is a bit of a killer at the moment - has me stumped. Lets assume there is a delimiting space between those two floats for now:
import Parser exposing ((|.), (|=), Parser, chompIf, end, float, getChompedString, keyword, lineComment, oneOf, spaces, succeed, symbol)
type Record
= Hello
| Goodbye
{-| Parsed information for each row.
Not sure what your floats are for, so these are of course just dummy names.
-}
type alias Data =
{ header : Record
, first : Float
, second : Float
, third : Float
, trailChar : Maybe String
, finalChar : String
}
{-| This guy does the actual work.
-}
scanner : Parser Data
scanner =
succeed Data
|= header
|. spaces
|= setWidthFloat
|. spaces
|= setWidthFloat
|. spaces
|= setWidthFloat
|= oneOf
[ succeed Just
|= charString
|. spaces
, succeed Nothing
|. spaces
]
|= charString
|. spaces
|. endRow
{-| Convert the initial string into a record type.
-}
header : Parser Record
header =
oneOf
[ succeed Hello
|. keyword "HELLO"
, succeed Goodbye
|. keyword "GOODBYE"
]
{-| Not sure if you have comments in your data like you've
shown here, but if so, you can ignore them like this.
Otherwise you can just use `|. end` in the `scanner` function.
-}
endRow : Parser ()
endRow =
oneOf
[ end
, lineComment "--"
]
{-| Works on the single character portion at the end.
Assumes that these will always be uppercase ASCII values.
-}
charString : Parser String
charString =
getChompedString <| chompIf Char.isUpper
{-| A custom float parser since we need to separate those two
values without delimiters. (Not implemented here, this just captures the negative symbol)
-}
setWidthFloat : Parser Float
setWidthFloat =
oneOf
[ succeed negate
|. symbol "-"
|= float
, float
]
Running the parser here will get you a Data
record for the row:
> Parser.run scanner "HELLO 19.000 200.000 -1.000A C -- Real data format"
Ok { finalChar = "C", first = 19, header = Hello, second = 200, third = -1, trailChar = Just "A" }
: Result (List Parser.DeadEnd) Data
To get around the 19.000200.000
issue, I’ve got to this point:
floatString : Parser String
floatString =
getChompedString <|
succeed ()
|. Parser.chompWhile (\c -> Char.isDigit c)
|. symbol "."
|. chompIf Char.isDigit
|. chompIf Char.isDigit
|. chompIf Char.isDigit
Which captures the correct information, but has a String
type. I haven’t been able to figure out how to do this AND convert the string to a Float
at the same time. Perhaps someone else can see a way to do that?
If so, then setWidthFloat
could be altered so use floatString
instead of float
, and the |. spaces
between the first and second float captures in scanner
can be removed. This should be everything.