如何使用parsec忽略任意标记?

时间:2018-06-15 19:53:53

标签: haskell parsec

我想用Parsec替换sedawk。例如,从unknown structure but containing the number 42 and maybe some other stuff等字符串中提取数字。

我遇到了“意外的输入结束”。我正在寻找相当于非贪婪的.*([0-9]+).*

module Main where

import Text.Parsec

parser :: Parsec String () Int
parser = do
    _ <- many anyToken
    x <- read <$> many1 digit
    _ <- many anyToken
    return x

main :: IO ()
main = interact (show . parse parser "STDIN")

3 个答案:

答案 0 :(得分:1)

这可以通过我的库regex-applicative轻松完成。它为您提供了组合器界面和您似乎想要的正则表达式的功能。

这是一个与您的示例最接近的工作版本:

{-# LANGUAGE ApplicativeDo #-}
import Text.Regex.Applicative
import Text.Regex.Applicative.Common (decimal)

parser :: RE Char Int
parser = do
    _ <- many anySym
    x <- decimal
    _ <- many anySym
    return x

main :: IO ()
main = interact (show . match parser)

这是一个更短的版本,使用findFirstInfix

import Text.Regex.Applicative
import Text.Regex.Applicative.Common (decimal)

main :: IO ()
main = interact (snd3 . findFirstInfix decimal)
  where snd3 (_, r, _) = r

如果您想要执行实际的标记化(例如,在93中跳过foo93bar),请查看lexer-applicative,一个基于正则表达式的标记生成器。

答案 1 :(得分:1)

用解析器替换sedawkreplace-megaparsec 图书馆就是一切。

从非结构化字符串中提取数字 sepCap 解析器组合器。

import Replace.Megaparsec
import Text.Megaparsec
import Text.Megaparsec.Char.Lexer

parseTest (sepCap (decimal :: Parsec Void String Int))
  $ "unknown structure but containing the number 42 and maybe some other stuff"
[ Left "unknown structure but containing the number "
, Right 42
, Left " and maybe some other stuff"
]

答案 2 :(得分:0)

这不起作用,因为anyToken接受并消费 - 正如其名称所示 - 任何令牌,包括数字。然后你应用它many次。因此,尝试使用第二个解析器读取数字必须失败。根本就没有任何令牌。

而是让你的第一个解析器接受任何不是数字的字符(使用模块isDigit中的Data.Char):

parser :: Parsec String () Int
parser = do
    _ <- many $ satisfy (not . isDigit)
    x <- read <$> many1 digit
    _ <- many anyToken
    return x