7

今天我收到了一封以十六进制字节字符串形式的电子邮件回复:

"686170707920333974682068617665206120676f6f64206f6e6521"

而且我正在考虑将字符串转换为ASCII等价物的最有效的干净方法。我会添加我对这个问题的答案,但我觉得它没有它本来可以的那么优雅。

4

7 回答 7

11

这是一个迭代解决方案

(defun decode-hex-string (hex-string)
  (let ((res nil))
    (dotimes (i (/ (length hex-string) 2) (apply #'concat (reverse res)))
      (let ((hex-byte (substring hex-string (* 2 i) (* 2 (+ i 1)))))
        (push (format "%c" (string-to-number hex-byte 16)) res)))))

还有一个 using loop,如果你想避免副作用操作(你可能需要(require 'cl)为了使用这个):

(defun decode-hex-string (hex-string)
  (apply #'concat 
     (loop for i from 0 to (- (/ (length hex-string) 2) 1) 
           for hex-byte = (substring hex-string (* 2 i) (* 2 (+ i 1)))
           collect (format "%c" (string-to-number hex-byte 16)))))

一般来说,在 Elisp 和 Common Lisp 中最好避免递归;您的堆栈将因足够大的输入而崩溃,并且两种语言都不能保证尾递归(您没有使用,但仍然如此)。在 Scheme 中,情况就不同了。

顺便说一句,39 日快乐。

于 2012-08-17T14:24:46.383 回答
4

对于那些来这里寻找...

详细说明 Inaiimathi 的答案,这里是用解码的六进制替换所选区域的代码:

(defun decode-hex-string (hex-string)
  (apply #'concat 
         (loop for i from 0 to (- (/ (length hex-string) 2) 1) 
               for hex-byte = (substring hex-string (* 2 i) (* 2 (+ i 1)))
               collect (format "%c" (string-to-number hex-byte 16)))))

(defun hex-decode-region (start end) 
  "Decode a hex string in the selected region."
  (interactive "r")
  (save-excursion
    (let* ((decoded-text 
            (decode-hex-string 
             (buffer-substring start end))))
      (delete-region start end)
      (insert decoded-text))))

  (provide 'decode-hex-string)
  (provide 'hex-decode-region)

将其保存在文件中,然后 Mx 加载文件。或者放在 ~/emacs.d 上,或者其他什么。然后选择具有 hexa 内容和 Mx hex-decode-region 的区域。享受!

于 2013-08-16T16:57:04.917 回答
4

如果您使用 Magnar Sveen 的dash.el列表 API(并且应该),请尝试:

(concat (--map (string-to-number (concat it) 16) (-partition 2 (string-to-list "686170707920333974682068617665206120676f6f64206f6e6521"))))

该解决方案使用 Emacs 函数string-to-numberstring-to-listand concat,anddash.el函数-partition和照应版本-map。好处concat是它不仅连接字符串,还连接字符列表或向量。我们可以使用->>线程宏重写此代码。它采用第一个参数的结果,然后将其应用于第二个、第三个等参数,就像Unix pipe一样。

(->> (string-to-list "686170707920333974682068617665206120676f6f64206f6e6521")
  (-partition 2)
  (--map (string-to-number (concat it) 16))
  concat)
于 2014-03-18T05:13:27.360 回答
2

在构建 Inaimathi 和 Shrein 提供的答案时,我还添加了一个编码函数。这是字符串和区域参数的编码和解码的实现:

;; ASCII-HEX converion
(defun my/hex-decode-string (hex-string)
  (let ((res nil))
    (dotimes (i (/ (length hex-string) 2) (apply #'concat (reverse res)))
      (let ((hex-byte (substring hex-string (* 2 i) (* 2 (+ i 1)))))
        (push (format "%c" (string-to-number hex-byte 16)) res)))))

(defun my/hex-encode-string (ascii-string)
  (let ((res nil))
    (dotimes (i (length ascii-string) (apply #'concat (reverse res)))
      (let ((ascii-char (substring ascii-string i  (+ i 1))))
        (push (format "%x" (string-to-char ascii-char)) res)))))

(defun my/hex-decode-region (start end) 
  "Decode a hex string in the selected region."
  (interactive "r")
  (save-excursion
    (let* ((decoded-text 
            (my/hex-decode-string
             (buffer-substring start end))))
      (delete-region start end)
      (insert decoded-text))))

(defun my/hex-encode-region (start end) 
  "Encode a hex string in the selected region."
  (interactive "r")
  (save-excursion
    (let* ((encoded-text 
            (my/hex-encode-string
             (buffer-substring start end))))
      (delete-region start end)
      (insert encoded-text))))
于 2017-10-10T09:16:01.853 回答
1

这是我的。我也不是说这特别地道或优雅。也许有点老派。

(defun hex-string-decode (str)
  "Decode STR of the form \"4153434949\" to corresponding \"ASCII\"."
  (let (decoded sub)
    (while (> (length str) 0)
      (setq sub (substring str 0 2)
            decoded (cons (string-to-number sub 16) decoded)
            str (substring str 2) ) )
    (when (not (zerop (length str))) (error "residue %s" str))
    (mapconcat #'char-to-string (nreverse decoded) "") ) )
于 2012-08-20T13:51:43.687 回答
1

起初我没有看到它必须是 Elisp 的要求,所以我以交互方式完成了它,下面的代码遵循我的交互过程。

   (defun decode-hex-string (hex-string)
      (with-temp-buffer
        (insert-char 32 (/ (length hex-string) 2))
        (beginning-of-buffer)
        (hexl-mode)        
        (hexl-insert-hex-string hex-string 1)
        (hexl-mode-exit)
        (buffer-string)))
于 2016-01-06T23:59:55.390 回答
0

这是我想出的解决方案,让我觉得有点难看:

(defun decode-hex-string(string)
  "Decode a hex string into ASCII"
  (let* ((hex-byte (substring string 0 2))
     (rest (substring string 2))
     (rest-as-string (if (> (length rest) 2)
                 (decode-hex-string rest)
               "")))
    (format "%c%s" (string-to-number hex-byte 16) rest-as-string)))
于 2012-08-17T09:34:50.857 回答