7

エスケープ文字を含む可能性のある文字列を解析しようとしています。例を次に示します。

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 が提供する効率的な文字列処理のための関数を使用して、上記のようなエスケープで文字列を解析する方法はありますか? のようstringscan、、、、runScanner_takeWhile...

のようなものを解析すると、"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
4

1 に答える 1

4

いくつかのエスケープ コードを書くことは可能でattoparsecあり、text完全に非常に簡単です。すでにパーサーを使用していることがわかります。

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"
于 2016-02-09T21:48:01.180 に答える