【问题标题】:Fast parsing of string that allows escaped characters?快速解析允许转义字符的字符串?
【发布时间】:2016-02-09 19:42:39
【问题描述】:

我正在尝试解析一个可以包含转义字符的字符串,这是一个示例:

import qualified Data.Text as T

exampleParser :: Parser T.Text
exampleParser = T.pack <$> many (char '\\' *> escaped <|> anyChar)
  where escaped = satisfy (\c -> c `elem` ['\\', '"', '[', ']'])

上面的解析器创建了一个String,然后将它打包到Text。有没有办法使用 attoparsec 提供的高效字符串处理函数来解析带有上述转义的字符串?喜欢stringscanrunScannertakeWhile...

解析"one \"two\" \[three\]" 之类的内容会产生one "two" [three]

更新

感谢@epsilonhalbe,我能够提出一个适合我需求的通用解决方案;请注意,以下函数不会查找匹配的转义字符,例如 [..]".."(..) 等;而且,如果它发现一个无效的转义字符,它会将\ 视为文字字符。

takeEscapedWhile :: (Char -> Bool) -> (Char -> Bool) -> Parser Text
takeEscapedWhile isEscapable while = do
  x <- normal
  xs <- many escaped
  return $ T.concat (x:xs)
  where normal = Atto.takeWhile (\c -> c /= '\\' && while c)
        escaped = do
          x <- (char '\\' *> satisfy isEscapable) <|> char '\\'
          xs <- normal
          return $ T.cons x xs

【问题讨论】:

    标签: parsing haskell parser-combinators attoparsec


    【解决方案1】:

    可以编写一些转义代码,attoparsectext - 总的来说非常简单 - 看到您已经使用过解析器

    import Data.Attoparsec.Text as AT
    import qualified Data.Text as T
    import Data.Text (Text)
    
    escaped, quoted, brackted :: Parser Text
    normal =  AT.takeWhile (/= '\\')
    escaped = do r <- normal
                 rs <- many escaped'
                 return $ T.concat $ r:rs
      where escaped' = do r1 <- normal
                          r2 <- quoted <|> brackted
                          return $ r1 <> r2
    
    quoted = do string "\\\""
                res <- normal
                string "\\\""
                return $ "\""<>res <>"\""
    
    brackted = do string "\\["
                  res <- normal
                  string "\\]"
                  return $ "["<>res<>"]"
    

    那么你就可以用它来解析下面的测试用例了

    Prelude >: MyModule
    Prelude MyModule> import Data.Attoparsec.Text as AT
    Prelude MyModule AT> import Data.Text.IO as TIO
    Prelude MyModule AT TIO>:set -XOverloadedStrings
    Prelude MyModule AT TIO> TIO.putStrLn $ parseOnly escaped "test"
    test
    Prelude MyModule AT TIO> TIO.putStrLn $ parseOnly escaped "\\\"test\\\""
    "test"
    Prelude MyModule AT TIO> TIO.putStrLn $ parseOnly escaped "\\[test\\]"
    [test]
    Prelude MyModule AT TIO> TIO.putStrLn $ parseOnly escaped "test \\\"test\\\" \\[test\\]"
    test "test" [test]
    

    请注意,您必须逃脱转义 - 这就是您看到 \\\" 而不是 \" 的原因

    另外,如果你只是解析它会打印出Text 转义的值,比如

    Right "test \"text\" [test]"
    

    最后一个例子。

    如果你解析一个文件,你会在文件中编写简单的转义文本。

    test.txt

    I \[like\] \"Haskell\"
    

    那么你可以

    Prelude MyModule AT TIO> file <- TIO.readFile "test.txt" 
    Prelude MyModule AT TIO> TIO.putStrLn $ parseOnly escaped file
    I [like] "Haskell"
    

    【讨论】:

    • 所需的代码让您思考是否值得以性能换取简单性
    猜你喜欢
    • 2023-02-22
    • 1970-01-01
    • 2020-03-26
    • 2020-02-28
    • 1970-01-01
    • 1970-01-01
    • 2011-03-11
    • 1970-01-01
    • 2016-09-19
    相关资源
    最近更新 更多