2009-03-01 59 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: 
    * 
相关问题