Использование литералов Emoji в исходном коде Clojure

В Linux с включенной консолью UTF-8:

Clojure 1.6.0
user=> (def c \の)
#'user/c
user=> (str c)
"の"
user=> (def c \????)

RuntimeException Unsupported character: \????  clojure.lang.Util.runtimeException (Util.java:221)
RuntimeException Unmatched delimiter: )  clojure.lang.Util.runtimeException (Util.java:221)

Я надеялся получить приложение Clojure, богатое смайликами, без особых усилий, но, похоже, я буду искать и вводить коды смайликов? Или я пропустил что-то очевидное здесь? ????


person noahlz    schedule 28.05.2014    source источник
comment
Поскольку ???? — это не символ, а два, нельзя ли просто использовать его как строку: "????"?   -  person Karol S    schedule 06.06.2014
comment
Я надеялся использовать литералы символов, но вы правы. Если я сделаю (def c "????") на tryclj.com - это сработает!   -  person noahlz    schedule 06.06.2014
comment
Контекст: twitter.com/wex_viator/status/473884675476574208   -  person noahlz    schedule 06.06.2014


Ответы (2)


Java представляет символы Unicode в UTF-16. Символы эмодзи являются «дополнительными символами» и имеют кодовую точку, которая не может быть представлена ​​​​в 16 битах.

http://www.oracle.com/technetwork/articles/javase/supplementary-142654.html

По сути, дополнительные символы представлены не как chars, а как int и для работы с ними есть специальные API.

Один из способов - с (Character/toChars 128516) - он возвращает массив символов, который вы можете преобразовать в строку для печати: (apply str (Character/toChars 128516)). Или вы можете создать строку из массива целых чисел с кодовой точкой напрямую с помощью (String. (int-array [128516]) 0 1). В зависимости от всех различных вещей между Java/Clojure и вашими глазами, это может или не может делать то, что вы хотите.

Формат API поддерживает дополнительные символы, так что это может быть проще всего, однако он принимает целое число, поэтому вам понадобится приведение: (format "Smile! %c" (int 128516)).

person Alex Miller    schedule 28.05.2014
comment
Обратите внимание, что UTF-16 не имеет ширины 16 бит с начала 2000-х — это распространенное заблуждение. Он имеет ширину 16 или 32 бита, в зависимости от представляемой кодовой точки. Хотя Java действительно использует UTF-16 внутри, она поддерживает обе разрядности, начиная с версии 1.5 (которая старше, чем самая старая JVM, поддерживаемая в настоящее время Clojure). - person Peter; 14.11.2017

Благодаря расширяемым тегам чтения в Clojure вы можете легко создавать литералы Unicode самостоятельно.

Мы уже знаем, что не весь Юникод может быть представлен в виде char литералов; что предпочтительным представлением символов Unicode в JVM является int; и что строковый литерал может содержать любой символ Unicode таким образом, который также удобен для чтения людьми.

Таким образом, помеченный литерал #u "????", который читается как int, станет отличным символьным литералом Unicode!

Настройте функцию чтения для нового тегового литерала в *data-readers*:

(defn read-codepoint
  [^String s]
  {:pre [(= 1 (.codePointCount s 0 (.length s)))]}
  (.codePointAt s 0))

(set! *data-readers* (assoc *data-readers* 'u #'read-codepoint))

При этом читатель читает такие литералы как целые числа кодовой точки:

#u"????"  ; => 127826
(Character/getName #u"????")  ; => "CHERRIES"

«Теги чтения без квалификаторов пространства имен зарезервированы для Clojure», — говорится в документации… #u — это короткий, но, возможно, не самый ответственный выбор.

person glts    schedule 30.06.2018