如何使用 Parsec 按特定字符串分隔字符串

How to use Parsec to separate a string by a specific string

我正在学习parsec,刚好遇到如下情况。我想通过特定的 StringString 分成 [String];例如,我得到 "abcSEPdef ,分隔符是 "SEP",所以,在解析之后,我应该得到一个 ["abc","def"]

我认为解析器应该看起来像 sepBy a_parser (string "SEP");但是,我不知道 a_parser 应该是什么样子。

找到 "SEP" 的否定,并让该解析器成为 parseNonSEP。 理论上保证parseNonSEP属于正则语言的范畴,因为正则语言在否定下是封闭的,应该有直接的方式来实现。

然后,

sepBy pareseNonSEP(字符串 "SEP")

会完成任务的。

好吧,我上面提到的是一个相当理论的方法:) 更多 parsec 风格的方法可能是在不实际消耗输入的情况下提前查看输入标记列表 and/or 使用回溯,例如 try、notFollowedBy、lookAhead。

http://hackage.haskell.org/package/parsec-3.1.9/docs/Text-Parsec-Combinator.html

使用 manyTill 几次即可:

uptoSEP = manyTill anyChar (eof <|> (string "SEP" >> return ()))

splitSEP = manyTill uptoSEP eof

例如:

ghci> parseTest splitSEP "abcSEPdefSEPxyz"
["abc","def","xyz"]

您需要启用 {-# LANGUAGE NoMonomorphismRestriction #-} pragma。

我终于找到了一种将 split 包合并到 parsec 中的方法:

module Sep where
import Text.ParserCombinators.Parsec
import qualified Data.List.Split  as DLS
mysep :: String -> Parser [String]
mysep sep = getInput >>= return . DLS.splitOn sep

replace-megaparsec 包有一个 sepCap 用于拆分字符串和捕获分隔的组合器。

import Replace.Megaparsec
import Text.Megaparsec

parseTest (sepCap (chunk "SEP" :: Parsec Void String String)) "abcSEPdef"
[Left "abc",Right "SEP",Left "def"]