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

How to ignore arbitrary tokens using parsec?

我想用秒差距替换 sedawk。例如,从 unknown structure but containing the number 42 and maybe some other stuff.

这样的字符串中提取数字

我运行变成了"unexpected end of input"。我正在寻找非贪婪 .*([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")

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

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

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

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

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

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

parser :: RE Char Int
parser = do
    _ <- few 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

如果您想执行实际的分词(例如跳过 foo93bar 中的 93),请查看 lexer-applicative,一个基于 regex-applicative 的分词器。

用解析器替换 sedawk 是什么 replace-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"
]