Syllables
Use the syllable functions to parse, validate and format written pinyin without loading a dictionary.
import { isSyllable, readSyllable, writeSyllable } from "@kensio/pinyinjs";
readSyllable("jiù"); // { initial: "j", final: "iou", tone: 4 }readSyllable("jiu4"); // the same, both notations parsereadSyllable("lv4"); // { initial: "l", final: "ü", tone: 4 }readSyllable("hello"); // undefinedreadSyllable("běi3"); // undefined, one notation at a timeThese functions are useful for pinyin input fields, learner exercises and conversion between tone notations.
Underlying forms
Section titled “Underlying forms”initial and final store the underlying syllable components. For example, 就 contains j + iou, while 军 contains j + ün:
readSyllable("jūn"); // { initial: "j", final: "ün", tone: 1 }readSyllable("jun1"); // the sameFormatting applies the spelling rules. It contracts iou to iu after an initial and removes the umlaut from ün after j. Different accepted spellings therefore produce the same underlying syllable.
Choose a notation when formatting the syllable:
const jiu = { initial: "j", final: "iou", tone: 4 } as const;writeSyllable(jiu); // "jiù"writeSyllable(jiu, "numbers"); // "jiu4"writeSyllable(jiu, "superscript"); // "jiu⁴"writeSyllable(jiu, "none"); // "jiu"writeSyllableSpelling gives the toneless spelling on its own:
import { writeSyllableSpelling } from "@kensio/pinyinjs";
writeSyllableSpelling({ initial: "j", final: "ün", tone: 1 }); // "jun"Accepted input
Section titled “Accepted input”Input can use tone marks, tone digits, superscript digits, or v and u: for ü:
readSyllable("lü4"); // { initial: "l", final: "ü", tone: 4 }readSyllable("lv4"); // the samereadSyllable("lu:4"); // the sameA syllable must use one tone notation. Mixed notation such as běi3 returns undefined.
normaliseUmlaut converts the v and u: conventions separately:
import { normaliseUmlaut } from "@kensio/pinyinjs";
normaliseUmlaut("lv"); // "lü"Parsing and validation
Section titled “Parsing and validation”A successful parse means the spelling has a valid initial and final. Use an inventory check to determine whether Mandarin uses that combination:
readSyllable("shong"); // { initial: "sh", final: "ong", tone: undefined }isSyllable("shong"); // trueFor example, shong can be parsed but is absent from the standard Mandarin inventory:
import { ATTESTED_SYLLABLES, DICTIONARY_SYLLABLES } from "@kensio/pinyinjs";
DICTIONARY_SYLLABLES.has("shong"); // falseDICTIONARY_SYLLABLES.has("zhuang"); // trueATTESTED_SYLLABLES.length; // 415Choose the inventory appropriate to your input:
| Export | Size | Is |
|---|---|---|
ATTESTED_SYLLABLES |
415 | the standard toneless syllable inventory |
RARE_SYLLABLES |
9 | spellings the dictionary uses that the inventory omits |
DICTIONARY_SYLLABLES |
424 | the two together, what the build validates against |
The dictionary inventory additionally includes nine rare syllables, bong, cei, din, eng, fiao, lo, rua, sei and tei. They occur in dialect readings, interjections and onomatopoeia. Use ATTESTED_SYLLABLES for learner input and DICTIONARY_SYLLABLES when validating dictionary data.
Valid tone combinations
Section titled “Valid tone combinations”The syllable inventories omit tone. Some syllables use only a subset of the five tones. For example, lo occurs only in neutral tone, while bàn occurs but bán does not.
import { isAttestedTone, readSyllable, SYLLABLE_TONES } from "@kensio/pinyinjs";
SYLLABLE_TONES.get("lo"); // [5]SYLLABLE_TONES.get("ban"); // [1, 3, 4, 5]isAttestedTone(readSyllable("ló")); // falseisAttestedTone(readSyllable("lo")); // true, no tone claims nothingThe dictionary contains 1,708 of the 2,120 possible combinations of 424 syllables and five tones. A build assertion keeps the exported tone inventory consistent with those readings.
Romanisation readers use this inventory to narrow ambiguous spellings. For example, Wade-Giles lo² can only represent 羅, luó. isAttestedTone accepts syllables outside its inventory without judging them. Use the inventory sets separately when validating the syllable itself.
INITIALS has 21 entries and FINALS has 41, with isInitial, isFinal and
isPalatalInitial beside them.
Splitting written pinyin
Section titled “Splitting written pinyin”import { readWord, splitSyllables } from "@kensio/pinyinjs";
splitSyllables("nǐhǎo"); // ["nǐ", "hǎo"]splitSyllables("Xī'ān"); // ["Xī", "ān"]splitSyllables("yinhang"); // ["yin", "hang"]splitSyllables("guórén"); // ["guó", "rén"], not ["guór", "én"]splitSyllables("hǎiōu"); // ["hǎi", "ōu"], missing apostrophe, read anywayreadWord("yínháng"); // the same, parsed into Syllable objectsSplitting uses valid syllable forms to choose boundaries. For example, guórén cannot become guór + én because guór is invalid. A missing apostrophe can be recovered when the boundary is unambiguous.
Using tone marks to find boundaries
Section titled “Using tone marks to find boundaries”Tone marks provide additional boundary information:
splitSyllables("bùān"); // ["bù", "ān"], 不安 without its apostrophesplitSyllables("xīan1"); // ["xī", "an1"], 西安 half typedsplitSyllables("xīa"); // ["xīa"], the mark misplaced on one syllableTwo tone marks cannot belong to one syllable. A misplaced mark and a syllable boundary have equal cost, and ties favour the longer syllable. This keeps xīa together. For xīan1, the tone information makes the complete reading cheaper than xīa + n1.
Many Latin letter sequences can be parsed as pinyin, including English words:
readWord("nonsense");// [{ initial: "n", final: "o" }, { initial: "", final: "n" }, … ]Validate the parsed pieces against ATTESTED_SYLLABLES when checking a pinyin input field. A successful readWord call alone does not establish that the input is pinyin.
import { applyToneMark, NEUTRAL_TONE, stripToneMarks, toneFromMarks,} from "@kensio/pinyinjs";
applyToneMark("hao", 3); // "hǎo"applyToneMark("hao", NEUTRAL_TONE); // "hao"applyToneMark("lü", 4); // "lǜ"stripToneMarks("hǎo"); // "hao"stripToneMarks("Xī'ān"); // "Xi'an"toneFromMarks("hǎo"); // 3toneFromMarks("hao"); // undefinedapplyToneMark places the mark on a, otherwise on o or e, otherwise on the last vowel. This puts the mark on u in iu and on i in ui. It replaces an existing mark and leaves text without a vowel unchanged.
undefined and the neutral tone
Section titled “undefined and the neutral tone”Syllable.tone distinguishes an explicit neutral tone from an unspecified tone:
5(NEUTRAL_TONE) means the syllable has neutral tone, as in the particledein 我的.undefinedmeans the input did not specify a tone, as inbeiinbeijing.
For example, toneFromMarks("hao") returns undefined because the spelling contains no tone mark.
From the command line
Section titled “From the command line”$ pinyinjs syllable nǐhǎonǐhǎo nǐ hǎo nǐ n + i, tone 3 nǐ ni3 ni³ hǎo h + ao, tone 3 hǎo hao3 hao³The syllable and sandhi commands run without loading a dictionary.
