-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
345 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,342 @@ | ||
/* 推導《中原音韻》 | ||
* | ||
* 可選四家擬音方案: | ||
* | ||
* - 楊耐思. 中原音韻音系. 北京: 中國社會科學出版社, 1981. | ||
* - 寧繼福. 中原音韻表稿. 長春: 吉林文史出版社, 1985. | ||
* - 薛鳳生. 中原音韻音位系統. 魯國堯, 侍建國, 譯. 北京: 北京語言學院出版社, 1990. | ||
* - unt. 《中原音韻》音系簡述, 2021. https://zhuanlan.zhihu.com/p/353713058 | ||
* | ||
* @author unt | ||
*/ | ||
|
||
const is = (...x) => 音韻地位.屬於(...x); | ||
const when = (...x) => 音韻地位.判斷(...x); | ||
|
||
if (!音韻地位) return [ | ||
['顯示', [5, | ||
'音位(薛鳳生, 1990)', | ||
'音位(unt, 2021)', | ||
'音值(楊耐思, 1981)', | ||
'音值(寧繼福, 1985)', | ||
'音值(unt, 2021)', | ||
]], | ||
['標記古入聲字', true], | ||
['包含部分例外音變', true], | ||
['異讀分隔符(留空則爲換行)', ''], | ||
['高元音開口呼', 選項.顯示?.includes('unt') ?? true ? [2, 'ɨ', 'ə'] : null], | ||
]; | ||
|
||
const 例外 = 選項.包含部分例外音變; | ||
let 層次 = 0; // 本方案只涉及 0 和 1 兩個層次。對入聲來說,0 代表白讀,1 代表文讀 | ||
|
||
function 調整音韻地位() { | ||
function 調整(表達式, 調整屬性) { if (is(表達式)) 音韻地位 = 音韻地位.調整(調整屬性); } | ||
// 輕唇化例外 | ||
調整('明母 尤韻', { 等: '一', 韻: '侯' }); | ||
調整('明母 東韻', { 等: '一' }); | ||
|
||
調整('云母 通攝 平聲', { 母: '匣' }); // 熊 | ||
if (!例外) return; | ||
|
||
// 流攝脣音入遇攝字 | ||
調整('明母 侯韻 上聲', { 韻: '模' }); // 母某牡畝(忽略:謀戊) | ||
調整('尤韻 (並母 平上聲 或 幫滂母 去聲)', { 韻: '虞' }); // 浮、婦阜負、富、副 | ||
|
||
// 蟹攝二等入假攝字 | ||
if (when([ | ||
['佳韻', [ | ||
['並母 上聲', true], // 罷 | ||
['見母 開口 平聲', true], // 佳 | ||
['溪母 合口 平聲', true], // 咼 | ||
['見匣母 合口 去聲', true], // 卦掛、畫 | ||
[層次 === 1 && '疑母 開口 平聲', true], // 涯\崖 | ||
[層次 === 1 && '生母 開口 去聲', true], // 洒\曬 | ||
]], | ||
['夬韻 匣母 合口 去聲', true], // 話 | ||
])) 調整('蟹攝', { 韻: '麻' }); | ||
|
||
調整('端母 蕭韻 上聲', { 母: '泥' }); // 鳥 | ||
調整('生母 山韻 上聲', { 母: '初' }); // 産 | ||
調整('書母 通攝 舒聲', { 母: '昌' }); // 舂 | ||
調整('書母 鍾韻 入聲', { 母: '昌' }); // 束 | ||
if (層次 === 0) 調整('書母 支韻 開口 去聲', { 母: '昌' }); // 翅\施 | ||
調整('見母 蕭韻 平聲', { 母: '曉' }); // 梟鴞驍 | ||
|
||
if (層次 === 0) { | ||
調整('果攝 開口 (定泥母 去聲 或 透母 平聲)', { 韻: '麻', 等: '二' }); // 大那+他 | ||
調整('端母 庚韻 上聲', { 韻: '麻' }); // 打 | ||
} | ||
} | ||
|
||
function get聲母() { | ||
return when([ | ||
[例外, [ | ||
['崇母 止攝 仄聲', 'ʂ'], // 士 | ||
['常母 平聲 (支韻 合口 或 魚尤宵韻)', 'tʂʰ'], // 垂蜍讎韶 | ||
['常母 深攝 平聲', 'ʂ'], // 忱煁 | ||
['船母 平聲 合口', 'tʂʰ'], // 船唇 | ||
[層次 === 1 && '船母 曾攝 舒聲', 'tʂʰ'], // 乗\繩 | ||
|
||
[層次 === 1 && '匣母 寒韻 合口 平聲', ''], // 丸\桓 | ||
['匣母 肴韻 平聲', 'x'], // 爻。《中州樂府音韻類編》與哮小韻陰陽配對,《中州音韻》與遙小韻合併 | ||
['以母 蟹攝 合口', 'ɻ'], // 鋭 | ||
[層次 === 0 && '脂韻 以母 合口 平聲', 'ʋ'], // 惟\遺 | ||
['疑母', [ | ||
['宕攝 三等 開口', 'ŋ'], // 仰、虐瘧 | ||
['山攝 三四等 開口 入聲', 'n'], // 囓臬糵 | ||
['咸攝 三四等 入聲', 'ŋ'], // 業鄴 | ||
[層次 === 1 && '梗攝 二等 入聲', 'ŋ'], // 額 | ||
['效攝 一等 仄聲', 'ŋ'], // 傲奡鏊 | ||
]], // 俺《廣韻》未收,不考慮 | ||
]], | ||
|
||
['東鍾微虞廢文元歌陽尤凡韻 三等 非 重紐A類', [ // “非 重紐A類”用於過濾𩦠小韻,“歌韻”用於包含縛小韻 | ||
['幫滂並母', 'f'], ['明母', 'ʋ'], | ||
]], | ||
['幫母 或 並母 仄聲', 'p'], ['滂並母', 'pʰ'], ['明母', 'm'], | ||
['端母 或 定母 仄聲', 't'], ['透定母', 'tʰ'], ['泥孃母', 'n'], ['來母', 'l'], | ||
['見母 或 羣母 仄聲', 'k'], ['溪羣母', 'kʰ'], ['影疑云以母', ''], ['曉匣母', 'x'], | ||
['精母 或 從母 仄聲', 'ts'], ['清從母', 'tsʰ'], ['心邪俟母', 's'], | ||
|
||
['常母 平聲 陽聲韻', 'tʂʰ'], | ||
['知莊章母 或 澄崇母 仄聲', 'tʂ'], ['徹澄初崇昌母', 'tʂʰ'], ['生俟常書船母', 'ʂ'], ['日母', 'ɻ'], | ||
], '無聲母規則', true); | ||
} | ||
|
||
function get介音() { | ||
let 洪細 = when([ | ||
[例外 && '見影組 二等 開口 梗攝 平聲', [ | ||
['曉母', ''], // 亨 | ||
['匣母 耕韻', ''], // 莖 | ||
[層次 === 1 && '影母', ''], // 甖 | ||
]], | ||
|
||
['幫組 微廢韻', 'j'], | ||
['幫組 東鍾微虞廢文元歌陽尤凡韻 三等 非 重紐A類', ''], | ||
['莊組', ''], | ||
|
||
['宕攝 合口 三等', ''], | ||
['(精章組 或 日母) 止攝 開口', ''], | ||
['通攝 三等 舒聲', [ | ||
['知章組 非 孃母 或 日母', ''], | ||
['見母 或 溪羣母 仄聲', ''], // 弓拱恐共 | ||
[層次 === 1 && '影母 平聲', ''], // 癰廱壅\邕嗈雍 | ||
]], | ||
[層次 === 1 && '(知章組 或 日母) 通攝 入聲 非 孃母', ''], | ||
|
||
['三四等 或 見影組 二等 非 合口', 'j'], | ||
['', ''], | ||
], '無洪細規則', true); | ||
|
||
let 開合 = when([ | ||
[例外, [ | ||
['止蟹攝 四等 合口 匣母 平聲', ''], // 畦携 | ||
['止蟹攝 重紐A類 合口 見母 去聲', ''], // 季 | ||
['脂韻 以母 合口 平聲', ''], // 遺 | ||
[層次 === 1 && '以母 合口 山攝', ''], // 緣沿掾\捐鉛鳶 | ||
[層次 === 1 && '曉匣母 先韻 合口', ''], // 懸縣血 | ||
[層次 === 1 && '清青韻 合口', ''], | ||
|
||
['見組 祭韻 合口', ''], // 鱖 | ||
|
||
[層次 === 0 && '疑母 歌韻 開口 上聲', 'w'], // 我 | ||
[層次 === 1 && '定母 宕江攝 入聲', ''], // 鐸 | ||
[層次 === 0 && '明母 宕江攝 入聲', ''], | ||
['明母 豪韻', ''], | ||
|
||
['止蟹攝 重紐B類 幫母 去聲', 'w'], // 秘祕賁\詖 | ||
['止蟹攝 重紐A類', [ | ||
['幫母 平聲', 'w'], // 卑(避諱) | ||
['幫母 支韻 去聲', 'w'], // 臂 | ||
['並母 仄聲', 'w'], // 婢避幣\斃 | ||
['明母 去聲', 'w'], // 袂寐 | ||
]], | ||
]], | ||
|
||
['幫組', [ | ||
['(宕攝 或 曾攝 一等) 入聲', 'w'], | ||
['一等 非 通宕曾流攝 或 文歌韻', 'w'], | ||
['(止蟹攝 或 臻攝 入聲) 重紐B類', 'w'], // 蟹攝幫三實際上無 B 類 | ||
]], | ||
|
||
['果江攝 銳音 或 宕攝 莊組', 'w'], | ||
[層次 === 1 && '宕攝 入聲 銳音', 'w'], | ||
['合口', 'w'], | ||
['', ''], | ||
], '無開合規則', true); | ||
|
||
return 洪細 + 開合; | ||
} | ||
|
||
function get韻基() { | ||
return when([ | ||
[例外, [ | ||
['心母 止攝 開口 上聲 非 脂韻', 'jəj'], // 璽枲徙\死(避諱) | ||
[層次 === 1 && '昌母 止攝 開口 非 (之韻 上聲 或 支韻 去聲)', 'jəj'], // 蚩媸鴟幟熾\齒(元曲押支思)\\翅施 | ||
['知母 開口 (脂韻 平聲 或 之韻 上聲)', 'ə'], // 胝(元曲無)、徵(元曲押支思) | ||
|
||
[層次 === 0 && '幫滂並母 尤韻 仄聲', 'waw'], // 缶覆 | ||
[層次 === 0 && '滂母 侯韻 上聲', 'waw'], // 剖 | ||
[層次 === 0 && '明母 侯韻 去聲', 'aw'], // 茂 | ||
['泰韻 疑母 合口', 'aj'], // 外 | ||
]], | ||
|
||
['遇攝', 'u'], // 魚模韻 | ||
['止攝 開口 (精莊章組 或 日母)', 'ə'], // 支思韻 | ||
['果攝 (一等 或 幫組 三等)', 'ʌ'], // 歌戈韻 | ||
['假攝 二等', 'a'], // 家麻韻 | ||
['果假攝 三等', 'ɛ'], // 車遮韻 | ||
|
||
['蟹攝 (一等 開口 或 二等 或 莊組) 或 止攝 莊組', 'aj'], // 皆來韻 | ||
['止蟹攝', 'əj'], // 齊微韻 | ||
|
||
['流攝', 'əw'], // 尤侯韻 | ||
['效攝 (一二等 或 莊組)', 'aw'], // 蕭豪韻·一二等 | ||
['效攝 三四等', 'ɛw'], // 蕭豪韻·三四等 | ||
|
||
['舒聲', [ | ||
[例外 && 層次 === 1 && '曾梗攝 一二等 非 開口 或 庚韻 三等 合口', 'uŋ'], | ||
['通攝', 'uŋ'], // 東鍾韻 | ||
['宕江攝', 'aŋ'], // 江陽韻 | ||
['曾梗攝', 'əŋ'], // 庚青韻 | ||
|
||
['臻攝 非 元韻', 'ən'], // 真文韻 | ||
['山攝 一等 非 開口', 'ʌn'], // 桓歡韻 | ||
['山攝 (一二等 或 莊組) 或 元韻 幫組', 'an'], // 寒山韻 | ||
['山攝 三四等 或 元韻', 'ɛn'], // 先天韻 | ||
|
||
['深攝', is`幫組` ? 'ən' : 'əm'], // 侵尋韻 | ||
['咸攝 (一二等 或 莊組) 或 嚴凡韻 幫組', is`幫組` ? 'an' : 'am'], // 監咸韻 | ||
['咸攝 三四等', is`幫組` ? 'ɛn' : 'ɛm'], // 廉纖韻 | ||
]], | ||
['入聲', [ | ||
['通攝', [ | ||
[層次 === 0 && '(精知章莊組 或 來日母) 東韻 三等', 'əw'], | ||
[層次 === 0 && '(知章莊組 或 日母) 鍾韻', 'əw'], // 燭褥+贖屬(元曲押魚模、尤侯)\辱(元曲只押魚模) | ||
['', 'u'], | ||
]], | ||
['宕江攝', [ | ||
[層次 === 1, 'ʌ'], | ||
['', 'aw'], | ||
]], | ||
|
||
[例外, [ | ||
[層次 === 1 && '登韻 心母', 'ə'], // 塞(元曲押齊微) | ||
[層次 === 1 && '登韻 精母', 'aj'], // 則(元曲押齊微) | ||
[層次 === 1 && '曾梗攝 一等 溪母 開口', 'jaj'], // 刻(元曲押齊微、皆來) | ||
[層次 === 1 && '曾梗攝 二等 溪疑母 開口', 'ɛ'], // 客(元曲押皆來、車遮)、額(元曲只押皆來) | ||
[層次 === 0 && '文韻 並母', 'ʌ'], // 佛(元曲押魚模、歌戈) | ||
['臻攝 一等 幫組 非 明母', 'ʌ'], // 勃 | ||
[層次 === 0 && '日母 深攝', 'u'], // 入 | ||
]], | ||
['臻攝 (一等 或 文韻 幫組 或 合口 非 元韻)', 'u'], // +麧(《中原音韻》未收) | ||
['臻深攝 莊組 開口', 'ə'], | ||
['曾梗臻深攝 (二等 或 莊組)', 'aj'], | ||
['曾梗臻深攝 非 元韻', 'əj'], | ||
['山咸攝 一等 非 (銳音 開口)', 'ʌ'], | ||
['山咸攝 (一二等 或 莊組) 或 元嚴凡韻 幫組', 'a'], | ||
['山咸攝 三四等 或 元韻', 'ɛ'], | ||
]], | ||
], '無韻基規則', true); | ||
} | ||
|
||
function get聲調() { | ||
return when([ | ||
[例外, [ | ||
['匣母 蟹攝 上聲 開口', '³'], // 駭蟹\解獬 | ||
['羣母 臻攝 上聲 合口 非 元韻', '³'], // 窘 | ||
|
||
['羣母 梗攝 三等 開口 入聲', '⁴ʼ'], // 劇 | ||
['生母 山攝 合口 入聲', '⁴ʼ'], // 刷 | ||
['影疑母 通臻攝 一等 入聲 非 開口', '³ʼ'], // 屋沃兀 | ||
[層次 === 0 && '影母 眞韻 重紐A類 開口 入聲', '³ʼ'], // 一 | ||
]], | ||
['平聲 (全清 或 次清)', '¹'], | ||
['平聲 (全濁 或 次濁)', '²'], | ||
['上聲 非 全濁', '³'], | ||
['上去聲', '⁴'], | ||
['入聲', [ | ||
['全濁', '²ʼ'], | ||
['次濁 或 影母', '⁴ʼ'], // 影母入聲《中原音韻》按次濁歸派 | ||
['', '³ʼ'], | ||
]], | ||
], '無聲調規則', true); | ||
} | ||
|
||
function get音節() { | ||
function 批量替換(str, pairs) { | ||
pairs.forEach(pair => { str = str.replace(new RegExp(pair[0], 'g'), pair[1]); }); | ||
return str; | ||
} | ||
let 聲母 = get聲母(); | ||
let 韻母 = get介音() + get韻基(); | ||
let 聲調 = get聲調(); | ||
韻母 = 韻母.replace('wu', 'u'); | ||
韻母 = 韻母.replace('jwəj', 'wəj'); | ||
韻母 = 韻母.replace('jʌ', 'jwʌ'); | ||
|
||
if (選項.顯示.includes('unt')) { | ||
if (選項.顯示.includes('音值')) { | ||
韻母 = 批量替換(韻母, [ | ||
['jw', 'ɥ'], ['əj', 'əi'], | ||
['jə', 'i'], ['ii', 'i'], | ||
['wə', 韻母.includes('ŋ') ? 'wə' : 'u'], | ||
['ɥə', 韻母.includes('ŋ') ? 'ɥi' : 'y'], | ||
['wʌ', 'wɔ'], ['ɥʌ', 'jɔ'], | ||
]); | ||
if (韻母 === 'ə' && 選項.高元音開口呼 === 'ə') 韻母 = 聲母.includes('s') ? 'ɹ̩' : 'ɻ̍'; | ||
if ('pmfʋ'.includes(聲母[0])) 韻母 = 韻母.replace('wɔ', 'ɔ'); | ||
if ('tnlsʂɻ'.includes(聲母[0]) && 韻母 === 'wɔ') 韻母 = 'ɔ'; | ||
} | ||
韻母 = 韻母.replace('ə', 選項.高元音開口呼); | ||
} else if (選項.顯示.includes('楊耐思')) { | ||
聲母 = 批量替換(聲母, [['ʰ', 'ʻ'], ['ʋ', 'v'], ['ʂ', 'ʃ'], ['ɻ', 'ʒ']]); | ||
韻母 = 批量替換(韻母, [ | ||
['j', 'i'], ['w', 'u'], | ||
['əi', 'ei'], ['iei', 'i'], | ||
['uau', ['k', 'kʻ', '', 'ŋ', 'x'].includes(聲母) ? 'uau' : 'au'], | ||
['iau', ['k', 'kʻ', '', 'ŋ', 'x'].includes(聲母) ? 'iau' : 'iɛu'], | ||
['ʌ', 'o'], ['iuo', 'io'], ['uon', 'on'], | ||
['ia', 'i̯a'], ['i̯aŋ', 'iaŋ'], | ||
]); | ||
if (韻母 === 'ə') 韻母 = 'ï'; | ||
} else if (選項.顯示.includes('寧繼福')) { | ||
聲母 = 批量替換(聲母, [['ʰ', 'ʻ'], ['ɻ', 'ɽ']]); | ||
韻母 = 批量替換(韻母, [ | ||
['j', 'i'], ['w', 'u'], | ||
['iəi', 'i'], ['uəi', 'ui'], ['əi', 'ei'], | ||
['uau', 'pmfʋ'.includes(聲母[0]) ? 'ɑ-u' : 'a-u'], // - 用於佔位 | ||
['iau', 聲調.includes('ʼ') ? 'ia-u' : 'a-u'], | ||
['au', 聲母.includes('ʂ') || 'pmfʋ'.includes(聲母[0]) ? 'au' : 'ɑu'], | ||
['iɛu', 'iau'], ['-u', 'u'], | ||
['ʌ', 'ɔ'], ['iuɔ', 'iɔ'], | ||
]); | ||
if (韻母 === 'ə') 韻母 = 'ï'; | ||
if ('pmfʋ'.includes(聲母[0]) && !'iu'.includes(韻母[0]) && !'iu'.includes(韻母.slice(-1))) 韻母 = 'u' + 韻母; | ||
if (is`孃母 效攝`) 韻母 = 'au'; | ||
} else if (選項.顯示.includes('薛鳳生')) { | ||
聲母 = 批量替換(聲母, [['ʰ', 'h'], ['ʋ', 'v'], ['ʂ', 'sr'], ['ɻ', 'r'], ['ts', 'c'], ['x', 'h']]); | ||
韻母 = 批量替換(韻母, [ | ||
['j', 'y'], | ||
['əŋ', 'eŋ'], ['ə', 'ɨ'], ['ɛ', 'e'], | ||
['uŋ', 'woŋ'], ['u', 'wɨ'], ['ʌ', 'o'], | ||
['waw', 聲母.includes('r') ? 'ow' : 'wow'], | ||
['aw', 聲母.includes('r') || 'pmfv'.includes(聲母[0]) ? 'aw' : 'ow'], ['yow', 'yaw'], | ||
]); | ||
if ('pmfv'.includes(聲母[0]) && !'yw'.includes(韻母[0])) 韻母 = 'w' + 韻母; | ||
if (is`孃母 效攝`) 韻母 = 'aw'; | ||
} | ||
|
||
if (!選項.標記古入聲字) 聲調 = 聲調[0]; | ||
return 聲母 + 韻母 + 聲調; | ||
} | ||
|
||
const 音韻地位備份 = 音韻地位; | ||
const 結果 = [0, 1].map(i => { | ||
層次 = i; | ||
音韻地位 = 音韻地位備份; | ||
調整音韻地位(); | ||
return get音節(); | ||
}); | ||
return [...new Set(結果)].join(選項['異讀分隔符(留空則爲換行)'] || '\n'); |