使用Parsec对引用字符串进行解析

时间:2014-06-08 12:47:58

标签: parsing haskell parsec

我想解析这样的输入字符串:"this is \"test \" message \"sample\" text"

现在,我编写了一个解析器来解析单个文本而没有任何引号:

parseString :: Parser String
parseString = do
  char '"'
  x <- (many $ noneOf "\"")
  char '"'
  return x

这解析了这样的简单字符串:"test message"

然后我为引用的字符串写了一个解析器:

quotedString :: Parser String
quotedString = do
  initial <- string "\\\""
  x <- many $ noneOf "\\\"" 
  end <- string "\\\""
  return $ initial ++ x ++ end

这个解析器的字符串如下:\"test message\"

有没有办法可以将两个解析器结合起来,以便获得我想要的目标?究竟什么是解决这个问题的方法?

6 个答案:

答案 0 :(得分:20)

这就是我要做的事情:

escape :: Parser String
escape = do
    d <- char '\\'
    c <- oneOf "\\\"0nrvtbf" -- all the characters which can be escaped
    return [d, c]

nonEscape :: Parser Char
nonEscape = noneOf "\\\"\0\n\r\v\t\b\f"

character :: Parser String
character = fmap return nonEscape <|> escape

parseString :: Parser String
parseString = do
    char '"'
    strings <- many character
    char '"'
    return $ concat strings

现在您需要做的就是调用它:

parse parseString "test" "\"this is \\\"test \\\" message \\\"sample\\\" text\""

Parser组合器起初有点难以理解,但是一旦掌握了它,它们就比编写BNF语法更容易。

答案 1 :(得分:2)

quotedString = do
    char '"'
    x <- many (noneOf "\"" <|> (char '\\' >> char '\"'))
    char '"'
    return x

我相信,这应该有用。

答案 2 :(得分:1)

我想解析引用的字符串并删除在解析步骤中用于转义的任何反斜杠。在我的简单语言中,唯一可以逃避的字符是双引号和反斜杠。这是我的解决方案:

quotedString = do
  string <- between (char '"') (char '"') (many quotedStringChar)
  return string
  where
    quotedStringChar = escapedChar <|> normalChar
    escapedChar = (char '\\') *> (oneOf ['\\', '"'])
    normalChar = noneOf "\""

答案 3 :(得分:1)

如果有人正在寻找更开箱即用的解决方案,this就是这样。以下是正确导入的完整示例:

$:

答案 4 :(得分:0)

我更喜欢以下内容,因为它更容易阅读:

quotedString :: Parser String
quotedString = do
    a <- string "\""
    b <- concat <$> many quotedChar
    c <- string "\""
    -- return (a ++ b ++ c) -- if you want to preserve the quotes
    return b
    where quotedChar = try (string "\\\\")
                   <|> try (string "\\\"")
                   <|> ((noneOf "\"\n") >>= \x -> return [x] )

Aadit的解决方案可能更快,因为它不使用try,但可能更难阅读。

请注意,它与Aadit的解决方案不同。我的解决方案忽略了字符串中的转义内容,实际上只关心\"\\

例如,假设您在字符串中有一个制表符。 我的解决方案成功地将"\"\t\""解析为Right "\t"。 Aadit的解决方案说unexpected "\t" expecting "\\" or "\""

另请注意,Aadit的解决方案仅接受有效的&#39;逃脱。例如,它拒绝"\"\\a\""\a不是有效的转义序列(根据man ascii,它代表系统钟并且有效)。我的解决方案只返回Right "\\a"

所以我们有两个不同的用例。

  • 我的解决方案:解析引用的字符串,其中包含可能已转义的引号并转义转义

  • Aadit的解决方案:使用有效转义序列解析带引号的字符串,其中有效转义符为"\\\"\0\n\r\v\t\b\f"

答案 5 :(得分:0)

详细介绍@Priyatham的回复

s