簡體   English   中英

Haskell:如何將“\\\\ 0”變成“\\ 0”?

[英]Haskell: How to get “\\0” into “\0”?

Haskell有許多使用\\轉義序列的字符串文字 例如\\n\\t\\NUL

如果我有字符串文字:

let s = "Newline: \\n Tab: \\t"

如何定義函數escape :: String -> String將上述字符串轉換為的字符串:

"Newline: \n Tab: \t"

與所有其他字符串文字轉義序列相同。

我可以使用Quasi Quoting和Template Haskell,但不知道如何使用它們來實現結果。 有什么指針嗎?


更新 :我剛剛找到了包含在Base庫中的Text.ParserCombinators.ReadP模塊。 它支持readLitChar :: ReadS Char函數,它可以實現我想要的功能,但我不知道如何使用ReadP模塊。 我嘗試了以下功能:

escape2 [] = []
escape2 xs = case readLitChar xs of
    [] -> []
    [(a, b)] -> a : escape2 b

但這可能不是使用ReadP模塊的正確方法。 任何人都可以提供一些指示嗎?

另一個更新 :謝謝大家。 我的最終功能如下。 不錯,我想。

import Text.ParserCombinators.ReadP
import Text.Read.Lex

escape xs 
    | []      <- r = []
    | [(a,_)] <- r = a
    where r = readP_to_S (manyTill lexChar eof) xs 

你不需要做任何事情。 輸入字符串文字時

let s = "Newline: \\n Tab: \\t"

你可以檢查它是你想要的:

Prelude> putStrLn s
Newline: \n Tab: \t
Prelude> length s
19

如果你只是問ghci的s值,你會得到別的東西,

Prelude> s
"Newline: \\n Tab: \\t"

顯然它正在你背后做一些逃避格式化,它也顯示引號。 如果你打電話給showprint你會得到其他答案:

Prelude> show s
"\"Newline: \\\\n Tab: \\\\t\""
Prelude> print s
"Newline: \\n Tab: \\t"

這是因為show用於序列化值,因此當您show一個字符串時,您不會獲得原始字符串,而是獲取一個可以解析為原始字符串的序列化字符串。 show s的結果實際上是由print s顯示print sprint定義為putStrLn . show )。 當你在ghci中show s ,你會得到一個更奇怪的答案; 這里ghci正在格式化由show序列化的字符。

tl; dr - 總是使用putStrLn來查看字符串在ghci中的值。

編輯 :我剛才意識到你想要轉換字面值

Newline: \n Tab: \t

進入實際的控制序列。 最簡單的方法是將其粘貼在引號中並使用read

Prelude> let s' = '"' : s ++ "\""
Prelude> read s' :: String
"Newline: \n Tab: \t"
Prelude> putStrLn (read s')
Newline: 
 Tab:   

編輯2 :使用readLitChar一個例子,這與Chris的答案非常接近,除了readLitChar

strParser :: ReadP String
strParser = do
  str <- many (readS_to_P readLitChar)
  eof
  return str

然后用readP_to_S運行它,它給你一個匹配的解析列表(不應該有多個匹配,但是可能沒有任何匹配,所以你應該檢查一個空列表。)

> putStrLn . fst . head $ readP_to_S strParser s
Newline:
Tab:    
>

詢問QQ和TH意味着您希望在編譯時進行此轉換。 對於簡單的String - > Something轉換,您可以使用GHC中的OverloadedString文字工具。

編輯2 :在Text.Read.Lex中使用公開的字符詞法分析器

module UnEscape where

import Data.String(IsString(fromString))
import Text.ParserCombinators.ReadP as P
import Text.Read.Lex as L

newtype UnEscape = UnEscape { unEscape :: String }

instance IsString UnEscape where
  fromString rawString = UnEscape lexed
    where lexer = do s <- P.many L.lexChar
                     eof
                     return s
          lexed = case P.readP_to_S lexer rawString of
                    ((answer,""):_) -> answer
                    _ -> error ("UnEscape could not process "++show rawString)

編輯1 :我現在有一個更好的UnEscape實例使用GHC的讀取:

instance IsString UnEscape where
  fromString rawString = UnEscape (read (quote rawString))
    where quote s = '"' : s ++ ['"']

例如:

module UnEscape where

import Data.String(IsString(fromString))

newtype UnEscape = UnEscape { unEscape :: String }

instance IsString UnEscape where
  fromString rawString = UnEscape (transform rawString)
    where transform [] = []
          transform ('\\':x:rest) = replace x : transform rest
          transform (y:rest) = y : transform rest
            -- also covers special case of backslash at end
          replace x = case x of
                        'n' -> '\n'
                        't' -> '\t'
                        unrecognized -> unrecognized

以上必須是與使用unEscape的模塊分開的模塊:

{-# LANGUAGE OverloadedStrings #-}
module Main where

import UnEscape(UnEscape(unEscape))

main = do
  let s = "Newline: \\n Tab: \\t"
      t = unEscape "Newline: \\n Tab: \\t"
  print s
  putStrLn s
  print t
  putStrLn t

這產生了

shell prompt$ ghci Main.hs 


GHCi, version 7.0.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package ffi-1.0 ... linking ... done.
[1 of 2] Compiling UnEscape         ( UnEscape.hs, interpreted )
[2 of 2] Compiling Main             ( Main.hs, interpreted )
Ok, modules loaded: Main, UnEscape.
*Main> main
"Newline: \\n Tab: \\t"
Newline: \n Tab: \t
"Newline: \n Tab: \t"
Newline: 
 Tab:   

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM