我尝试这样做:
解析表格中的文字:
一些文字#{0,0,0}一些文字#{0,0,0}#{0,0,0}更多文字#{0,0,0}
进入一些数据结构列表:
[Inside“Some Text”,Outside(0,0,0),Inside“some text”,Outside(0,0,0),Outside(0,0,0),Inside“more text”,Outside (0,0,0)]
所以这些#{a,b,c} -bits应该变成与文本其余部分不同的东西。
我有这段代码:
module ParsecTest where
import Text.ParserCombinators.Parsec
import Monad
type Reference = (Int, Int, Int)
data Transc = Inside String | Outside Reference
deriving (Show)
text :: Parser Transc
text = do
x <- manyTill anyChar ((lookAhead reference) <|> (eof >> return (Inside "")));
return (Inside x)
transc = reference <|> text
alot :: Parser [Transc]
alot = do
manyTill transc eof
reference :: Parser Transc
reference = try (do{ char '#';
char '{';
a <- number;
char ',';
b <- number;
char ',';
c <- number;
char '}';
return (Outside (a,b,c)) })
number :: Parser Int
number = do{ x <- many1 digit;
return (read x) }
这可以按预期工作。您可以通过键入
在ghci中进行测试parseTest alot“Some Text#{0,0,0} some text#{0,0,0}#{0,0,0} more text#{0,0,0}”
但我觉得这不好。
1)使用lookAhead
对我的问题真的有用吗?
2)return (Inside "")
是一个丑陋的黑客吗?
3)通常是否有更简洁/更聪明的方法来实现同样的目标?
答案 0 :(得分:5)
1)我认为您需要lookAhead
,因为您需要该解析的结果。通过使用Parser (Transc,Maybe Transc)
来指示Inside
以及Outside
之后的可选项,可以避免运行该解析器两次。如果性能是一个问题,那么这是值得的。
2)是的。
3)Applicative
s
number2 :: Parser Int
number2 = read <$> many1 digit
text2 :: Parser Transc
text2 = (Inside .) . (:)
<$> anyChar
<*> manyTill anyChar (try (lookAhead reference2) *> pure () <|> eof)
reference2 :: Parser Transc
reference2 = ((Outside .) .) . (,,)
<$> (string "#{" *> number2 <* char ',')
<*> number2
<*> (char ',' *> number2 <* char '}')
transc2 = reference2 <|> text2
alot2 = many transc2
您可能希望使用reference2
等帮助程序重写aux x y z = Outside (x,y,z)
的开头。
编辑:更改text
以处理不以Outside
结尾的输入。