Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I convert a string of hex into ASCII using elisp?

Tags:

emacs

elisp

Today I received a reply to one of my emails in the form of a string of hex bytes:

"686170707920333974682068617665206120676f6f64206f6e6521"

And I was thinking of the most efficient clean way to convert the string into it's ASCII equivalent. I'll add my answer to the question but I didn't feel it was as elegant as it could have been.

like image 729
stsquad Avatar asked Aug 17 '12 09:08

stsquad


People also ask

Which function is used to convert hexadecimal values to ASCII characters?

sprintf() will convert your presumably binary data to an ASCII hex string or a decimal hex string.


2 Answers

Here's an iterative solution

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

And one using loop, if you're looking to avoid side-effect operations (you may need to (require 'cl) in order to use this one):

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

In general, it's best to avoid recursion in Elisp and Common Lisp; your stack is going to keel over with a big enough input, and neither language guarantees tail recursion (which you aren't using, but still). In Scheme, it's a different story.

Incidentally, Happy 39th.

like image 185
Inaimathi Avatar answered Nov 15 '22 11:11

Inaimathi


For those that come here searching...

Elaborating a bit on Inaimathi's answer, here's the code to replace the selected region with the decoded hexa:

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

Save that on a file and then M-x load-file. Or put on ~/emacs.d, or whatever. Then select the region with the hexa contents and M-x hex-decode-region. Enjoy!

like image 44
Shrein Avatar answered Nov 15 '22 12:11

Shrein