Как прочитать строку utf-8 по usocket - PullRequest
1 голос
/ 09 декабря 2011

Когда я читал из потока usocket , используя код ниже:

(let ((stream (socket-stream sk)) line)
  (loop for line = (read-line stream)
     while line do (format t line)))

когда read-line встречается с не-ascii характером, он выдает исключение:

decoding error on stream
#<SB-SYS:FD-STREAM
  for "socket 118.229.141.195:52946, peer: 119.75.217.109..."
  {BCA02F1}>
(:EXTERNAL-FORMAT :UTF-8):
  the octet sequence (176) cannot be decoded.
   [Condition of type SB-INT:STREAM-DECODING-ERROR]

Ни read-line, ни read-byte не работают, поэтому я попытался использовать trivial-utf-8 для чтения строки utf-8 используя read-utf-8-string, но он принимает только двоичный поток, кажется, что сокет-поток не создает двоичный поток, поэтому я был озадачен, как читать из потока сокетов, который имеет символы, отличные от ascii?

Ответы [ 3 ]

1 голос
/ 10 декабря 2011

Ошибка, которую вы получаете, указывает на то, что данные, которые вы пытаетесь прочитать, на самом деле не являются данными UTF-8. Действительно, 176 (= #b10110000) не является байтом, который может вводить символ UTF-8. Если данные, которые вы пытаетесь прочитать, находятся в какой-то другой кодировке, попробуйте соответствующим образом настроить внешний формат вашего компилятора Lisp или использовать Babel или FLEXI-STREAMS для декодировать данные.

1 голос
/ 09 декабря 2011

Вы можете сначала read-sequence (если вы знаете длину раньше времени) или read-bytes, пока они есть, а затем преобразовать их в строку с (babel:octets-to-string octets :encoding :utf-8)) (где октеты (make-array expected-length :element-type '(unsigned-byte 8))).

0 голосов
/ 09 декабря 2011

Когда-то мне это было нужно, и мне было лень искать библиотеку, чтобы сделать это, поэтому я сделал это сам :) Возможно, это не лучший способ, но мне нужно было что-то только для быстрого и не сложного, так что вот оно идет:

(defun read-utf8-char (stream)
  (loop for i from 7 downto 0
     with first-byte = (read-byte stream nil 0)
     do (when (= first-byte 0) (return +null+))
     do (when (or (not (logbitp i first-byte)) (= i 0))
          (setf first-byte (logand first-byte (- (ash 1 i) 1)))
              (return
            (code-char 
             (dotimes (a (- 6 i) first-byte)
               (setf first-byte
                     (+ (ash first-byte 6)
                        (logand (read-byte stream) #x3F)))))))))
...