Packages

A lightweight wrapper library around Unicode normalization

Current section

Files

Jump to
unicorn src unicorn.erl
Raw

src/unicorn.erl

-module(unicorn).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src\\unicorn.gleam").
-export([to_nfc/1, to_nfd/1, to_nfkc/1, to_nfkd/1, normalize/2]).
-export_type([form/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" A lightweight wrapper library around built-in Unicode normalization functions\n"
" for both Erlang and JavaScript targets.\n"
"\n"
" You can use either Erlang-style (`to_nfc`, `to_nfd`, `to_nfkc`, `to_nfkd`)\n"
" or JavaScript-style (`normalize`) APIs, with type safety provided by Gleam.\n"
"\n"
" ## Usage\n"
"\n"
" ```gleam\n"
" import gleam/int\n"
" import gleam/list\n"
" import gleam/string\n"
"\n"
" import unicorn.{NFKC}\n"
"\n"
" pub fn main() {\n"
" // **Erlang style**\n"
"\n"
" // NFC: \"e\" with a combining acute -> single \"é\"\n"
" let s = unicorn.to_nfc(\"e\\u{0301}\")\n"
" echo #(s, unicode_notations(s))\n"
" // #(\"é\", [\"U+00E9\"])\n"
"\n"
" // NFD: single \"が\" -> \"か\" with a combining dakuten\n"
" let s = unicorn.to_nfd(\"が\")\n"
" echo #(s, unicode_notations(s))\n"
" // #(\"が\", [\"U+304B\", \"U+3099\"])\n"
"\n"
" // NFKC: half-width \"カ\" + half-width dakuten -> full-width \"ガ\"\n"
" let s = unicorn.to_nfkc(\"ガ\")\n"
" echo #(s, unicode_notations(s))\n"
" // #(\"ガ\", [\"U+30AC\"])\n"
"\n"
" // NFKD: single ḕ -> \"e\" + macron + grave\n"
" let s = unicorn.to_nfkd(\"ḕ\")\n"
" echo #(s, unicode_notations(s))\n"
" // #(\"ḕ\", [\"U+0065\", \"U+0304\", \"U+0300\"])\n"
"\n"
" // **JavaScript style**\n"
" // To use it, pass (unicorn.)`Form` to the 2nd argument\n"
"\n"
" // NFKC: fraction \"¼\" -> separate \"1\" + \"⁄\" + \"4\"\n"
" let s = unicorn.normalize(\"¼\", NFKC)\n"
" echo #(s, unicode_notations(s))\n"
" // #(\"1⁄4\", [\"U+0031\", \"U+2044\", \"U+0034\"])\n"
"\n"
" // NFKC: hangul conjoining jamo \"ᄀ\" + \"ᅡ\" + \"ᆨ\" -> single \"각\"\n"
" let s = unicorn.normalize(\"각\", NFKC)\n"
" echo #(s, unicode_notations(s))\n"
" // #(\"각\", [\"U+AC01\"])\n"
" }\n"
" \n"
" fn unicode_notations(s: String) -> List(String) {\n"
" list.map(string.to_utf_codepoints(s), fn(cp) {\n"
" let cp = string.utf_codepoint_to_int(cp)\n"
" \"U+\" <> string.pad_start(int.to_base16(cp), 4, \"0\")\n"
" })\n"
" }\n"
" ```\n"
"\n"
" For details on Unicode normalization, see:\n"
" https://unicode.org/reports/tr15/\n"
).
-type form() :: n_f_c | n_f_d | n_f_k_c | n_f_k_d.
-file("src\\unicorn.gleam", 77).
?DOC(
" Converts a `String` into its\n"
" canonical composition form (NFC).\n"
).
-spec to_nfc(binary()) -> binary().
to_nfc(S) ->
er_ffi:to_nfc(S).
-file("src\\unicorn.gleam", 83).
?DOC(
" Converts a `String` into its\n"
" canonical decomposition form (NFD).\n"
).
-spec to_nfd(binary()) -> binary().
to_nfd(S) ->
er_ffi:to_nfd(S).
-file("src\\unicorn.gleam", 89).
?DOC(
" Converts a `String` into its\n"
" compatibility composition form (NFKC).\n"
).
-spec to_nfkc(binary()) -> binary().
to_nfkc(S) ->
er_ffi:to_nfkc(S).
-file("src\\unicorn.gleam", 95).
?DOC(
" Converts a `String` into its\n"
" compatibility decomposition form (NFKD).\n"
).
-spec to_nfkd(binary()) -> binary().
to_nfkd(S) ->
er_ffi:to_nfkd(S).
-file("src\\unicorn.gleam", 98).
?DOC(" Normalizes a `String` to the specified Unicode normalization `form`.\n").
-spec normalize(binary(), form()) -> binary().
normalize(S, Form) ->
case Form of
n_f_c ->
er_ffi:to_nfc(S);
n_f_d ->
er_ffi:to_nfd(S);
n_f_k_c ->
er_ffi:to_nfkc(S);
n_f_k_d ->
er_ffi:to_nfkd(S)
end.