In the previous post we discussed the
Q and
B encodings, and ended with
a bug on mismatching charset if the charset is not utf-8, let's try to fix the bug here.
It would be nice if we can use local charsets such as
iso-8559-1 or
big5 if we know for sure that the charset contains all of the characters that appears in the string (of course, it is the developer's responsibility to choose the right charset; the code will error out if the charset does not match the data).
PLT Scheme provides a
convert-stream to help handle converting bytes from one charset to another. We can build helpers that takes strings or bytes and return string or bytes on top of this function. What we want are something like:
(bytes/charset->string #"this is a string" "ascii") ;; => returns a string
(bytes/charset->bytes/utf-8 <bytes> <charset>) ;; => returns a bytes
The idea is that we'll convert the input data to input-port, and then retrieve the data from the output-port, which will be a bytes port.
So let's start with a helper function that'll take in an input-port, and the charsets and then return a bytes:
(define (port->bytes/charset in charset-in charset-out)
(call-with-output-bytes
(lambda (out)
(convert-stream charset-in in charset-out out))))
Then we can have the following:
(define (bytes->bytes/charset bytes charset-in charset-out)
(port->bytes/charset (open-input-bytes bytes) charset-in charset-out))
And we can define converting bytes to and from utf-8:
(define (bytes/charset->bytes/utf-8 bytes charset)
(bytes->bytes/charset bytes charset "utf-8"))
(define (bytes/utf-8->bytes/charset bytes charset)
(bytes->bytes/charset bytes "utf-8" charset))
And finally we can then return strings on top of these two functions:
;; there are more to handle (specifically charsets).
(define (bytes/charset->string bytes charset)
(bytes->string/utf-8 (bytes/charset->bytes/utf-8 bytes charset)))
(define (string->bytes/charset string charset)
(bytes/utf-8->bytes/charset (string->bytes/utf-8 string) charset))
With the above functions, we can now ensure to convert the encoded word into the correct charset: