Skip to content

Commit

Permalink
Add new 選項 to chiangxhua.js
Browse files Browse the repository at this point in the history
  • Loading branch information
untunt committed Aug 1, 2021
1 parent 1223f3b commit e3dadfb
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 72 deletions.
167 changes: 96 additions & 71 deletions chiangxhua.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ const is = (x) => 音韻地位.屬於(x.replace(/ +/g, ' ').replace(/ /g, '').

if (!音韻地位) return [
['顯示', [3, '音位', '音值', '音位及音值']],
['聲調用調類表示', false], // 打開則用 ¹²³⁴ 表示(分別為平上去入),關閉則用國際音標的附加符號表示
['省略唇音後的w介音', true], // 僅用於音值。打開則“八”/pʕʷɐ/ -> [pa],關閉則 /pʕʷɐ/ -> [pwa]
['知照組使用', [1, '齦腭音', '捲舌音']],
['三個元音音位使用', [1, 'ə ɐ ɵ', 'ə ɐ o']],
['聲調使用', [1, '附加符號', '調類數字']], // 調類數字用 ¹²³⁴ 表示(分別為平上去入),附加符號用國際音標的附加符號表示
['全濁上歸陽去', true], // 推斷
['山攝二等唇音歸合口', false], // 打開則“八”/pʕʷɐ/,關閉則 /pʕɐ/
];

function 聲母規則() {
Expand All @@ -31,24 +34,24 @@ function 聲母規則() {
if (is('定 母 平聲')) return 'dʰ';
if (is('泥孃母 上聲')) return 'ˀn';
if (is('泥孃母   ')) return 'n';
if (is('知 母   ')) return '';
if (is('徹 母   ')) return 'tɻʰ';
if (is('澄 母 仄聲')) return '';
if (is('澄 母 平聲')) return 'dɻʰ';
if (is('知 母   ')) return '';
if (is('徹 母   ')) return 'tɹʰ';
if (is('澄 母 仄聲')) return '';
if (is('澄 母 平聲')) return 'dɹʰ';
if (is('精 母   ')) return 'ts';
if (is('清 母   ')) return 'tsʰ';
if (is('從 母 仄聲')) return 'dz';
if (is('從 母 平聲')) return 'dzʰ';
if (is('心 母   ')) return 's';
if (is('邪 母   ')) return 'z';
if (is('莊章母   ')) return '';
if (is('初昌母   ')) return 'tʂʰ';
if (is('崇 母 仄聲') && '撰饌棧助寨砦乍狀驟'.includes(字頭)) return ''; // 特例:乍
if (is('船 母 平聲') && '晨船荼乘'.includes(字頭)) return 'dʐʰ'; // 推斷的特例
if (is('崇常母 平聲')) return 'dʐʰ';
if (is('生書母   ')) return 'ʂ';
if (is('崇常母 仄聲')) return 'ʐ';
if (is('俟船母   ')) return 'ʐ';
if (is('莊章母   ')) return '';
if (is('初昌母   ')) return 'tɕʰ';
if (is('崇 母 仄聲') && '撰饌棧助寨砦乍狀驟'.includes(字頭)) return ''; // 特例:乍
if (is('船 母 平聲') && '晨船荼乘'.includes(字頭)) return 'dʑʰ'; // 推斷的特例
if (is('崇常母 平聲')) return 'dʑʰ';
if (is('生書母   ')) return 'ɕ';
if (is('崇常母 仄聲')) return 'ʑ';
if (is('俟船母   ')) return 'ʑ';
if (is('見 母   ')) return 'k';
if (is('溪 母   ')) return 'kʰ';
if (is('羣 母 仄聲')) return 'ɡ';
Expand All @@ -64,8 +67,8 @@ function 聲母規則() {
if (is('云以母   ')) return '';
if (is('來 母 上聲')) return 'ˀl';
if (is('來 母   ')) return 'l';
if (is('日 母 上聲')) return 'ˀɻ';
if (is('日 母   ')) return 'ɻ';
if (is('日 母 上聲')) return 'ˀɹ';
if (is('日 母   ')) return 'ɹ';
throw new Error('無聲母規則');
}

Expand All @@ -75,13 +78,13 @@ function 介音規則() {
// II 等:ʕ
// I 等:無
if (is('端精組 或 孃來母')) {
if (is('泥母 咍韻 開口 上聲')) return ''; // 特例:乃。可能是因為 II 等被“嬭”小韻(中古孃母)佔據了。來母蟹攝二等僅“唻”一字,推測不影響咍泰韻 II 等化,故不考慮來母
if (is('泥母 咍韻 開口 上聲')) return ''; // 特例:乃。可能是因為 II 等被“嬭”小韻(中古孃母)佔據了。來母蟹攝二等僅“唻”一字,且它實際上是一等音,故不影響咍泰韻 II 等化
if (is('泥母 咍泰韻 開口')) return ''; // 據“乃”類推
if (is('二等 或 咍泰寒覃談韻 開口')) return 'ʕ';
if (is('一等')) return '';
if (is('精組 止攝 開口')) return ''; // 中古後期發生 sjᵻ & sɉᵻ > sᵻ,變 I 等
if (is('精組 止攝 開口')) return ''; // 中古後期發生 sjə & sɉə > ,變 I 等
if (is('三四等')) return 'ɉ'; // 一律歸 III 等
};
}
if (is('知組 二等 或 莊組')) return 'ʕ';
if (is('知組 三等 或 章組 或 日母')) return 'ɉ';
// “茝、佁”之類字不作考慮
Expand All @@ -99,71 +102,73 @@ function 介音規則() {
}

function 唇化規則() {
if (is('止臻攝 幫組 重紐B類')) return 'ʷ'; // 幫組 III 等推測已經發生了 > ᵻj 的裂化(和見組合口 > ᵻj 平行)。ᵻj III、IV 等舒聲只有合口
if (is('止臻攝 幫組 重紐B類')) return 'ʷ'; // 幫組 III 等推測已經發生了 ə > əj 的裂化(和見組合口 ə > əj 平行)。əj III、IV 等舒聲只有合口
if (is('幫組 流通深咸攝')) return ''; // 幫組一等除這四攝外,都算合口
if (is('幫組 二等 梗蟹攝')) return ''; // 幫組二等這兩攝非常不像合口,不算合口
if (is('幫組 一二等 或 合口 或 鍾虞模韻')) return 'ʷ'; // 其他一二等推測都算合口
if (is('幫組 一等 或 合口 或 鍾虞模韻')) return 'ʷ'; // 其他一二等推測都算合口
if (is('幫組 鍾虞文陽韻')) return 'ʷ'; // 輕唇變一等的
if (is('幫組 元韻')) return 'ʷ'; // 輕唇變二等的(凡韻已經被排除),也是合口。因為“八”列在合口
// 注意,咸深攝舒聲入聲都視為開口,不依原圖定義

// 原圖“八”列在合口,而《韻鏡》、《七音略》刪韻舒聲和山韻入聲幫組字也列在合口(但刪入山舒列在開口)
// 這裡如果開關打開,山攝二等就一律視為合口
if (選項.山攝二等唇音歸合口 && is('幫組 二等 山攝 或 幫組 元韻')) return 'ʷ';

if (is('江韻 知莊組 或 江韻 孃來母')) return 'ʷ'; // 據《蒙古字韻》推斷,且“雙、霜”需要靠開合對立
return '';
}

function 韻基規則() {
// 遇攝
if (is('遇攝     ')) return 'ʊ ';
if (is('遇攝     ')) return 'ɵ ';
// 止攝
if (is('止攝 幫組 重紐B類')) return 'ᵻj'; // 幫組 III 等推測已經發生了 > ᵻj 的裂化(和見組合口 > ᵻj 平行)
if (is('止攝 莊組  ')) return ' '; // 衰、帥
if (is('止攝 合口  ')) return 'ᵻj';
if (is('止攝     ')) return ' '; // [i] 的音位也可分析为 jᵻj,但邵雍的分析是 jᵻ,排在 韻基一行
if (is('止攝 幫組 重紐B類')) return 'əj'; // 幫組 III 等推測已經發生了 ə > əj 的裂化(和見組合口 ə > əj 平行)
if (is('止攝 莊組  ')) return 'ə '; // 衰、帥
if (is('止攝 合口  ')) return 'əj';
if (is('止攝     ')) return 'ə '; // [i] 的音位也可分析为 jəj,但邵雍的分析是 ,排在 ə 韻基一行
// 蟹攝
if (is('蟹攝 一二等 ')) return 'ɐj'; // 二等今讀 [a] 的字不作考慮
if (is('蟹攝 合口  ')) return 'ᵻj'; // 三四等合口。推斷
if (is('蟹攝     ')) return ' '; // 三四等開口。“妻”排在 韻基一行,說明 [jej] 之類的音已經併入 [i]
if (is('蟹攝 合口  ')) return 'əj'; // 三四等合口。推斷
if (is('蟹攝     ')) return 'ə '; // 三四等開口。“妻”排在 ə 韻基一行,說明 [jej] 之類的音已經併入 [i]
// 果假攝
if (is('果假攝    ')) return 'ɐ ';
// 流攝
if (is('流攝     ')) return 'ᵻw';
if (is('流攝     ')) return 'ɵw';
// 效攝
if (is('效攝     ')) return 'ɐw';
// 臻攝
if (is('臻攝 幫組 重紐B類 入聲')) return 'ᵻj'; // 推測和止攝一樣 > ᵻj(“筆”)
if (is('臻攝 幫組 重紐B類 入聲')) return 'əj'; // 推測和止攝一樣 ə > əj(“筆”)
if (is('元韻     ')) return is('舒聲') ? 'ɐn' : 'ɐ ';
if (is('臻攝     ')) return is('舒聲') ? 'ᵻn' : ' '; // ʊ 無入聲,推斷文韻幫組入聲韻基只能是 。就像南昌話“骨”經歷 kut > kul > kuɨʔ > kuʔ 的演變。入聲(“紇”)韻基也推測為
if (is('臻攝     ')) return is('舒聲') ? 'ən' : 'ə '; // ɵ 無入聲,推斷文韻幫組入聲韻基只能是 ə。就像南昌話“骨”經歷 kut > kul > kuɨʔ > kuʔ 的演變。入聲(“紇”)韻基也推測為 ə
// 山攝
if (is('山攝     ')) return is('舒聲') ? 'ɐn' : 'ɐ ';
// 曾梗攝
if (is('曾梗攝 一二等')) return is('舒聲') ? 'ᵻŋ' : 'ᵻj'; // 入聲韻基為推測,因為“窄、虱”今不同韻所以韻基不能是
if (is('曾梗攝    ')) return is('舒聲') ? 'ᵻŋ' : ' '; // 三四等。開口入聲只能是 [i],合口入聲也推測為 。《蒙古字韻》中合口入聲是 ᵻj 韻基(ÿue 或 ue),但現代方言未見,不採用
if (is('曾梗攝 一二等')) return is('舒聲') ? 'əŋ' : 'əj'; // 入聲韻基為推測,因為“窄、虱”今不同韻所以韻基不能是 ə
if (is('曾梗攝    ')) return is('舒聲') ? 'əŋ' : 'ə '; // 三四等。開口入聲只能是 [i],合口入聲也推測為 ə。《蒙古字韻》中合口入聲是 əj 韻基(ÿue 或 ue),但現代方言未見,不採用
// 通攝
if (is('通攝     ')) return is('舒聲') ? 'ʊŋ' : 'ᵻw'; // ʊ 無入聲,推斷東一入聲韻基只能是 ᵻw。又推斷冬韻併入東一
if (is('通攝     ')) return is('舒聲') ? 'ɵŋ' : 'ɵw'; // ɵ 無入聲,推斷東一入聲韻基只能是 əw。又推斷冬韻併入東一
// 宕江韻
if (is('宕江攝    ')) return is('舒聲') ? 'ɐŋ' : 'ɐw';
// 深攝
if (is('深攝     ')) return is('舒聲') ? 'ᵻm' : 'ᵻʋ'; // 南昌話“骨”kul 也可以視為和“滾、棍”kun 只有聲調差別(因為 n、l 是同一音位)。這裡 ʋ 就是聲母中的微母,它有鼻音變體絲毫不奇怪
if (is('深攝     ')) return is('舒聲') ? 'əm' : 'əʋ'; // 南昌話“骨”kul 也可以視為和“滾、棍”kun 只有聲調差別(因為 n、l 是同一音位)。這裡 ʋ 就是聲母中的微母,它有鼻音變體絲毫不奇怪
// 咸攝
if (is('咸攝     ')) return is('舒聲') ? 'ɐm' : 'ɐʋ';
throw new Error('無韻基規則');
}

function 聲調規則() {
if (is('平聲   ')) return '̀';
if (is('上聲 全濁')) return '̌'; // 推斷全濁上已經歸陽去
if (is('上聲   ')) return '́';
if (is('去聲   ')) return '̌';
if (is('入聲   ')) return '̆';
if (選項.全濁上歸陽去 && is('上聲 全濁')) return '̌';
if (is('平聲')) return '̀';
if (is('上聲')) return '́';
if (is('去聲')) return '̌';
if (is('入聲')) return '̆';
throw new Error('無聲調規則');
}

function 調類規則() {
if (is('平聲   ')) return '¹';
if (is('上聲 全濁')) return '³'; // 推斷全濁上已經歸陽去
if (is('上聲   ')) return '²';
if (is('去聲   ')) return '³';
if (is('入聲   ')) return '⁴';
if (選項.全濁上歸陽去 && is('上聲 全濁')) return '³';
if (is('平聲')) return '¹';
if (is('上聲')) return '²';
if (is('去聲')) return '³';
if (is('入聲')) return '⁴';
throw new Error('無聲調規則');
}

Expand All @@ -173,63 +178,83 @@ let 唇化 = 唇化規則();
let 韻基 = 韻基規則().trim(); // 移除韻母末尾可能的空格
let 韻核 = 韻基[0];
let 韻尾 = 韻基.substring(1);
let 聲調 = 選項.聲調用調類表示 ? 調類規則() : 聲調規則();
let 聲調 = 選項.聲調使用 === '調類數字' ? 調類規則() : 聲調規則();

let 音位 = '';
let 音值 = '';

if (選項.聲調用調類表示) {
if (選項.知照組使用 === '捲舌音') {
聲母 = 聲母.replace('ɹ', 'ɻ');
聲母 = 聲母.replace('ɕ', 'ʂ');
聲母 = 聲母.replace('ʑ', 'ʐ');
}

if (選項.三個元音音位使用 === 'ə ɐ o') {
韻核 = 韻核.replace('ɵ', 'o');
}

if (選項.聲調使用 === '調類數字') {
音位 = 聲母 + 介音 + 唇化 + 韻核 + 韻尾 + 聲調;
} else {
音位 = 聲母 + 介音 + 唇化 + 韻核 + 聲調 + 韻尾;
}

if (選項.顯示 === '音位') return 音位;

// 接下來對音位應用音系規則,生成音值

// /ʊ/ 的實現與等無關,單獨處理
if (韻核 === 'ʊ' && 唇化) {
// 虞模的實現與等無關,單獨處理
if ('ɵo'.includes(韻核) && 韻尾 === '' && 唇化) {
韻核 = 'u';
}

// // 和 /ɐ/ 的實現
// /ə/ 和 /ɐ/ 的實現
if (介音 === 'j') { // IV 等
if (韻核 === '') {
if (韻核 === 'ə') {
if (韻尾 === 'ʋ' || 韻尾 === 'm') {
韻核 = 'ɨ';
} else if (唇化 && 'jw'.includes(韻尾)) { // 合口,且韻尾是 j、w 或無韻尾
} else if (唇化 && (韻尾 === 'j' || 韻尾 === '')) {
韻核 = 'ʉ';
} else {
韻核 = 'i';
}
} else if (韻核 === 'ɐ' && 韻尾 !== 'ŋ') { // jɐŋ 仍是 jɐŋ
韻核 = 'ɛ';
} else if (韻核 === 'ɐ') {
if (韻尾 !== 'ŋ') {
韻核 = 'ɛ';
} // jɐŋ 仍是 jɐŋ
} else { // ɵ 韻核
if (韻尾) {
韻核 = 韻尾 === 'w' && !唇化 ? 'i' : 'ʉ';
}
}
} else if (介音 === 'ɉ') { // III 等
if (韻核 === 'ᵻ') {
韻核 = 唇化 ? 'ʉ' : 'ɨ';
} // III 等 /ɐ/ 就實現為 [ɐ]
if (韻核 === 'ə') {
韻核 = 唇化 && 韻尾 !== 'ŋ' ? 'ʉ' : 'ɨ';
} else if (韻核 !== 'ɐ') { // III 等 /ɐ/ 就實現為 [ɐ]
if (韻尾) {
韻核 = 韻尾 === 'w' && !唇化 ? 'ɨ' : 'ʉ';
}
}
} else if (介音 === 'ʕ') { // II 等
if (韻核 === '') {
if (韻核 === 'ə') {
if (韻尾 === 'j' || 韻尾 === 'ŋ') {
韻核 = 'ɛ'; // 構擬音值介於 [ɛ]、[ɜ] 之間,寫 [ɛ]
} else if (韻尾 === '') {
if (唇化) {
韻核 = 'ɛ';
韻尾 = ';
韻尾 = 選項.知照組使用 === '捲舌音' ? 'ɻ' : ';
} else {
韻核 = 'ɻ̍';
韻核 = 選項.知照組使用 === '捲舌音' ? 'ɻ̍' : 'ɹ̩';
}
} else {
韻核 = 唇化 ? 'u' : '; // 同 I 等
} else if (唇化) {
韻核 = 'u'; // 同 I 等
}
} else if (韻核 === 'ɐ') {
韻核 = 'a';
}
} else { // I 等
if (韻核 === 'ᵻ') {
韻核 = 唇化 ? 'u' : 'ə';
if (韻核 === 'ə') {
if (唇化) {
韻核 = 'u';
}
if (韻尾 === '') {
if (is('精組') && !唇化) {
韻核 = 'ɹ̩';
Expand Down Expand Up @@ -264,11 +289,11 @@ if (唇化) {
if (介音[0] === 'j') {
介音 = 介音.replace('j', 'ɥ'); // III、IV 等
} else {
介音 = is('幫組') && 選項.省略唇音後的w介音 ? '' : 'w'; // I、II 等直接是 w 介音,但唇音后省略
介音 = 'w'; // I、II 等直接是 w 介音
}
}

if (選項.聲調用調類表示) {
if (選項.聲調使用 === '調類數字') {
音值 = 聲母 + 介音 + 韻核 + 韻尾 + 聲調;
} else {
音值 = 聲母 + 介音 + 韻核 + 聲調 + 韻尾;
Expand All @@ -280,6 +305,6 @@ if (選項.聲調用調類表示) {
音值 = 音值.replace('ɥ̈ʉ', 'ʉ');
音值 = 音值.replace('wu', 'u');

if (選項.顯示 === '音位') return 音位;
if (選項.顯示 === '音值') return 音值;

return 音位 + ' \n[' + 音值 + ']';
2 changes: 1 addition & 1 deletion test/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ assert_equal(panwuyun(音韻地位), "ɕiɛu˧˥");
assert_equal(unt(音韻地位), "ɕjɛw˦˦˥");
assert_equal(unt_j(音韻地位), "ɕe̋w");
assert_equal(msoeg_v8(音韻地位), "çiɛuˀ");
assert_equal(chiangxhua(音韻地位), "ʂɉɐ́w \n[ʂj̈ɐ́w]");
assert_equal(chiangxhua(音韻地位), "ɕɉɐ́w \n[ɕj̈ɐ́w]");
assert_equal(fanwan(音韻地位), "shiu2");
assert_equal(zaonhe(音韻地位), "sɔ̄");
assert_equal(putonghua(音韻地位), "shao3");
Expand Down

0 comments on commit e3dadfb

Please sign in to comment.