2012-01-16 33 views
8

tôi luôn luôn gặp phải lỗi sau khi cố gắng đọc một ByteString:
Prelude.read: no parseCách tốt nhất để chuyển đổi ByteString thành Int là gì?

Đây là một mẫu mã mà sẽ gây ra lỗi này xảy ra khi render trong một trình duyệt:

factSplice :: SnapletSplice App App 
factSplice = do 
    mbstr <- getParam "input" -- returns user input as bytestring 
    let str = maybe (error "splice") show mbstr 
    let n = read str :: Int 
    return [X.TextNode $ T.pack $ show $ product [1..n]] 

Hoặc có lẽ đơn giản hơn:

simple bs = read (show bs) :: Int 

Vì lý do nào đó, sau show bs chuỗi kết quả bao gồm dấu ngoặc kép. Vì vậy, để có được xung quanh các lỗi tôi phải loại bỏ các dấu ngoặc kép sau đó read nó. tôi sử dụng hàm sau sao chép từ internet để làm như vậy:

sq :: String -> String 
sq [email protected][c]      = s 
sq ('"':s) | last s == '"' = init s 
      | otherwise  = s 
sq ('\'':s) | last s == '\'' = init s 
      | otherwise  = s 
sq s       = s 

Sau đó simple bs = read (sq.show bs) :: Int công trình như mong đợi.

  1. Tại sao lại xảy ra trường hợp này?
  2. Cách tốt nhất để chuyển đổi ByteString thành Int là gì?

Trả lời

9

Show được sử dụng để tạo ra một đại diện String của một cái gì đó, đó là hữu ích cho gỡ lỗiplain-text serialization. Các Show typeclass không chỉ là một cách ưa thích của chuyển đổi bất cứ điều gì thành một String. Đó là lý do tại sao ByteString thêm dấu ngoặc kép vào chuỗi: vì có thể dễ dàng đọc nó theo cách đó khi gỡ lỗi hoặc deserializing luồng dữ liệu.

Bạn có thể sử dụng Data.ByteString.Char8.unpack chức năng để chuyển đổi một ByteString đến một String, nhưng lưu ý rằng đây Giải nén các byte byte mỗi ByteString, mà messes lên các ký tự Unicode có giá trị cao hoặc các ký tự khác được lưu trữ như nhiều hơn một byte ; nếu bạn muốn thực hiện điều gì khác ngoài việc sử dụng kết quả read, tôi khuyên bạn nên chuyển đổi ByteString thành Text, điều này mang lại sự linh hoạt hơn trong tình huống này. Giả sử rằng mã hóa của bạn là UTF8 trong trường hợp này (Như phải là mặc định trong Snap), bạn có thể sử dụng chức năng Data.Text.Encoding.decodeUtf8 cho việc này. Để chuyển đổi giá trị Text thành String bằng các ký hiệu Unicode chính xác, bạn sử dụng Data.Text.unpack.

Khi bạn có số String, bạn được tự do read số tiền tùy thích; Ngoài ra, bạn có thể chọn đọc giá trị Text trực tiếp bằng các chức năng trong mô-đun Data.Text.Read.

+0

Đối với tôi câu hỏi số 2 vẫn không rõ ràng - hoặc nó có thể chỉ là trường hợp sử dụng cụ thể hơn mà tôi tò mò và tôi nghĩ là liên quan đến câu hỏi ban đầu này: Điều gì sẽ xảy ra nếu có một số loại " lĩnh vực chiều dài "được phân tích cú pháp như một ByteString của chiều dài 4, trong đó thực tế mô tả một Int32. Giải pháp được đề xuất của bạn có còn hợp lệ không? Như một giải pháp thoải mái hơn, tôi đã tìm kiếm một thư viện có thể lấy loại ByteString như vậy và sẽ trả về đúng Int. Có thư viện nào có thể xử lý trường hợp sử dụng này không? –

10

Cách tốt nhất để chuyển đổi ByteString thành X phụ thuộc vào X. Nếu bạn có chuyển đổi tốt từ String, hãy truy cập qua Data.BytString.Char8.unpack có thể tốt, nếu đó là ASCII ByteString. Đối với mã UTF-8 được mã hóa ByteString s, gói utf8-string chứa hàm chuyển đổi toString. Đối với một số loại cụ thể, như Int, như được đề cập trong tiêu đề, các chuyển đổi đặc biệt nhanh hơn tồn tại. Ví dụ: Data.ByteString.Char8.readIntreadInteger.

+1

Đối với những người đến từ internet: ** Đây là câu trả lời nếu "cách tốt nhất" cũng có nghĩa là "cách hiệu quả" cho bạn! ** – donatello

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