用 Haskell 解析引号
Parse between quotes with Haskell
要求取自 DOT language specification,更准确地说,我正在尝试解析 [ID]
属性,例如,
any double-quoted string ("...") possibly containing escaped quotes (\")1;
下面应该是一个最小的例子。
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Text.Megaparsec
import Text.Megaparsec.Char
import Data.Void
import Data.Char
import Data.Text hiding ( map
, all
, concat
)
type Parser = Parsec Void Text
escape :: Parser String
escape = do
d <- char '\'
c <- oneOf ['\', '\"', '0', 'n', 'r', 'v', 't', 'b', 'f']
return [d, c]
nonEscape :: Parser Char
nonEscape = noneOf ['\', '\"', '[=11=]', '\n', '\r', '\v', '\t', '\b', '\f']
identPQuoted :: Parser String
identPQuoted =
let inner = fmap return (try nonEscape) <|> escape
in do
char '"'
strings <- many inner
char '"'
return $ concat strings
identP :: Parser Text
identP = identPQuoted >>= return . pack
main = parseTest identP "\"foo \"bar\""
虽然我想要 foo "bar
,但上面的代码第二次失败了 returns "foo "
我不明白为什么。我以为 megaparsec
会重复应用 inner
直到它解析最后的 "
。但它只是重复应用 nonEscape
解析器,第一次失败,它使用 escape
,然后它似乎跳过了内部字符串的其余部分,只是转到最后的引号。
您的输入文本是 "foo "bar"
,其中不包含任何转义引号。它被解析为"foo "
的完整ID(后跟bar"
,被忽略)。
如果您想确保您的解析器使用所有可用的输入,您可以使用
parseTest (identP <* eof) "..."
如果您想向解析器提供带有转义引号的 ID,就像这样...
"foo \"bar"
... 然后你需要转义所有特殊字符以将它们嵌入 Haskell 源代码:
main = parseTest identP "\"foo \\"bar\""
\"
表示文字 "
并且 \
表示文字 \
.
要求取自 DOT language specification,更准确地说,我正在尝试解析 [ID]
属性,例如,
any double-quoted string ("...") possibly containing escaped quotes (\")1;
下面应该是一个最小的例子。
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Text.Megaparsec
import Text.Megaparsec.Char
import Data.Void
import Data.Char
import Data.Text hiding ( map
, all
, concat
)
type Parser = Parsec Void Text
escape :: Parser String
escape = do
d <- char '\'
c <- oneOf ['\', '\"', '0', 'n', 'r', 'v', 't', 'b', 'f']
return [d, c]
nonEscape :: Parser Char
nonEscape = noneOf ['\', '\"', '[=11=]', '\n', '\r', '\v', '\t', '\b', '\f']
identPQuoted :: Parser String
identPQuoted =
let inner = fmap return (try nonEscape) <|> escape
in do
char '"'
strings <- many inner
char '"'
return $ concat strings
identP :: Parser Text
identP = identPQuoted >>= return . pack
main = parseTest identP "\"foo \"bar\""
虽然我想要 foo "bar
"foo "
我不明白为什么。我以为 megaparsec
会重复应用 inner
直到它解析最后的 "
。但它只是重复应用 nonEscape
解析器,第一次失败,它使用 escape
,然后它似乎跳过了内部字符串的其余部分,只是转到最后的引号。
您的输入文本是 "foo "bar"
,其中不包含任何转义引号。它被解析为"foo "
的完整ID(后跟bar"
,被忽略)。
如果您想确保您的解析器使用所有可用的输入,您可以使用
parseTest (identP <* eof) "..."
如果您想向解析器提供带有转义引号的 ID,就像这样...
"foo \"bar"
... 然后你需要转义所有特殊字符以将它们嵌入 Haskell 源代码:
main = parseTest identP "\"foo \\"bar\""
\"
表示文字 "
并且 \
表示文字 \
.