如何使用 Parsec (Haskell) 根据密钥标记将值插入字符串?

How can I interpolate values into a string based on a key token using Parsec (Haskell)?

我是解析领域的新手,有一个看似相当简单的问题:

我有一个长字符串,由 Chunk 的普通文本和 Key 编码的 <<key-label>>.

组成
data Merge a = Chunk a
             | Key a
  deriving (Show)

key :: Parser (Merge String)
key = Key <$> between (string "<<") (string ">>") (many1 letter)

chunk :: Parser (Merge String)
chunk = Chunk <$> many1 anyChar

prose = many1 $ key <|> chunk

ex = parseTest prose "hi <<x>> ! Do you like <<y>>?"

-- Returns: 
-- [Chunk "hi <<x>> ! Do you like <<y>>?"]

-- I'd like:
-- [Chunk "hi ", Key "x", Chunk " !", ...]

我想用值替换这些键,但我可以解决这个问题,如果我可以将字符串解析为我的标记,IE String -> [Merge]

我已经深入到 lexing/parsing 的无限深度,虽然我希望最终能学会所有这些,但现在有解决这个问题的指导吗?

这是我尝试的最简单的实例化,尽管我尝试过单独传递数据,包括单独的 lexing/parsing 步骤,并且我 喜欢 使用parsec 而不是更具体的插值库。

您可以使用 notFollowedBy 表示您希望一个块包含一个 字符,只要它不是键。 notFollowedBy不消费 输入所以 prose 仍会继续将密钥再次解析为它自己的项目。

chunk = Chunk <$> many1 (notFollowedBy key >> anyChar)

这将允许像 aaa<<bbbbbb 这样的东西被解析为一个块, 一直走到文件末尾,没有找到结束符 >>,决定它一定不是钥匙,因此它可以 成为大块的一部分。

如果您希望 << 始终作为密钥的开头并且在以下情况下失败 它没有关闭,禁止来自块的 <<:

chunk = Chunk <$> many1 (notFollowedBy (string "<<") >> anyChar)

replace-megaparsec 是一个用于使用解析器进行搜索和替换的库。这 搜索和替换功能是 streamEdit.

import Replace.Megaparsec
import Text.Megaparsec
import Text.Megaparsec.Char
import Data.Char

key = between (string "<<") (string ">>") (many letterChar) :: Parsec Void String String
editor k = "Key " ++ (fmap toUpper k)

streamEdit key editor "hi <<x>> ! Do you like <<y>>?"
"hi Key X ! Do you like Key Y?"

你也可以用 sepCap parser combinator,其中 returns 等同于 [Merge] 的结构 您正在尝试构建。