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 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