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

Đó là tệp UTF-8 được tạo bằng notepad ++ ... làm cách nào để đọc tệp trong haskell?haskell - chuỗi byte trang mã không hợp lệ

+0

Bạn có thể đăng một kết xuất hex của tệp tối thiểu hiển thị lỗi này cho bạn không? Tôi không thể sao chép lỗi của bạn. – ghoti

+1

Sử dụng ký tự này: 'č' –

+0

Ngôn ngữ của bạn là gì? Nó là một utf-8 hoặc một cái gì đó ucs2ish (notepad ++ cho Windows)? –

Trả lời

12

Theo mặc định, tệp được đọc ở ngôn ngữ hệ thống, vì vậy nếu bạn có tệp bằng cách sử dụng mã hóa không chuẩn, bạn cần phải tự đặt mã hóa của tệp.

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

sẽ giúp bạn bắt đầu. Lưu ý rằng đây không chứa xử lý lỗi, cách tốt hơn sẽ do đó được

import Control.Exception -- for bracket 

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

hoặc

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

Tôi đã đưa ra một cái gì đó tương tự (ví dụ như' foo' của bạn, mặc dù tôi không biết về '_bom' ..). Có thể thực hiện tính toán bên ngoài, giống như cách tôi làm với 'readFile'? ví dụ 'foo' hoạt động nếu tôi không sử dụng dòng' hClose' (và nó là OK cho chương trình đồ chơi của tôi, nhưng muốn biết "đúng cách" .. tôi có phải trả về một cái gì đó như 'IO (String, Xử lý) '?) –

+0

Hơi khó, nếu bạn cần tập tin của bạn được đọc một cách lười biếng. 'HClose' đóng tệp khi tính toán trả về, có thể xảy ra trước khi bất kỳ tệp nào được đọc. Vì vậy, nếu bạn có thể có toàn bộ tập tin trong bộ nhớ cùng một lúc, làm một nội dung '' chiều dài '' seq' return'' sẽ buộc đọc toàn bộ tập tin và bạn có thể thực hiện việc xử lý bên ngoài. Nếu không, nó có lẽ sẽ là tốt nhất để đọc các tập tin như là một 'ByteString' lười biếng và chuyển đổi từ đó (sử dụng' Data.ByteString.Lazy.UTF8.toString' từ gói 'utf8-string'). –

+0

Tôi không thấy làm thế nào 'ByteString' giúp/làm cho mọi việc dễ dàng hơn (mặc dù tôi là người mới bắt đầu) ..' readFile' là lười biếng, phải không? Vậy làm thế nào nó đóng tập tin? Liệu nó có kiểm tra ký tự cuối cùng được đọc không? Tôi có thể bắt chước hành vi của nó bằng cách nào đó? –

1

Theo this site, 6 byte bạn giải mã như sau:

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) 

Vì vậy, một mình trình tự UTF-8 hợp pháp.

Tuy nhiên, các hàm Prelude chuẩn ban đầu chỉ làm ASCII. Tôi không biết họ làm gì bây giờ, nhưng hãy xem câu hỏi này How does GHC/Haskell decide what character encoding it's going to decode/encode from/to? để biết thêm một số ý tưởng. Và sau đó sử dụng http://hackage.haskell.org/package/utf8-string thay vì các chức năng Prelude.

Các vấn đề liên quan