我想用Parsec替换sed
和awk
。例如,从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")
答案 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)
用解析器替换sed
和awk
是
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"
]
答案 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