Parsing 如何从单词列表中生成Haskell解析器?
我是Haskell初学者,使用ATOPASSERC在文本中查找一些颜色表达式。我希望能够匹配,例如,文本中的“浅蓝绿色”和“浅蓝绿色”。当然,我需要一个这样的字符串的广义解。所以我一直在想Parsing 如何从单词列表中生成Haskell解析器?,parsing,haskell,attoparsec,Parsing,Haskell,Attoparsec,我是Haskell初学者,使用ATOPASSERC在文本中查找一些颜色表达式。我希望能够匹配,例如,文本中的“浅蓝绿色”和“浅蓝绿色”。当然,我需要一个这样的字符串的广义解。所以我一直在想 "light" >> sep >> "blue" >> sep >> "green" where sep = inClass "\n\r- " stack runhaskell ThisFile.hs --package attoparsec replac
"light" >> sep >> "blue" >> sep >> "green"
where sep = inClass "\n\r- "
stack runhaskell ThisFile.hs --package attoparsec replace-attoparsec text
换句话说,我想我需要一种方法将>sep>>
插入到单词列表中。比如:
import qualified Data.Text as T
import Data.Attoparsec.Text
-- | Makes a parser from a list of words, accepting
-- spaces, newlines, and hyphens as separators.
wordListParser :: [T.Text] -> Parser
wordListParser wordList = -- Some magic here
或者也许我想的完全是错误的,还有更简单的方法吗
编辑:这个最小的不起作用的示例感觉就快到了:
{-# LANGUAGE OverloadedStrings #-}
import Replace.Attoparsec.Text
import Data.Attoparsec.Text as AT
import qualified Data.Text as T
import Control.Applicative (empty)
wordListParser :: [T.Text] -> Parser T.Text
wordListParser (w:ws) = string w >> satisfy (inClass " -") >> wordListParser ws
wordListParser [w] = string w
wordListParser [] = empty -- or whatever the empty parser is
main :: IO ()
main = parseTest (wordListParser (T.words "light green blue")) "light green-blue"
我想可以用这样的东西运行
"light" >> sep >> "blue" >> sep >> "green"
where sep = inClass "\n\r- "
stack runhaskell ThisFile.hs --package attoparsec replace-attoparsec text
我不熟悉attoparsec,但您可以使用递归解决方案:
wordListParser::[T.Text]->Parser
wordListParser[]=空
wordListParser[w]=文本w
wordListParser(w:ws)=文本w>>包含类“\n\r-”>>wordListParser ws
假设您有颜色的数据类型,我会这样做;如果你没有,就用它代替你正在使用的东西。函数parsecolorgen
接受任何空格分隔的Text
,并生成接受颜色的解析器,其中每个单词由一个或多个合法分隔符分隔
import Prelude hiding (concat, words)
import Control.Applicative ((<|>))
import Data.Attoparsec.Text
import Data.List (intersperse)
import Data.Text (concat, pack, singleton, Text, words)
data Colour = LightBlue | DarkBlue | VibrantRed deriving Show
parseColourGen :: Text -> Parser [Text]
parseColourGen = sequence . intersperse (mempty <$ many1 legalSep) .
fmap string . words
parseColour :: [(Text, Colour)] -> Parser Colour
parseColour = foldl1 (<|>) . fmap (\(text, colour) ->
colour <$ parseColourGen text)
legalSep :: Parser Text
legalSep = singleton <$> satisfy (inClass "\n\r- ")
通过这种方式,您可以在一个位置配置所有颜色及其对应的颜色名称,然后可以像这样运行解析器:
> parse (parseColour wordList) $ pack "vibrant-red"
Done "" VibrantRed
编辑
在对你的问题进行编辑之后,我想我更了解你想要什么。FWIW,我仍然更喜欢上面的解决方案,但下面是如何修复最后一段代码:
(w:ws)
和[w]
是重叠的,因此如果您希望运行时捕获单元素模式,必须将其放在顶部a>>b
表示“运行操作a
,放弃其结果,然后运行操作b
并使用该结果”。这就是为什么解析器(使用上面的修复程序)将输出Done”““blue”
。解决这个问题的一个简单方法是使用do
表示法绑定所有三个计算的结果,并返回它们的串联wordListParser :: [Text] -> Parser Text
wordListParser [w] = string w
wordListParser (w:ws) = do
a <- string w
b <- satisfy (inClass " -")
c <- wordListParser ws
return (a `append` (singleton b) `append` c) -- singleton :: Char -> Text
wordListParser [] = empty
wordListParser::[Text]->解析器文本
wordListParser[w]=字符串w
wordListParser(w:ws)=do
a知道在哪里可以找到空解析器吗?我尝试了Parser T.empty
和T.empty
,但没有接近太多。@Jonathan第一个结果是正确的。这只是产生了一个部分解析,并没有完成。@Jonathan“它产生了一个部分解析”是什么意思?你能给出一个它不起作用的例子吗?我刚刚在我的问题中添加了一个例子,显示了它返回Partial\u
的位置。你希望解析的结果是浅蓝绿色
吗?你可能想使用sepBy1
和choice
。结果应该是t.Text。我将如何使用seppy1
?我已经用您问题中的编辑更新了我的答案。