我是Haskell初学者,使用Attoparsec在文本中查找一些颜色表达式。例如,我希望能够在文本中匹配"浅蓝绿色"和"浅蓝绿色"。但是,当然,我需要为任何这样的字符串提供通用解决方案。所以我一直在想它会是这样的
"light" >> sep >> "blue" >> sep >> "green"
where sep = inClass "nr- "
换句话说,我认为我需要一种方法来将>> 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"
我认为可以用类似的东西运行
stack runhaskell ThisFile.hs --package attoparsec replace-attoparsec text
这就是我会做的,假设你的颜色有一个数据类型;如果你没有,只需用它代替你正在使用的。该函数parseColourGen
采用空格分隔的任何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 "nr- ")
然后,您可以将wordList
提供给解析器;但是,它需要是一个关联列表:
wordList :: [(Text, Colour)]
wordList = [("light blue", LightBlue), ("dark blue", DarkBlue), ("vibrant red", VibrantRed)]
这样,您可以在一个地方配置所有颜色及其相应的颜色名称,然后可以像这样运行解析器:
> 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
最后一件事:您当前的实现不会解析 Windows 换行符 (nr
(。我不知道您是否从分隔符中删除了n
和r
,但是如果您没有并且Windows文件对您来说是一种可能性,那么
我不熟悉attoparsec,但你可以使用递归解决方案:
wordListParser :: [T.Text] -> Parser
wordListParser [] = empty
wordListParser [w] = text w
wordListParser (w:ws) = text w >> inClass "nr- " >> wordListParser ws