使用#x ...如下所示获得十六进制值的小数
> #xB1
177
> #xA5
165
> #xFF
255
假设我们有一个十六进制列表,在列表中使用mapcar #x ...的正确语法是什么?以下不起作用:
> (mapcar #'(lambda (hex) `(#x,hex)) '(B1 A5 FF))
读卡器错误:#b / #o / #x /#r宏中的格式错误。 [SIMPLE-ERROR类型的条件]
感谢。
答案 0 :(得分:8)
#x被称为"读取器宏"。它与使用引号(即"")表示字符串非常相似。它们在读取/编译代码时执行。你真正想要的是一个可以在运行时从十六进制字符串转换的过程。您正在寻找的过程是parse-integer,它接受一个字符串并返回它所代表的值。带有它的mapcar看起来应该是这样的:
(mapcar (lambda (hex)
(parse-integer hex :radix 16))
'("B1" "A5" "FF"))
请注意,这是使用字符串,如果您想在建议中使用符号,则必须执行以下操作:
(mapcar (lambda (hex)
(parse-integer (symbol-name hex) :radix 16))
'(B1 A5 FF))
如果你不知道符号和字符串之间的区别,我建议你阅读:What exactly is a symbol in lisp/scheme?
答案 1 :(得分:3)
我觉得虽然最好解决这个问题的方法可能是malisper's answer中提到的 parse-integer ,但是这种感觉可以通过基于映射的方法来解决。
当我们写#xB1
之类的内容时,我们不是显式地调用函数。相反,我们使用的事实是#
是一个调度读取宏字符,并且为子字符x
安装了一个读取以十六进制编写的数字的函数。这意味着,当评估者或编译器获得表单时,该数字已经存在。但是,我们 do 可以使用get-dispatch-macro-character访问正在处理十六进制字符串的函数。即:
CL-USER> (get-dispatch-macro-character #\# #\x)
#<FUNCTION SB-IMPL::SHARP-X> ; in SBCL
CL-USER> (get-dispatch-macro-character #\# #\x)
#<SYSTEM-FUNCTION SYSTEM::HEXADECIMAL-READER> ; in CLISP
我们可以用这个功能做什么?我们将如何使用它?
2.1.4.4 Macro Characters
...如果一个字符是一个调度宏字符C1,它的读取器宏 function是由实现提供的函数。这个功能 读取十进制数字字符,直到读取非数字C2。如果有的话 读取数字后,将它们转换为相应的整数 中缀参数P;否则,中缀参数P为零。该 终止非数字C2是一个字符(有时称为a “子角色”强调其在下属中的作用 在与之关联的调度表中查找的调度 调度宏字符C1。 读者宏功能 与子字符C2相关联的调用有三个参数: 流,子字符C2和中缀参数P. 更多 有关调度字符的信息,请参阅该函数 设置调度宏字符。
这意味着,当我们编写#xB1
之类的内容时,上面的函数会被调用一个流,可以从中读取B1
,字符x
和{{1} }。我们可以尝试使用这样的参数调用该函数,尽管我们不能确定会发生什么,因为实现可能会对函数的调用位置做出不同的假设。
例如,这在CLISP中没有问题,但SBCL假定该函数应该从读取(我们没有这样做)递归调用:
nil
CL-USER> (funcall (get-dispatch-macro-character #\# #\x)
(make-string-input-stream "B1")
#\x
nil)
177 ; in CLISP
也就是说,对于可以工作的实现,我们可以轻松编写一个 mapcar 类函数来提取调度宏字符函数并将其映射到某些字符串上。因此,在一个有效的实现中:
CL-USER> (funcall (get-dispatch-macro-character #\# #\x)
(make-string-input-stream "B1")
#\x
nil)
; Evaluation aborted on #<SB-INT:SIMPLE-READER-ERROR "~A was invoked
; with RECURSIVE-P being true outside of a recursive read operation."
; {1005F245B3}>. ; in SBCL
(defun map-dispatch-macro-character (disp-char
sub-char
list
&optional (readtable *readtable*))
"Retrieve the dispatch macro character for DISP-CHAR and SUB-CHAR and
map it over the elements in LIST. Each element in LIST is either a
string designator or a two-element list of a string-designator and a
prefix argument."
(flet ((to-list (x)
(if (listp x) x
(list x))))
(let ((fn (get-dispatch-macro-character disp-char sub-char readtable)))
(mapcar (lambda (x)
(destructuring-bind (str &optional prefix) (to-list x)
(with-input-from-string (in (string str))
(funcall fn in sub-char prefix))))
list))))
当然,如果你真的想要能够写CL-USER> (map-dispatch-macro-character #\# #\x '(B1 "A5" (FF nil)))
(177 165 255)
,你当然可以定义一个只从长度为2的字符串中提取字符的版本,这样就可以了:
#x