質問

バイト配列を返す面白いAPIを呼び出していますが、テキストストリームが必要です。バイト配列からテキストストリームを取得する簡単な方法はありますか?今のところ、私は一緒に投げました:

(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))

そして結果をwith-input-from-stringでラップしますが、それは最良の方法ではありません。 (さらに、ひどく非効率的です。)

この場合、常にASCIIであることがわかっているため、ASCIIまたはUTF-8として解釈しても問題ありません。ユニコード対応のSBCLを使用していますが、SBCLユニコード固有のソリューションよりも、ポータブルな(ASCIIのみの)ソリューションを好むでしょう。

役に立ちましたか?

解決

FLEXI-STREAMS( 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)

バイトベクトルからテキストを読み取るストリームを返します

他のヒント

この変換には2つのポータブルライブラリがあります:

  • flexi-streams、別の回答ですでに言及されています。

    このライブラリは古く、より多くの機能、特に拡張可能なストリームがあります。

  • Babel 、文字エンコードおよびデコード専用のライブラリ

    フレキシストリームに対するBabelの主な利点は速度です。

最高のパフォーマンスを得るには、必要な機能がある場合はBabelを使用し、それ以外の場合はflexi-streamsにフォールバックします。速度差を示す(わずかに非科学的な)マイクロベンチマークの下。

このテストケースの場合、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.
|#

UTF-8エンコーディング(本質的には「単なるASCII」を意味する)を心配する必要がない場合は、MAPを使用できます:

(map 'string#' code-char#(72 101108108111))

提案されているflexistreamまたはbabelソリューションを使用すると言います。

しかし、完全性とこのページに到着する将来のグーグルの利益のために、私はsbcl自身のsb-ext:octets-to-string:に言及したいです:

   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:
     *

SBCLは、いわゆるグレーストリームをサポートしています。これらは、CLOSクラスと汎用関数に基づいた拡張可能なストリームです。バイト配列から文字を取得するテキストストリームサブクラスを作成できます。

FORMAT 関数を試してください。 (FORMAT NIL ...)は、結果を文字列として返します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top