2012-10-15 12 views
10
readFile "file.html" 
"start of the file... *** Exception: file.html: hGetContents: invalid argument (invalid code page byte sequence) 

È un file UTF-8 creato con notepad ++ ... come posso leggere il file in haskell?haskell - sequenza di codici pagina codici non valida

+0

Puoi pubblicare un dump esadecimale di un file minimale che mostra questo errore per te? Non riesco a duplicare il tuo errore. – ghoti

+1

Usa questo carattere: 'č' –

+0

Qual è il tuo locale? È un utf-8 o qualcosa di simile a ucs2ish (Notepad ++ suggerisce Windows)? –

risposta

12

Per impostazione predefinita, i file vengono letti nelle impostazioni internazionali del sistema, quindi se si dispone di un file che utilizza una codifica non standard, è necessario impostare personalmente la codifica dell'handle del file.

foo = do 
    handle <- openFile "file.html" ReadMode 
    hSetEncoding handle utf8_bom 
    contents <- hGetContents handle 
    doSomethingWithContents 
    hClose handle 

dovrebbe iniziare. Si noti che questo non contiene la gestione degli errori, il modo migliore sarebbe quindi

import Control.Exception -- for bracket 

foo = bracket 
     (openFile "file.html" ReadMode >>= \h -> hSetEncoding h utf8_bom >> return h) 
     hClose 
     (\h -> hGetContents h >>= doSomething) 

o

foo = withFile "file.html" ReadMode $ 
     \h -> do hSetEncoding h utf8_bom 
       contents <- hGetContents h 
       doSomethingWith contents 
+0

Mi è venuta in mente qualcosa di simile (come il tuo esempio' foo', anche se non sapevo di '_bom' ..). È possibile eseguire il calcolo all'esterno, come nel modo in cui lo faccio con 'readFile'? l'esempio di 'foo' funziona se non uso la riga' hClose' (ed è OK per il mio programma di giocattoli, ma vorrei sapere la "strada giusta" .. devo restituire qualcosa come 'IO (String, Handle) '?) –

+0

È un po 'difficile, se hai bisogno che il tuo file venga letto pigramente. 'HClose' chiude il file quando ritorna il calcolo, ciò può accadere prima che venga letto qualcosa del file. Quindi se si può avere l'intero file in memoria in una sola volta, facendo un semplice '' contenuto di lunghezza 'seq' return contents'' forza la lettura dell'intero file e si può eseguire l'elaborazione all'esterno. Altrimenti, probabilmente sarebbe meglio leggere il file come 'ByteString 'pigro e convertirlo da (usando' Data.ByteString.Lazy.UTF8.toString' dal pacchetto 'utf8-string'). –

+0

Non vedo come 'ByteString' aiuti/faciliti le cose (anche se sono un principiante) ..' readFile' è pigro, giusto? Quindi come chiude il file? Controlla che sia stato letto l'ultimo carattere? Potrei imitare il suo comportamento in qualche modo? –

1

Secondo this site, i vostri 6 byte decodificare come segue:

EF BB BF -> ZERO WIDTH NO-BREAK SPACE (i.e. the BOM, although its not needed in UTF-8 
C4 8D -> LATIN SMALL LETTER C WITH CARON (what you said) 
0D  -> CARRIAGE RETURN (CR) 

Quindi è un sequenza UTF-8 legale.

Tuttavia, le funzioni di Preludio standard hanno originariamente fatto solo ASCII. Non so cosa fanno ora, ma vedi questa domanda How does GHC/Haskell decide what character encoding it's going to decode/encode from/to? per qualche altra idea. Quindi utilizzare http://hackage.haskell.org/package/utf8-string anziché le funzioni di preludio.