我想解析这样的输入字符串:"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\"
有没有办法可以将两个解析器结合起来,以便获得我想要的目标?究竟什么是解决这个问题的方法?
答案 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