Frage

Ich rufe eine lustige API, die ein Byte-Array zurückgibt, aber ich möchte einen Text-Stream. Gibt es eine einfache Möglichkeit, einen Text-Stream von einem Byte-Array zu bekommen? Denn jetzt warf ich gerade zusammen:

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

und dann wickeln Sie das Ergebnis mit Eingängen-from-String, aber das kann der beste Weg, nicht sein. (Plus, es ist schrecklich ineffizient.)

In diesem Fall, ich weiß, es ist immer ASCII, so dass es entweder als ASCII oder UTF-8 zu interpretieren wäre in Ordnung. Ich bin mit Unicode-aware SBCL, aber ich würde eine tragbare (auch ASCII-only) Lösung auf einen SBCL-Unicode-spezifischen bevorzugen.

War es hilfreich?

Lösung

FLEXI-STREAMS ( http://weitz.de/flexi-streams/ ) hat portable Konvertierungsfunktion

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

=>

"Hello"

Oder, wenn Sie wollen einen Strom:

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

wird einen Stream zurück, die den Text aus Byte-Vektor liest

Andere Tipps

Es gibt zwei portable Bibliotheken für diese Umwandlung:

  • flexi-Ströme, die bereits in einer anderen Antwort erwähnt.

    Diese Bibliothek ist älter und hat mehr Funktionen, insbesondere die ausfahrbaren Ströme.

  • Babel , eine Bibliothek für specificially Zeichencodierung und Decodierung

    Der Hauptvorteil von Babel über flexi-Streams ist die Geschwindigkeit.

Für eine optimale Leistung verwenden Babel, wenn sie die Funktionen, die Sie brauchen, und ansonsten zurück zu flexi-Ströme fallen. Unterhalb einem (slighly unwissenschaftlich)-Micro, welche die Geschwindigkeitsdifferenz.

Für diesen Testfall, Babel ist 337-mal schneller und muss 200-mal weniger Speicher.

(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.
|#

Wenn Sie sich nicht um UTF-8-Codierung sorgen (das im Wesentlichen bedeutet „einfach nur ASCII“) können Sie in der Lage sein, die Karte zu verwenden:

(Map 'string #' Code-char # (72 101 108 108 111))

sagen, dass ich mit den vorgeschlagenen flexistream oder babel Lösungen gehen.

Aber nur der Vollständigkeit halber und Nutzen künftiger Googler auf dieser Seite ankommen Ich möchte sbcl eigenen sb-ext erwähnen: Oktett-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 unterstützt die sogenannte Grey Streams . Diese sind dehnbare Ströme basierend auf CLOS Klassen und generische Funktionen. Sie könnten eine Text-Stream-Unterklasse erstellen, die die Zeichen aus dem Byte-Array wird.

Versuchen Sie, die FORMAT Funktion. (FORMAT NIL ...) gibt die Ergebnisse als String zurück.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top