Every emoji in one hash table: playing with Emacs' ucs‑names

Emacs has a native function ucs-names in mule-cmds.el. Running it creates a hash table with almost 50 thousand unicode characters, which is then memoized in a variable of the same name.

I was playing with that, and thought they'd make good examples of xht usage, the amount of which I seem never to be satisfied with.

So there we go.

Size of the hash table:

(require 'xht)

;; Yes, it's a hash table
(h? (ucs-names)) => t
;; which is now memoized here
(h?  ucs-names)  => t
;; and which has a lot of unicode characters
(h-length ucs-names) => 45680

The characters named PENGUIN and MONKEY:

(h-let (ucs-names) (string .PENGUIN)) => "🐧"
(h-let (ucs-names) (string .MONKEY))  => "🐒"

The character named MONKEY FACE:

;; Two ways of doing it:
(h-let (ucs-names) (string .MONKEY\ FACE)) => "🐵"
(string (h-get (ucs-names) "MONKEY FACE")) => "🐵"

All characters that have MONKEY in their names:

;; In two passes:
(->> (ucs-names)
     (h--sel  (s-match "monkey" key))
     (h--hmap (string value) key))
;; Or in one pass:
(h--hmap (when (s-match "monkey" key) (string value))  key  (ucs-names))
H=> (h* "🐒" "MONKEY"
        "🐵" "MONKEY FACE"
        "🙈" "SEE-NO-EVIL MONKEY"
        "🙉" "HEAR-NO-EVIL MONKEY"
        "🙊" "SPEAK-NO-EVIL MONKEY")

For comparison: same as above — but, instead of xht we use only primitive hash table functions, with the results displayed as such:

(let ((res (make-hash-table :test 'equal)))
  (maphash (lambda (key value)
             (when (string-match "monkey" key)
               (puthash (string value) key res)))
           (ucs-names))
  res)
#s(hash-table test equal data
              ("🐒" "MONKEY" "🐵" "MONKEY FACE" "🙈" "SEE-NO-EVIL MONKEY"
               "🙉" "HEAR-NO-EVIL MONKEY" "🙊" "SPEAK-NO-EVIL MONKEY"))

The name of that monkey character, capitalized:

(h-let (h--hmap (when (s-match "monkey" key) (string value)) key (ucs-names))
  (capitalize .🙊))
=> "Speak-No-Evil Monkey"

What shared end do these monkey names have?

(h-let (h--hmap (when (s-match "monkey" key) (string value)) key (ucs-names))
  (-reduce #'s-shared-end (list .🙈 .🙉 .🙊)))
=> "-NO-EVIL MONKEY"

All characters whose names have MONKEY:

(->> (ucs-names) (h--sel (s-match "monkey" key)) h-values (-map #'string))
=> '("🐒" "🐵" "🙈" "🙉" "🙊")

All characters whose names have LAMBDA:

(->> (ucs-names) (h--sel (s-match "lambda" key)) h-values (-map #'string))
=> '("ƛ" "ƛ" "Λ" "λ" "ᴧ" "𐎍" "𝚲" "𝛌" "𝛬" "𝜆" "𝜦" "𝝀" "𝝠" "𝝺" "𝞚" "𝞴")

A hash table of all characters whose names have TABLE.
Keys are characters, as symbols. Values are names, as strings:

(h--hmap (when (s-match "table" key)
           (read (string value)))
         key
         (ucs-names))
H=> (h* ' "MONOSTABLE SYMBOL"
        ' "CJK RADICAL TABLE"
        ' "KANGXI RADICAL TABLE"
        ' "CIRCLED IDEOGRAPH SUITABLE"
        '🏓 "TABLE TENNIS PADDLE AND BALL"
        '📾 "PORTABLE STEREO"
        '🚰 "POTABLE WATER SYMBOL"
        '🚱 "NON-POTABLE WATER SYMBOL")

An Org table of monkeys, with header: Name, Code, Emoji.
Actually, let's split Code into Decimal and Hex:

(h->orgtbl
 (h--hmap (when (s-match "monkey" key) key)
          (h* 'Name key 'Decimal value
              'Hex  (format "%X" value)
              'Emoji     (string value))
          (ucs-names)))
O=> "\
| Name                 | Decimal | Hex   | Emoji |
|----------------------+---------+-------+-------|
| MONKEY               |  128018 | 1F412 | 🐒    |
| MONKEY FACE          |  128053 | 1F435 | 🐵    |
| SEE-NO-EVIL MONKEY   |  128584 | 1F648 | 🙈    |
| HEAR-NO-EVIL MONKEY  |  128585 | 1F649 | 🙉    |
| SPEAK-NO-EVIL MONKEY |  128586 | 1F64A | 🙊    |"

Hash tables are fun — go play with them.

📆 2025-11-08