blob: b378e96564d3318347a28b6151d85e553d6f82e4 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
module Parser
( TextWithNumber
, textWithNumber
, number
) where
import Control.Alt ((<|>))
import Data.Array as Array
import Data.Char as Char
import Data.Either (Either(Right))
import Data.Int as Int
import Data.Maybe (fromMaybe) as Maybe
import Data.Maybe (Maybe(Just, Nothing))
import Data.String.CodeUnits as String
import Prelude
import Text.Parsing.Parser (Parser)
import Text.Parsing.Parser (runParser) as Parser
import Text.Parsing.Parser.Combinators (optionMaybe) as Parser
import Text.Parsing.Parser.String (satisfy, anyChar, string, eof) as Parser
type TextWithNumber =
{ begin :: String
, number :: Number
, end :: String
}
textWithNumber :: String -> Maybe TextWithNumber
textWithNumber input =
case Parser.runParser input textWithNumberParser of
Right x -> Just x
_ -> Nothing
number :: String -> Maybe Number
number input =
case Parser.runParser input (numberParser <* Parser.eof) of
Right x -> Just x
_ -> Nothing
textWithNumberParser :: Parser String TextWithNumber
textWithNumberParser = do
begin <- String.fromCharArray <$> Array.many notDigit
num <- numberParser
end <- String.fromCharArray <$> Array.many Parser.anyChar
pure { begin: begin, number: num, end: end }
notDigit :: Parser String Char
notDigit = Parser.satisfy (not <<< isDigit)
numberParser :: Parser String Number
numberParser = do
whole <- numberFromIntArray <$> Array.some digit
decimal <- Parser.optionMaybe $ do
_ <- Parser.string "," <|> Parser.string "."
digits <- Array.some digit
let decimals = numberFromIntArray digits
pure $ Int.toNumber decimals / Int.toNumber (Int.pow 10 (Array.length digits))
pure (Int.toNumber whole + Maybe.fromMaybe 0.0 decimal)
numberFromIntArray :: Array Int -> Int
numberFromIntArray xs =
Array.range 0 (Array.length xs - 1)
# map (Int.pow 10)
# Array.reverse
# Array.zipWith (*) xs
# Array.foldl (+) 0
digit :: Parser String Int
digit = map (\c -> Char.toCharCode c - zeroCode) $ Parser.satisfy isDigit
isDigit :: Char -> Boolean
isDigit char =
let code = Char.toCharCode char
in code >= zeroCode && code <= zeroCode + 9
zeroCode :: Int
zeroCode = 48
|