首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在球拍方案或其他方案中解码六进制字符串的惯用方法

在球拍方案或其他方案中解码六进制字符串的惯用方法
EN

Stack Overflow用户
提问于 2019-11-20 09:14:47
回答 4查看 668关注 0票数 3

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

使用Common,我们可以使用循环:

代码语言:javascript
复制
(loop for (a b) on list do [processing])

在球拍计划中,我写了这个解决方案:

代码语言:javascript
复制
(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")

我觉得这不是惯用的拍子,也不是计划代码。我写了第二个解决方案:

代码语言:javascript
复制
(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方案和更一般的Lisp中,执行这种操作的惯用方法是什么?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2019-11-20 11:19:40

在Racket中有很多方法可以做到这一点(与更一般的Scheme不同):您想要的概念是序列、流和生成器

首先是一个函数,用于计算字符中的十六进制数字(这个函数可能存在于球拍中,但我太懒了,找不到它,这是可行的):

代码语言:javascript
复制
(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)]))

下面是一种简单的方法,可以将十六进制字符串转换为字节列表,方法是从字符串中创建两个序列,其中一个从字符串中选择高的序列,另一个选择低的数字:

代码语言:javascript
复制
(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变体,您可以构造不同的结果。

示例:

代码语言:javascript
复制
> (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

代码语言:javascript
复制
(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)了。

票数 4
EN

Stack Overflow用户

发布于 2019-11-20 09:32:13

请注意,Common版本将无法工作,因为输入是一个字符串;为了使用相同的方法,您应该首先将字符串转换为一个字符列表;其次,您需要添加一个by指令,以通过cddr来超越列表,即跳过已经读取的b。最终的结果是:

代码语言:javascript
复制
(loop
   for (a b) on (coerce "AABBCCDDEEFF" 'list) by #'cddr
   collect (parse-integer (coerce (vector a b) 'string)
                          :radix 16))

=> (170 187 204 221 238 255)

但是,这有点浪费,parse-integer承认:start:end参数,因此不需要分配任何中间列表或字符串(除了最后一个collect之外,您也可以跳过它,直接处理该值):

代码语言:javascript
复制
(loop
   with string = "AABBCCDDEEFF"
   with size = (length string)
   initially (assert (evenp size))
   for start from 0 by 2
   for end from 2 by 2 upto size
   collect (parse-integer string :start start :end end :radix 16))

=> (170 187 204 221 238 255)
票数 3
EN

Stack Overflow用户

发布于 2019-11-20 12:38:36

一种惯用的方法是使用递归(保持与split-string相同的功能),如下所示:

代码语言:javascript
复制
(define (split-string-recur str)
  (cond [(or (string=? str "") (string=? "" (substring str 1))) '()]
        [else (cons (substring str 0 2) (split-string-recur (substring str 2)))]))

还有一个尾递归版本:

代码语言:javascript
复制
(define (split-string-trecur str)
  (define (split-string-recur str acc)
    (cond [(or (string=? str "") (string=? "" (substring str 1))) acc]
        [else (split-string-recur (substring str 2) (append acc (list (substring str 0 2))))]))
  (split-string-recur str '()))

for/list方法( in-slice on in-string sequence,简称这里)也是一种惯用方法。

请注意,我们还可以在字符串上使用一个小接口,如以下所示,以提高其可读性:

代码语言:javascript
复制
(module string-util typed/racket
  (provide (all-defined-out))

  (: empty-string? : (-> String Boolean))
  (define (empty-string? s)
    (string=? "" s))

  (: string-first : (-> String String))
  (define (string-first s)
    (substring s 0 1))

  (: string-last : (-> String String))
  (define (string-last  s)
    (substring s (- (string-length s) 1) (string-length s)))

  (: string-rest : (-> String String))
  (define (string-rest  s)
    (substring s 1 (string-length s))))

(require 'string-util)

(define (split-string-recur str)
  (cond [(or (empty-string? str) (empty-string? (string-rest str))) '()]
        [else (cons (string-append (string-first str) (string-first (string-rest str)))
                    (split-string-recur (string-rest (string-rest str))))]))
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58950635

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档