scheme - 在 Racket 方案或其他方案中解码十六进制格式字符串的惯用方法

标签 scheme lisp common-lisp racket

我的输入数据是十六进制格式的字符串,没有长度限制。我需要单独处理字节。例如,对于“AABBCCDDEEFF”,我想处理 AA,然后是 BB、CC、DD、EE、FF。

使用 Common Lisp,我们可以使用 LOOP:

(loop for (a b) on list do [processing])

在 Racket Scheme 中,我写了这个解决方案:

(define (split-string str)
  (let ((bit #t)
        (char-1 null)
        (char-2 null)
        (result '()))
    (for ((char str))
      (if bit
          (begin
            (set! bit #f)
            (set! char-1 char))
          (begin
            (set! bit #t)
            (set! char-2 char)
            (set! result (cons (~a char-1 char-2) result)))))
    ;; return
    (reverse result)))

(split-string "AABBCCDDEEFF")
;; '("AA" "BB" "CC" "DD" "EE" "FF")

我觉得这不是惯用的 Racket 或 Scheme 代码。我写了第二个解决方案:

(define (split-string2 str)
 (bytes->list (integer->integer-bytes (string->number str 16) 8 false)))

(split-string2 "AABBCCDDEEFF")
;; '(255 238 221 204 187 170 0 0)

在 Racket Scheme 和更普遍的 Lisp 中执行这种操作的惯用方式是什么?

最佳答案

在 Racket 中有很多方法可以做到这一点(与更普遍的方案相反):你想要的概念是 sequences, streams and generators .

首先是一个从字符中计算十六进制数字的函数(这可能存在于 Racket 中,但我懒得找到它,而且它有效):

(define (char->hex-digit c)
  ;; Turn a character into a hex digit
  (cond [(char<=? #\0 c #\9)
         (- (char->integer c) (char->integer #\0))]
        [(char<=? #\A c #\F)
         (+ 10 (- (char->integer c) (char->integer #\A)))]
        [(char<=? #\a c #\f)
         (+ 10 (- (char->integer c) (char->integer #\a)))]
        [else
         (error 'char->hex-digit "~A is not a hex character" c)]))

现在这是一种将十六进制字符串转换为字节列表的简单方法,该方法通过从字符串中创建两个序列来工作,其中一个挑选出每对中的高位数字和另一个低位数字:

(define (hex-string->byte-list hs)
  (for/list ([h (in-string hs 0 #f 2)]
             [l (in-string hs 1 #f 2)])
    (+ (* (char->hex-digit h) 16) (char->hex-digit l))))

显然,根据您使用的 for 的哪个变体,您可以构造不同的结果。

例子:

> (hex-string->byte-list "F00D")
'(240 13)
> (hex-string->byte-list "0102030405060708090a0b0C0D0F")
'(1 2 3 4 5 6 7 8 9 10 11 12 13 15)
> (hex-string->byte-list "01xa")
; char->hex-digit: x is not a hex character [,bt for context]

另一种方法是使用in-slice:

(define (hex-string->byte-list hs)
  (for/list ([hl (in-slice 2 (in-string hs))])
    (+ (* (char->hex-digit (first hl)) 16) (char->hex-digit (second hl)))))

还有很多其他方法可以做到这一点,包括创建自己的序列或流类型,因此您可以编写 (for/list ([b (in-hex-stream-bytes ...)] ) b).

关于scheme - 在 Racket 方案或其他方案中解码十六进制格式字符串的惯用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58950635/

相关文章:

scheme - 如何在方案中创建列表列表?

scheme - 是否有可能在 mit-scheme 中实现 "define-macro"

lisp - 在 lisp 中乘以 2 个向量

macros - 使用 Lisp 宏创建类似的函数

raspberry-pi - 使用命令行参数调用 CCL + Quicklisp 脚本作为可执行文件并实现所需的输出

C++制作一个松散类型的语言解析器

scheme - Lisp 对一个新的(大概)程序员来说会很难学吗?

LISP 合并两个整数列表并按升序对它们进行排序?

namespaces - 为什么有多个命名空间?

function - 使用 defun 以编程方式构建 Common Lisp 函数