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

Sib*_*ibi 5 parsing haskell parsec

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

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

parseString :: Parser String
parseString = do
  char '"'
  x <- (many $ noneOf "\"")
  char '"'
  return x
Run Code Online (Sandbox Code Playgroud)

这解析简单的字符串,如下所示: "test message"

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

quotedString :: Parser String
quotedString = do
  initial <- string "\\\""
  x <- many $ noneOf "\\\"" 
  end <- string "\\\""
  return $ initial ++ x ++ end
Run Code Online (Sandbox Code Playgroud)

这个解析器的字符串是这样的: \"test message\"

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

Aad*_*hah 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
Run Code Online (Sandbox Code Playgroud)

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

parse parseString "test" "\"this is \\\"test \\\" message \\\"sample\\\" text\""
Run Code Online (Sandbox Code Playgroud)

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

  • 难道 `nonEscape` 不应该只是 `noneOf "\\\""`,以允许特殊字符按字面出现,同时可能大大加快处理速度? (2认同)
  • @dfeuer 在 7 个特殊字符(即`[0nrvtbf]`)中,无法在键盘上正常输入空字符。它必须复制粘贴。换行符 `\n` 和 `\r` 不允许出现在 Haskell 字符串中(或者大多数编程语言)。某些语言(如 JavaScript)允许转义换行符,但 Haskell 不允许。垂直制表符和换页在编程中几乎不使用。空格(空格和换行符除外)不应该被忽视。这足以禁止所有这些特殊字符作为字符串中的文字。它也可以作为一个很好的解释 (2认同)
  • 由于解析器组合器的实现方式,无论`noneEscape =“ \\\” \ 0 \ n \ r \ v \ t \ b \ f“`还是`nonEscape =” \\\“”都没有区别`。仍然需要相同的时间。这是因为解析器是使用查找表数组来实现的,该查找表确定了解析器的下一个状态。想想确定性下推自动机。对于给定的状态,您具有将每个输入符号映射到新状态的向量。因此,无论输入什么符号,都只需要进行一次查找就可以进入新状态。`noneOf`组合器产生一个解析器,解析器的深度只有一个级别。快速。 (2认同)