Common Lisp hash-table with with accented characters 作为键

Common Lisp hash-table with with accented characters as keys

我正在尝试在 Common Lisp 中创建一个散列table 来将字符存储为键,但是如果我使用重音字符,散列table 将不起作用。它只需要一个带有重音符号的可能键。

在这个例子中,我添加了 5 个键,看到散列 table 显示了 5 个元素,然后添加了另外 5 个带有重音符号的元素,而 table 显示了 6 个元素,然后添加了另一个“正常” 5 个元素,大小变为 11(如预期的那样)。

这是怎么回事?我该如何解决这个问题?

(defparameter *h* (make-hash-table))
(setf (gethash #\A *h*) #\A)
(setf (gethash #\E *h*) #\A)
(setf (gethash #\I *h*) #\A)
(setf (gethash #\O *h*) #\A)
(setf (gethash #\U *h*) #\A)
(hash-table-count *h*)
(setf (gethash #\á *h*) #\A)
(setf (gethash #\é *h*) #\A)
(setf (gethash #\í *h*) #\A)
(setf (gethash #\ó *h*) #\A)
(setf (gethash #\ú *h*) #\A)
(hash-table-count *h*)
(setf (gethash #\a *h*) #\A)
(setf (gethash #\e *h*) #\A)
(setf (gethash #\i *h*) #\A)
(setf (gethash #\o *h*) #\A)
(setf (gethash #\u *h*) #\A)
(hash-table-count *h*)

如果出于某种原因,您无法更改 SBCL 的默认值 external fomat,您可以随时使用 #\LATIN_SMALL_LETTER_A_WITH_ACUTE,等等

来自SBCL manual

On non-Unicode builds, the default external format is :latin-1.

您想使用 UTF-8。所以按照手册中的说明进行操作,并在调用 SBCL 时设置环境:

$ LANG=C.UTF-8 sbcl --noinform --no-userinit --eval "(print (map 'string #'code-char (list 97 98 246)))" --quit
"abö"
$ LANG=C sbcl --noinform --no-userinit --eval "(print (map 'string #'code-char (list 97 98 246)))" --quit
"ab?"

如果您使用 Emacs 中的 SLIME 或 Sly,可以在您的 init 中进行设置:

(setq sly-lisp-implementations
      '((sbcl ("/opt/sbcl/bin/sbcl") :coding-system utf-8-unix)))

然后使用理智的测试函数,比如char=。在我看来,您应该尽可能使用最具体的谓词。 char-equal 是 case-insensitive 版本。

Sly manual, though the above snippet works on SLIME too as slime-lisp-implemetations

如@Manuel 的评论所述,如果您的 LANG 变量和朋友不使用 UTF-8,那么您就完蛋了。 See this quetsion