Skip to content

Instantly share code, notes, and snippets.

@lionel-rowe
Last active August 2, 2025 08:28
Show Gist options
  • Save lionel-rowe/7976fd6ad8509258522bf9ad7b295e5f to your computer and use it in GitHub Desktop.
Save lionel-rowe/7976fd6ad8509258522bf9ad7b295e5f to your computer and use it in GitHub Desktop.
// @ts-check
// https://en.wikipedia.org/wiki/Korean_language_and_computers#Hangul_Syllables_block
const INITIAL = 'ᄀ'.charCodeAt(0)
const MEDIAL = 'ᅡ'.charCodeAt(0)
const FINAL = 'ᆨ'.charCodeAt(0) - 1
const initials = new Set()
const medials = new Set()
const finals = new Set()
console.info(charRange(0xAC00, 0xD7A3).map(check))
assert([...initials].join('') === 'ᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑᄒ')
assert([...medials].join('') === 'ᅡᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵ')
assert([...finals].join('') === 'ᆨᆩᆪᆫᆬᆭᆮᆯᆰᆱᆲᆳᆴᆵᆶᆷᆸᆹᆺᆻᆼᆽᆾᆿᇀᇁᇂ')
/** @param {string} char */
function check(char) {
const cp = char.charCodeAt(0)
const [initial, medial, final = null] = char.normalize('NFD')
assert(initial != null)
assert(medial != null)
const calced = calculateCodePoint(initial, medial, final)
initials.add(initial)
medials.add(medial)
if (final != null) finals.add(final)
assert(calced === cp)
return { char, initial, medial, final }
}
/**
* @param {string} initial
* @param {string} medial
* @param {string | null} final
*/
function calculateCodePoint(initial, medial, final) {
const i = initial.charCodeAt(0) - INITIAL
const m = medial.charCodeAt(0) - MEDIAL
const f = final == null ? 0 : final.charCodeAt(0) - FINAL
return i * 588 + m * 28 + f + 44032
}
/**
* @param {number} start
* @param {number} end
*/
function charRange(start, end) {
return Array.from({ length: end - start + 1 }, (_, i) => String.fromCodePoint(i + start))
}
/**
* @param {boolean} condition
* @returns {asserts condition}
*/
function assert(condition, message = 'Assertion failed') {
if (!condition) throw new Error(message)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment