【问题标题】:Common Lisp hash-table with with accented characters as keys以重音字符为键的 Common Lisp 哈希表
【发布时间】:2019-06-30 19:20:02
【问题描述】:

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

在这个例子中,我添加了 5 个键,然后看到哈希表显示了 5 个元素,然后添加了另外 5 个带重音符号的元素,表格显示了 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*)

【问题讨论】:

  • 您使用的是哪种实现方式?定义*h*时是否尝试过使用另一个test函数?
  • SBCL,我不明白你定义另一个“测试”函数是什么意思。
  • 您可以为make-hash-table 提供一个可选的test 关键字,该关键字确定使用哪个函数来测试两个哈希键是否相等。在 hyperspec 中查看其文档。
  • 这可能是正确的。如果我从终端执行 sbcl 并使用(eq #\É #\Á),它会显示NIL(我在~/.sbclrc 中有(setf sb-impl::*default-external-format* :utf-8) 行)但是如果我从Sublime Text 中的SublimeREPL 执行它,它会显示T。谢谢你。虽然这个答案可能仍然无法回答,但我可能会删除它。
  • 我会说这是 SBCL 中的一个错误。如果外部格式导致#\É#\Á 未正确解码,则读者应进行诊断。基本上这里似乎发生的是原始 UTF-8 遵循黑斜线,而反斜线语法只占用第一个字节(两个字符都是 #xC3),无法诊断尾随垃圾。

标签: unicode lisp common-lisp hashtable


【解决方案1】:

来自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 是不区分大小写的版本。

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

正如@Manuel 在评论中指出的那样,如果您的 LANG 变量和朋友不使用 UTF-8,那么您注定要失败。 See this quetsion

【讨论】:

  • 谢谢。我的问题是 SublimeREPL。我不知道如何找到一种方法让它在打开时加载 utf8。是否有写入LANG=C.UTF-8 的持久方式,以便在执行sbcl 时“读取”它?因为我不能告诉 SublimeREPL “执行”LANG=C.UTF-8 sbcl,所以它说 FileNotFoundError(2, "No such file or directory: 'LANG=C.UTF-8 sbcl'")。谢谢
  • 你可以编写一个“start-sbcl.sh”可执行脚本来做正确的事情,并将 SublimeREPL 指向该脚本。
  • eql,默认的测试函数,会和char=一样吗? char= 不是make-hash-table 的有效测试函数,所以如果不是,那么equalequalp(不区分大小写)是正确的选择。
  • @coredump 我会尝试(虽然如果它不简单,我不知道我是否能够做到),但这可能是我需要的。谢谢
  • 好吧,我解决了。无论如何,我需要的是@coredump 所说的,制作我自己的脚本,但我需要的LANG=... 的instedo 是LC_CTYPE=es_ES.UTF-8(取自here),Spenser Truex 的版本不起作用。我仍然不明白,但它有效。
【解决方案2】:

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

【讨论】:

  • 是的,我知道这一点。问题是 SublimeREPL 的行为不像预期的那样,并且不使用 utf-8 外部格式,我不知道该怎么做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-21
  • 2012-03-31
  • 1970-01-01
  • 1970-01-01
  • 2013-05-02
  • 2011-08-19
相关资源
最近更新 更多