2009-03-01 49 views
19

我打電話給一個有趣的API,它返回一個字節數組,但我想要一個文本流。有一種簡單的方法從字節數組中獲取文本流嗎?現在我只是把在一起:如何將字節數組轉換爲Common Lisp中的字符串?

(defun bytearray-to-string (bytes) 
    (let ((str (make-string (length bytes)))) 
    (loop for byte across bytes 
     for i from 0 
     do (setf (aref str i) (code-char byte))) 
    str)) 

,然後包裹結果與輸入 - 從字符串,但不能是最好的方式。 (另外,它的效率非常低。)

在這種情況下,我知道它總是ASCII,因此將它解釋爲ASCII或UTF-8就沒問題。我使用支持Unicode的SBCL,但我更喜歡SBCL-Unicode特定版本的便攜式(甚至是純ASCII)解決方案。

回答

27

FLEXI流(http://weitz.de/flexi-streams/)具有便攜轉換功能

(flexi-streams:octets-to-string #(72 101 108 108 111) :external-format :utf-8) 

=> 

"Hello" 

或者,如果你想有一個流:

(flexi-streams:make-flexi-stream 
    (flexi-streams:make-in-memory-input-stream 
     #(72 101 108 108 111)) 
    :external-format :utf-8) 

將返回讀取的字節矢量文本流

0

試試FORMAT函數。 (FORMAT NIL ...)以字符串形式返回結果。

+0

真實的,但它還是會做的中間字符串。我希望有一個解決方案可以將現有的字節數組包裝在一個流中,而不需要O(n)多個存儲空間。我猜我的頭銜不太好。 :-) – Ken 2009-03-01 17:02:59

4

SBCL支持所謂的Gray Streams。這些是基於CLOS類和泛型函數的可擴展流。您可以創建一個從字節數組中獲取字符的文本流子類。

23

此轉換有兩個便攜庫:

  • flexi-streams,已在另一個答案中提及。

    該庫較舊,具有更多功能,特別是可擴展流。

  • Babel,字符編碼和解碼

    specificially庫巴別超過彈性工作流的主要優點是速度。

爲獲得最佳性能,請使用Babel(如果它具有您需要的功能),否則返回到flexi-stream。說明速度差異的(微不科學的)微基準圖下方。

對於這個測試案例,Babel是337倍,更快,需要200倍的內存。

(asdf:operate 'asdf:load-op :flexi-streams) 
(asdf:operate 'asdf:load-op :babel) 

(defun flexi-streams-test (bytes n) 
    (loop 
    repeat n 
    collect (flexi-streams:octets-to-string bytes :external-format :utf-8))) 

(defun babel-test (bytes n) 
    (loop 
    repeat n 
    collect (babel:octets-to-string bytes :encoding :utf-8))) 

(defun test (&optional (data #(72 101 108 108 111)) 
         (n 10000)) 
    (let* ((ub8-vector (coerce data '(simple-array (unsigned-byte 8) (*)))) 
     (result1 (time (flexi-streams-test ub8-vector n))) 
     (result2 (time (babel-test ub8-vector n)))) 
    (assert (equal result1 result2)))) 

#| 
CL-USER> (test) 
Evaluation took: 
    1.348 seconds of real time 
    1.328083 seconds of user run time 
    0.020002 seconds of system run time 
    [Run times include 0.12 seconds GC run time.] 
    0 calls to %EVAL 
    0 page faults and 
    126,402,160 bytes consed. 
Evaluation took: 
    0.004 seconds of real time 
    0.004 seconds of user run time 
    0.0 seconds of system run time 
    0 calls to %EVAL 
    0 page faults and 
    635,232 bytes consed. 
|# 
14

如果您不必擔心UTF-8編碼(即,從本質上講,是指「只是普通的ASCII」),您可以使用地圖:

(地圖「串#'code-char#(72 101 108 108 111))
+2

,工程上出的現成的Common Lisp :) – Olie 2013-07-18 04:39:52

+0

根據UTF-8支持你的口齒不清系統很好的解決方案,這可以爲UTF-8的正常工作。例如,sbcl和ccl現在支持utf-8。可移植性是另一回事... – vancan1ty 2014-01-01 21:20:22

4

我說的是建議的flexistream或babel解決方案。

但只是爲了完整性,到達此頁面未來的Google我想提一提SBCL自己的SB-EXT的好處:八位字節到字符串:

SB-EXT:OCTETS-TO-STRING is an external symbol in #<PACKAGE "SB-EXT">. 
    Function: #<FUNCTION SB-EXT:OCTETS-TO-STRING> 
    Its associated name (as in FUNCTION-LAMBDA-EXPRESSION) is 
    SB-EXT:OCTETS-TO-STRING. 
    The function's arguments are: (VECTOR &KEY (EXTERNAL-FORMAT DEFAULT) (START 0) 
              END) 
    Its defined argument types are: 
    ((VECTOR (UNSIGNED-BYTE 8)) &KEY (:EXTERNAL-FORMAT T) (:START T) (:END T)) 
    Its result type is: 
    * 
相關問題