From bafc1c20aa014d87b31a46da0189041ecfa59af1 Mon Sep 17 00:00:00 2001 From: mkpoli Date: Wed, 23 Dec 2020 22:27:55 +0900 Subject: [PATCH 01/11] Add Japanese Kanon --- japanese-kanon.js | 334 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 334 insertions(+) create mode 100644 japanese-kanon.js diff --git a/japanese-kanon.js b/japanese-kanon.js new file mode 100644 index 0000000..6386b25 --- /dev/null +++ b/japanese-kanon.js @@ -0,0 +1,334 @@ +/* 推導日語漢音 + * + * 説明 + * 以下代碼爲生成推導日語漢音的函數體 + * + * 以字音假名遣形式表示,拗音用對應的小假名表示 + * + * 有開關可控制:-m -n 之分、-wi -we 合拗音、wiwe 小假名表示、狂 ク𛅥ャウ vs キャウ + * + * 函數接受音韻地位,返回對應的推導日語漢音 + * + */ + +const is = (x) => 音韻地位.屬於(x); + +const 開關 = {}; + +開關.分mn = true; // 開:サム 關:サン +開關.wiwe = true; // 開:ク𛅥ン 關:ケン +開關.小假名wiwe = true; // 開:ク𛅥ン 關:クヱン +開關.kwiyau = true; // 開:ク𛅥ャウ 關:キャウ + +function 聲母規則() { + if (is('幫母')) return 'f'; + if (is('滂母')) return 'f'; + if (is('並母')) return 'f'; + if (is('明母')) return 'm'; + if (is('端母')) return 't'; + if (is('透母')) return 't'; + if (is('定母')) return 't'; + if (is('泥母')) return 'd'; + if (is('知母')) return 't'; + if (is('徹母')) return 't'; + if (is('澄母')) return 't'; + if (is('孃母')) return 'd'; + if (is('精母')) return 's'; + if (is('清母')) return 's'; + if (is('從母')) return 's'; + if (is('心母')) return 's'; + if (is('邪母')) return 's'; + if (is('莊母')) return 's'; + if (is('初母')) return 's'; + if (is('崇母')) return 's'; + if (is('生母')) return 's'; + if (is('俟母')) return 's'; + if (is('章母')) return 's'; + if (is('昌母')) return 's'; + if (is('船母')) return 's'; + if (is('書母')) return 's'; + if (is('常母')) return 's'; + if (is('見母')) return 'k'; + if (is('溪母')) return 'k'; + if (is('羣母')) return 'k'; + if (is('疑母')) return 'g'; + if (is('影母')) return '0'; + if (is('曉母')) return 'k'; + if (is('匣母')) return 'k'; + if (is('云母')) return '0'; + if (is('以母')) return '0'; + if (is('來母')) return 'r'; + if (is('日母')) return 'z'; + throw new Error('無聲母規則'); +} + +function 韻母規則() { + // 果攝 + if (is('開口 一等 歌韻')) return 'a'; + if (is('開口 三等 戈韻')) return 'a'; + if (is('合口 一等 戈韻')) return 'wa'; + if (is('合口 三等 戈韻')) return 'wa'; + // 假攝 + if (is('開口 二等 麻韻')) return 'a'; + if (is('開口 三等 麻韻')) return 'ya'; + if (is('合口 二等 麻韻')) return 'wa'; + // 遇攝 + if (is('一等 模韻')) return 'o'; + if (is('三等 魚韻')) return is('莊組') ? 'o' : 'yo'; + if (is('三等 虞韻')) return is('幫見影組') ? 'u' : (is('知組') ? 'yuu' : 'yu'); + // 蟹攝 + if (is('開口 一等 咍韻')) return 'ai'; + if (is('開口 二等 佳韻')) return 'ai'; + if (is('開口 二等 皆韻')) return 'ai'; + if (is('開口 四等 齊韻')) return 'ei'; + if (is('開口 一等 泰韻')) return 'ai'; + if (is('開口 二等 夬韻')) return 'ai'; + if (is('開口 三等 祭韻')) return 'ei'; + if (is('開口 三等 廢韻')) return 'ai'; + if (is('合口 一等 灰韻')) return 'wai'; + if (is('合口 二等 佳韻')) return 'wai'; + if (is('合口 二等 皆韻')) return 'wai'; + if (is('合口 四等 齊韻')) return 'wei'; + if (is('合口 一等 泰韻')) return 'wai'; + if (is('合口 二等 夬韻')) return 'wai'; + if (is('合口 三等 祭韻')) return 'wei'; + if (is('合口 三等 廢韻')) return 'wai'; + // 止攝 + if (is('開口 三等 支韻')) return 'i'; + if (is('開口 三等 脂韻')) return 'i'; + if (is('開口 三等 之韻')) return 'i'; + if (is('開口 三等 微韻')) return 'i'; + if (is('合口 三等 支韻 重紐A類')) return 'i'; + if (is('合口 三等 支韻')) return 'wi'; + if (is('合口 三等 脂韻 重紐A類')) return 'i'; + if (is('合口 三等 脂韻')) return 'wi'; + if (is('合口 三等 微韻')) return 'wi'; + // 效攝 + if (is('一等 豪韻 幫組')) return 'ou'; + if (is('一等 豪韻')) return 'au'; + if (is('二等 肴韻')) return 'au'; + if (is('三等 宵韻')) return 'eu'; + if (is('四等 蕭韻')) return 'eu'; + // 流攝 + if (is('一等 侯韻')) return 'ou'; + if (is('三等 尤韻')) return is('幫組') ? (is('明母') ? 'ou' : 'uu') : 'iu'; + if (is('三等 幽韻')) return 'iu'; + // 咸攝 + if (is('開口 一等 談韻')) return 'am'; + if (is('開口 二等 銜韻')) return 'am'; + if (is('開口 二等 咸韻')) return 'am'; + if (is('開口 三等 鹽韻')) return 'em'; + if (is('開口 三等 嚴韻')) return 'em'; + if (is('開口 四等 添韻')) return 'em'; + if (is('開口 一等 覃韻')) return 'am'; + if (is('合口 三等 凡韻')) return 'am'; + // 深攝 + if (is('三等 侵韻')) return 'im'; + // 山攝 + if (is('開口 一等 寒韻')) return 'an'; + if (is('開口 二等 刪韻')) return 'an'; + if (is('開口 二等 山韻')) return 'an'; + if (is('開口 三等 仙韻')) return 'en'; + if (is('開口 四等 先韻')) return 'en'; + if (is('合口 一等 桓韻')) return 'wan'; + if (is('合口 二等 刪韻')) return 'wan'; + if (is('合口 二等 山韻')) return 'wan'; + if (is('合口 三等 仙韻')) return 'wen'; + if (is('合口 四等 先韻')) return 'wen'; + // 臻攝 + if (is('開口 一等 痕韻')) return 'on'; + if (is('開口 三等 眞韻')) return 'in'; + if (is('開口 三等 臻韻')) return 'in'; + if (is('開口 三等 欣韻')) return 'in'; + if (is('開口 三等 元韻')) return 'en'; + if (is('合口 一等 魂韻')) return 'on'; + if (is('合口 三等 眞韻')) return 'win'; + if (is('合口 三等 諄韻 重紐A類')) return 'in'; + if (is('合口 三等 諄韻')) return is('來母') ? 'in' : 'yun'; + if (is('合口 三等 文韻')) return 'un'; + if (is('合口 三等 元韻')) return is('幫組') ? 'wan' : 'wen'; + // 宕攝 + if (is('開口 一等 唐韻')) return 'aŋ'; + if (is('開口 三等 陽韻')) return is('莊組') ? 'aŋ' : 'yaŋ'; + if (is('合口 一等 唐韻')) return 'waŋ'; + if (is('合口 三等 陽韻')) return is('見組 或 影曉母') ? 'wiyaŋ' : 'waŋ'; + // 梗攝 + if (is('開口 二等 庚韻')) return is('見幫知組 或 匣母') ? 'aŋ' : 'eŋ'; + if (is('開口 二等 耕韻')) return 'aŋ'; + if (is('開口 三等 庚韻')) return 'eŋ'; + if (is('開口 三等 清韻')) return 'eŋ'; + if (is('開口 四等 青韻')) return 'eŋ'; + if (is('合口 二等 庚韻')) return 'waŋ'; + if (is('合口 二等 耕韻')) return 'waŋ'; + if (is('合口 三等 庚韻')) return 'weŋ'; + if (is('合口 三等 清韻')) return 'yeŋ'; + if (is('合口 四等 青韻')) return 'weŋ'; + // 曾攝 + if (is('開口 一等 登韻')) return 'oŋ'; + if (is('開口 三等 蒸韻')) return 'yoŋ'; + if (is('合口 一等 登韻')) return 'oŋ'; + if (is('合口 三等 蒸韻')) return 'yoŋ'; + // 通攝 + if (is('一等 東韻')) return 'oŋ'; + if (is('三等 鍾韻')) return 'yoŋ'; + if (is('一等 冬韻')) return 'oŋ'; + if (is('三等 東韻 幫組')) return !is('入聲') || is('明母') ? 'oŋ': 'uŋ'; + if (is('三等 東韻 知影組')) return 'iŋ'; + if (is('三等 東韻 日來以母')) return 'iŋ'; + if (is('三等 東韻 見組 入聲')) return 'iŋ'; + if (is('三等 東韻')) return 'yuŋ'; + // 江攝 + if (is('二等 江韻')) return 'aŋ'; + throw new Error('無韻母規則'); +} + +let 聲母 = 聲母規則(); +let 韻母 = 韻母規則(); + + +// == 韻尾規則 == + +// 入聲韻尾 +if (is('入聲')) { + if (韻母.endsWith('m')) { + 韻母 = 韻母.slice(0, -1) + 'fu'; + } else if (韻母.endsWith('n')) { + 韻母 = 韻母.slice(0, -1) + 'tu'; + } else if (韻母.endsWith('ŋ')) { + 韻母 = 韻母.slice(0, -1) + (韻母[韻母.length - 2] == 'e' ? 'ki' : 'ku'); + } +} + +// 鼻音韻尾同化鼻音聲母 +// NV > BV | NVN > NVN +// 例外:蚊 ブン NVN > NVN → mun > bun +if (聲母 == 'm' && (!韻母.endsWith('ŋ') || 韻母.startsWith('u') || is('唐陽東韻'))) { + 聲母 = 'b' +} + +// 後鼻音韻尾 +if (韻母.endsWith('ŋ')) { + 韻母 = 韻母.slice(0, -1) + (['e', 'i'].includes(韻母[韻母.length - 2]) ? 'i': 'u') +} + +// 汚 0o -> wo +// 翁 0ou -> wou +if (is('影母') && (is('模韻') || is('東韻'))) { + 聲母 = 'w' +} + +// == 韻頭規則 == + +// PyV > PV +if (is('幫組 三等') && (韻母.startsWith('y'))) { + 韻母 = 韻母.slice(1) +} + +// JwV > JV +if (is('以母 合口') && (韻母.startsWith('w'))) { + 韻母 = 韻母.slice(1) +} + + +// == 韻母規則 == + +// 水 swi > スイ | 類 rwi > ルイ | 對 twi > ツイ +if (['s', 't', 'r'].includes(聲母) && 韻母 == 'wi') { + 韻母 = 'u' + 韻母.slice(1) +} + +if (韻母 == 'ii') { + 韻母 = 'yuu' +} + +// == 特殊字規則 == +if (字頭 == '寧') { + 聲母 = 'n' +} + +function 片假名化(拉丁轉寫) { + const 五十音 = { + '0': {'a': 'ア', 'i': 'イ', 'u': 'ウ', 'e': 'エ', 'o': 'オ'}, + 'k': {'a': 'カ', 'i': 'キ', 'u': 'ク', 'e': 'ケ', 'o': 'コ'}, + 'g': {'a': 'ガ', 'i': 'ギ', 'u': 'グ', 'e': 'ゲ', 'o': 'ゴ'}, + 's': {'a': 'サ', 'i': 'シ', 'u': 'ス', 'e': 'セ', 'o': 'ソ'}, + 'z': {'a': 'ザ', 'i': 'ジ', 'u': 'ズ', 'e': 'ゼ', 'o': 'ゾ'}, + 't': {'a': 'タ', 'i': 'チ', 'u': 'ツ', 'e': 'テ', 'o': 'ト'}, + 'd': {'a': 'ダ', 'i': 'ヂ', 'u': 'ヅ', 'e': 'デ', 'o': 'ド'}, + 'n': {'a': 'ナ', 'i': 'ニ', 'u': 'ヌ', 'e': 'ネ', 'o': 'ノ'}, + 'f': {'a': 'ハ', 'i': 'ヒ', 'u': 'フ', 'e': 'ヘ', 'o': 'ホ'}, + 'b': {'a': 'バ', 'i': 'ビ', 'u': 'ブ', 'e': 'ベ', 'o': 'ボ'}, + 'm': {'a': 'マ', 'i': 'ミ', 'u': 'ム', 'e': 'メ', 'o': 'モ'}, + 'y': {'a': 'ヤ', 'i': '○', 'u': 'ユ', 'e': 'エ', 'o': 'ヨ'}, + 'r': {'a': 'ラ', 'i': 'リ', 'u': 'ル', 'e': 'レ', 'o': 'ロ'}, + 'w': {'a': 'ワ', 'i': 'ヰ', 'u': '○', 'e': 'ヱ', 'o': 'ヲ'}, + } + + let [wi, we] = 開關.wiwe ? 開關.小假名wiwe ? ['𛅤', '𛅥'] : ['ヰ', 'ヱ'] : ['○', '○'] + + const 小假名 = { + 'y': {'a': 'ャ', 'i': '○', 'u': 'ュ', 'e': '○', 'o': 'ョ'}, + 'w': {'a': 'ヮ', 'i': wi, 'u': '○', 'e': we, 'o': '𛅦'}, + } + + // 二合拗音:wiyau > 𛅤ャウ + if (拉丁轉寫 == 'kwiyau') { + if (開關.kwiyau && 開關.wiwe) + return 開關.小假名wiwe ? 'ク𛅤ャウ' : 'クヰヤウ' + else + return 'キャウ' + } + + if (拉丁轉寫 == 'gwiyau') { + if (開關.kwiyau && 開關.wiwe) + return 開關.小假名wiwe ? 'グ𛅤ャウ' : 'グヰヤウ' + else + return 'ギャウ' + } + + // CVVCV > CV.V.CV + // Ref: https://stackoverflow.com/a/49407494/2719898 + const 音節正則 = /[^aeiou]*[wy]?[aeioumn](?:$|[^aeiou](?=[^aeiou]))?/gi; + + 音節列表 = 拉丁轉寫.match(音節正則) + + 假名列表 = 音節列表.map((音節) => { + if (音節.length == 3) { + // CGV := CyV / CwV + let [C, G, V] = 音節; + + const GtoV = { + 'y': 'i', + 'w': 'u' + } + + if (C == '0') + return 五十音[G][V] + if (小假名[G][V] == '○') + return 五十音[C][V] + if (!['k', 'g'].includes(C) && G == 'w') + return 五十音[C][V] + + return 五十音[C][GtoV[G]] + 小假名[G][V] + } + + const C = 音節.length == 2 ? 音節[0] : '0' + const V = 音節.slice(-1) + + if (V.match(/[aiueo]/)) { + return 五十音[C][V] + } else if (V == 'n') { + return 'ン' + } else if (V == 'm') { + return 開關.分mn ? 'ム' : 'ン' + } else { + throw new Error(`未知規則音節: ${音節}`); + } + }) + + return 假名列表.join('') +} + + +// return `${片假名化(聲母 + 韻母)} (${聲母 + 韻母})` +return 片假名化(聲母 + 韻母); \ No newline at end of file From c568b1d7b86681a6c50b0c629aac0f64e3288a8b Mon Sep 17 00:00:00 2001 From: mkpoli Date: Wed, 23 Dec 2020 22:32:29 +0900 Subject: [PATCH 02/11] Update README.MD for Japanese Kanon --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 57975d0..268dedf 100644 --- a/README.md +++ b/README.md @@ -17,3 +17,4 @@ unt 切韻擬音 J | unt's _Qieyun_ Reconstruction J | `unt_j.js` 推導普通話 | Extrapolated Putonghua | `putonghua.js` 推導廣州音 | Extrapolated Cantonese | `gwongzau.js` 綾香思考音系 | | `ayaka_v8.js` +推導日語漢音 | Extrapolated Japanese Kanon | `japanese-kanon.js` From 8602bd59729bb83a657cff600557410cd081cda0 Mon Sep 17 00:00:00 2001 From: mkpoli Date: Thu, 24 Dec 2020 15:05:45 +0900 Subject: [PATCH 03/11] Rename Kan-on and Change desc --- README.md | 2 +- japanese-kanon.js => kan-on.js | 666 ++++++++++++++++----------------- 2 files changed, 334 insertions(+), 334 deletions(-) rename japanese-kanon.js => kan-on.js (97%) diff --git a/README.md b/README.md index 268dedf..310f30d 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ https://cdn.jsdelivr.net/gh/nk2028/qieyun-examples@/ 白一平轉寫 | Baxter’s Transcription | `baxter.js` unt 切韻朗讀音 | unt’s Reading Pronunciation of _Qieyun_ | `unt.js` unt 切韻擬音 J | unt's _Qieyun_ Reconstruction J | `unt_j.js` +推導日語漢音 | Extrapolated Japanese Kan-on | `kan-on.js` 推導普通話 | Extrapolated Putonghua | `putonghua.js` 推導廣州音 | Extrapolated Cantonese | `gwongzau.js` 綾香思考音系 | | `ayaka_v8.js` -推導日語漢音 | Extrapolated Japanese Kanon | `japanese-kanon.js` diff --git a/japanese-kanon.js b/kan-on.js similarity index 97% rename from japanese-kanon.js rename to kan-on.js index 6386b25..68979e8 100644 --- a/japanese-kanon.js +++ b/kan-on.js @@ -1,334 +1,334 @@ -/* 推導日語漢音 - * - * 説明 - * 以下代碼爲生成推導日語漢音的函數體 - * - * 以字音假名遣形式表示,拗音用對應的小假名表示 - * - * 有開關可控制:-m -n 之分、-wi -we 合拗音、wiwe 小假名表示、狂 ク𛅥ャウ vs キャウ - * - * 函數接受音韻地位,返回對應的推導日語漢音 - * - */ - -const is = (x) => 音韻地位.屬於(x); - -const 開關 = {}; - -開關.分mn = true; // 開:サム 關:サン -開關.wiwe = true; // 開:ク𛅥ン 關:ケン -開關.小假名wiwe = true; // 開:ク𛅥ン 關:クヱン -開關.kwiyau = true; // 開:ク𛅥ャウ 關:キャウ - -function 聲母規則() { - if (is('幫母')) return 'f'; - if (is('滂母')) return 'f'; - if (is('並母')) return 'f'; - if (is('明母')) return 'm'; - if (is('端母')) return 't'; - if (is('透母')) return 't'; - if (is('定母')) return 't'; - if (is('泥母')) return 'd'; - if (is('知母')) return 't'; - if (is('徹母')) return 't'; - if (is('澄母')) return 't'; - if (is('孃母')) return 'd'; - if (is('精母')) return 's'; - if (is('清母')) return 's'; - if (is('從母')) return 's'; - if (is('心母')) return 's'; - if (is('邪母')) return 's'; - if (is('莊母')) return 's'; - if (is('初母')) return 's'; - if (is('崇母')) return 's'; - if (is('生母')) return 's'; - if (is('俟母')) return 's'; - if (is('章母')) return 's'; - if (is('昌母')) return 's'; - if (is('船母')) return 's'; - if (is('書母')) return 's'; - if (is('常母')) return 's'; - if (is('見母')) return 'k'; - if (is('溪母')) return 'k'; - if (is('羣母')) return 'k'; - if (is('疑母')) return 'g'; - if (is('影母')) return '0'; - if (is('曉母')) return 'k'; - if (is('匣母')) return 'k'; - if (is('云母')) return '0'; - if (is('以母')) return '0'; - if (is('來母')) return 'r'; - if (is('日母')) return 'z'; - throw new Error('無聲母規則'); -} - -function 韻母規則() { - // 果攝 - if (is('開口 一等 歌韻')) return 'a'; - if (is('開口 三等 戈韻')) return 'a'; - if (is('合口 一等 戈韻')) return 'wa'; - if (is('合口 三等 戈韻')) return 'wa'; - // 假攝 - if (is('開口 二等 麻韻')) return 'a'; - if (is('開口 三等 麻韻')) return 'ya'; - if (is('合口 二等 麻韻')) return 'wa'; - // 遇攝 - if (is('一等 模韻')) return 'o'; - if (is('三等 魚韻')) return is('莊組') ? 'o' : 'yo'; - if (is('三等 虞韻')) return is('幫見影組') ? 'u' : (is('知組') ? 'yuu' : 'yu'); - // 蟹攝 - if (is('開口 一等 咍韻')) return 'ai'; - if (is('開口 二等 佳韻')) return 'ai'; - if (is('開口 二等 皆韻')) return 'ai'; - if (is('開口 四等 齊韻')) return 'ei'; - if (is('開口 一等 泰韻')) return 'ai'; - if (is('開口 二等 夬韻')) return 'ai'; - if (is('開口 三等 祭韻')) return 'ei'; - if (is('開口 三等 廢韻')) return 'ai'; - if (is('合口 一等 灰韻')) return 'wai'; - if (is('合口 二等 佳韻')) return 'wai'; - if (is('合口 二等 皆韻')) return 'wai'; - if (is('合口 四等 齊韻')) return 'wei'; - if (is('合口 一等 泰韻')) return 'wai'; - if (is('合口 二等 夬韻')) return 'wai'; - if (is('合口 三等 祭韻')) return 'wei'; - if (is('合口 三等 廢韻')) return 'wai'; - // 止攝 - if (is('開口 三等 支韻')) return 'i'; - if (is('開口 三等 脂韻')) return 'i'; - if (is('開口 三等 之韻')) return 'i'; - if (is('開口 三等 微韻')) return 'i'; - if (is('合口 三等 支韻 重紐A類')) return 'i'; - if (is('合口 三等 支韻')) return 'wi'; - if (is('合口 三等 脂韻 重紐A類')) return 'i'; - if (is('合口 三等 脂韻')) return 'wi'; - if (is('合口 三等 微韻')) return 'wi'; - // 效攝 - if (is('一等 豪韻 幫組')) return 'ou'; - if (is('一等 豪韻')) return 'au'; - if (is('二等 肴韻')) return 'au'; - if (is('三等 宵韻')) return 'eu'; - if (is('四等 蕭韻')) return 'eu'; - // 流攝 - if (is('一等 侯韻')) return 'ou'; - if (is('三等 尤韻')) return is('幫組') ? (is('明母') ? 'ou' : 'uu') : 'iu'; - if (is('三等 幽韻')) return 'iu'; - // 咸攝 - if (is('開口 一等 談韻')) return 'am'; - if (is('開口 二等 銜韻')) return 'am'; - if (is('開口 二等 咸韻')) return 'am'; - if (is('開口 三等 鹽韻')) return 'em'; - if (is('開口 三等 嚴韻')) return 'em'; - if (is('開口 四等 添韻')) return 'em'; - if (is('開口 一等 覃韻')) return 'am'; - if (is('合口 三等 凡韻')) return 'am'; - // 深攝 - if (is('三等 侵韻')) return 'im'; - // 山攝 - if (is('開口 一等 寒韻')) return 'an'; - if (is('開口 二等 刪韻')) return 'an'; - if (is('開口 二等 山韻')) return 'an'; - if (is('開口 三等 仙韻')) return 'en'; - if (is('開口 四等 先韻')) return 'en'; - if (is('合口 一等 桓韻')) return 'wan'; - if (is('合口 二等 刪韻')) return 'wan'; - if (is('合口 二等 山韻')) return 'wan'; - if (is('合口 三等 仙韻')) return 'wen'; - if (is('合口 四等 先韻')) return 'wen'; - // 臻攝 - if (is('開口 一等 痕韻')) return 'on'; - if (is('開口 三等 眞韻')) return 'in'; - if (is('開口 三等 臻韻')) return 'in'; - if (is('開口 三等 欣韻')) return 'in'; - if (is('開口 三等 元韻')) return 'en'; - if (is('合口 一等 魂韻')) return 'on'; - if (is('合口 三等 眞韻')) return 'win'; - if (is('合口 三等 諄韻 重紐A類')) return 'in'; - if (is('合口 三等 諄韻')) return is('來母') ? 'in' : 'yun'; - if (is('合口 三等 文韻')) return 'un'; - if (is('合口 三等 元韻')) return is('幫組') ? 'wan' : 'wen'; - // 宕攝 - if (is('開口 一等 唐韻')) return 'aŋ'; - if (is('開口 三等 陽韻')) return is('莊組') ? 'aŋ' : 'yaŋ'; - if (is('合口 一等 唐韻')) return 'waŋ'; - if (is('合口 三等 陽韻')) return is('見組 或 影曉母') ? 'wiyaŋ' : 'waŋ'; - // 梗攝 - if (is('開口 二等 庚韻')) return is('見幫知組 或 匣母') ? 'aŋ' : 'eŋ'; - if (is('開口 二等 耕韻')) return 'aŋ'; - if (is('開口 三等 庚韻')) return 'eŋ'; - if (is('開口 三等 清韻')) return 'eŋ'; - if (is('開口 四等 青韻')) return 'eŋ'; - if (is('合口 二等 庚韻')) return 'waŋ'; - if (is('合口 二等 耕韻')) return 'waŋ'; - if (is('合口 三等 庚韻')) return 'weŋ'; - if (is('合口 三等 清韻')) return 'yeŋ'; - if (is('合口 四等 青韻')) return 'weŋ'; - // 曾攝 - if (is('開口 一等 登韻')) return 'oŋ'; - if (is('開口 三等 蒸韻')) return 'yoŋ'; - if (is('合口 一等 登韻')) return 'oŋ'; - if (is('合口 三等 蒸韻')) return 'yoŋ'; - // 通攝 - if (is('一等 東韻')) return 'oŋ'; - if (is('三等 鍾韻')) return 'yoŋ'; - if (is('一等 冬韻')) return 'oŋ'; - if (is('三等 東韻 幫組')) return !is('入聲') || is('明母') ? 'oŋ': 'uŋ'; - if (is('三等 東韻 知影組')) return 'iŋ'; - if (is('三等 東韻 日來以母')) return 'iŋ'; - if (is('三等 東韻 見組 入聲')) return 'iŋ'; - if (is('三等 東韻')) return 'yuŋ'; - // 江攝 - if (is('二等 江韻')) return 'aŋ'; - throw new Error('無韻母規則'); -} - -let 聲母 = 聲母規則(); -let 韻母 = 韻母規則(); - - -// == 韻尾規則 == - -// 入聲韻尾 -if (is('入聲')) { - if (韻母.endsWith('m')) { - 韻母 = 韻母.slice(0, -1) + 'fu'; - } else if (韻母.endsWith('n')) { - 韻母 = 韻母.slice(0, -1) + 'tu'; - } else if (韻母.endsWith('ŋ')) { - 韻母 = 韻母.slice(0, -1) + (韻母[韻母.length - 2] == 'e' ? 'ki' : 'ku'); - } -} - -// 鼻音韻尾同化鼻音聲母 -// NV > BV | NVN > NVN -// 例外:蚊 ブン NVN > NVN → mun > bun -if (聲母 == 'm' && (!韻母.endsWith('ŋ') || 韻母.startsWith('u') || is('唐陽東韻'))) { - 聲母 = 'b' -} - -// 後鼻音韻尾 -if (韻母.endsWith('ŋ')) { - 韻母 = 韻母.slice(0, -1) + (['e', 'i'].includes(韻母[韻母.length - 2]) ? 'i': 'u') -} - -// 汚 0o -> wo -// 翁 0ou -> wou -if (is('影母') && (is('模韻') || is('東韻'))) { - 聲母 = 'w' -} - -// == 韻頭規則 == - -// PyV > PV -if (is('幫組 三等') && (韻母.startsWith('y'))) { - 韻母 = 韻母.slice(1) -} - -// JwV > JV -if (is('以母 合口') && (韻母.startsWith('w'))) { - 韻母 = 韻母.slice(1) -} - - -// == 韻母規則 == - -// 水 swi > スイ | 類 rwi > ルイ | 對 twi > ツイ -if (['s', 't', 'r'].includes(聲母) && 韻母 == 'wi') { - 韻母 = 'u' + 韻母.slice(1) -} - -if (韻母 == 'ii') { - 韻母 = 'yuu' -} - -// == 特殊字規則 == -if (字頭 == '寧') { - 聲母 = 'n' -} - -function 片假名化(拉丁轉寫) { - const 五十音 = { - '0': {'a': 'ア', 'i': 'イ', 'u': 'ウ', 'e': 'エ', 'o': 'オ'}, - 'k': {'a': 'カ', 'i': 'キ', 'u': 'ク', 'e': 'ケ', 'o': 'コ'}, - 'g': {'a': 'ガ', 'i': 'ギ', 'u': 'グ', 'e': 'ゲ', 'o': 'ゴ'}, - 's': {'a': 'サ', 'i': 'シ', 'u': 'ス', 'e': 'セ', 'o': 'ソ'}, - 'z': {'a': 'ザ', 'i': 'ジ', 'u': 'ズ', 'e': 'ゼ', 'o': 'ゾ'}, - 't': {'a': 'タ', 'i': 'チ', 'u': 'ツ', 'e': 'テ', 'o': 'ト'}, - 'd': {'a': 'ダ', 'i': 'ヂ', 'u': 'ヅ', 'e': 'デ', 'o': 'ド'}, - 'n': {'a': 'ナ', 'i': 'ニ', 'u': 'ヌ', 'e': 'ネ', 'o': 'ノ'}, - 'f': {'a': 'ハ', 'i': 'ヒ', 'u': 'フ', 'e': 'ヘ', 'o': 'ホ'}, - 'b': {'a': 'バ', 'i': 'ビ', 'u': 'ブ', 'e': 'ベ', 'o': 'ボ'}, - 'm': {'a': 'マ', 'i': 'ミ', 'u': 'ム', 'e': 'メ', 'o': 'モ'}, - 'y': {'a': 'ヤ', 'i': '○', 'u': 'ユ', 'e': 'エ', 'o': 'ヨ'}, - 'r': {'a': 'ラ', 'i': 'リ', 'u': 'ル', 'e': 'レ', 'o': 'ロ'}, - 'w': {'a': 'ワ', 'i': 'ヰ', 'u': '○', 'e': 'ヱ', 'o': 'ヲ'}, - } - - let [wi, we] = 開關.wiwe ? 開關.小假名wiwe ? ['𛅤', '𛅥'] : ['ヰ', 'ヱ'] : ['○', '○'] - - const 小假名 = { - 'y': {'a': 'ャ', 'i': '○', 'u': 'ュ', 'e': '○', 'o': 'ョ'}, - 'w': {'a': 'ヮ', 'i': wi, 'u': '○', 'e': we, 'o': '𛅦'}, - } - - // 二合拗音:wiyau > 𛅤ャウ - if (拉丁轉寫 == 'kwiyau') { - if (開關.kwiyau && 開關.wiwe) - return 開關.小假名wiwe ? 'ク𛅤ャウ' : 'クヰヤウ' - else - return 'キャウ' - } - - if (拉丁轉寫 == 'gwiyau') { - if (開關.kwiyau && 開關.wiwe) - return 開關.小假名wiwe ? 'グ𛅤ャウ' : 'グヰヤウ' - else - return 'ギャウ' - } - - // CVVCV > CV.V.CV - // Ref: https://stackoverflow.com/a/49407494/2719898 - const 音節正則 = /[^aeiou]*[wy]?[aeioumn](?:$|[^aeiou](?=[^aeiou]))?/gi; - - 音節列表 = 拉丁轉寫.match(音節正則) - - 假名列表 = 音節列表.map((音節) => { - if (音節.length == 3) { - // CGV := CyV / CwV - let [C, G, V] = 音節; - - const GtoV = { - 'y': 'i', - 'w': 'u' - } - - if (C == '0') - return 五十音[G][V] - if (小假名[G][V] == '○') - return 五十音[C][V] - if (!['k', 'g'].includes(C) && G == 'w') - return 五十音[C][V] - - return 五十音[C][GtoV[G]] + 小假名[G][V] - } - - const C = 音節.length == 2 ? 音節[0] : '0' - const V = 音節.slice(-1) - - if (V.match(/[aiueo]/)) { - return 五十音[C][V] - } else if (V == 'n') { - return 'ン' - } else if (V == 'm') { - return 開關.分mn ? 'ム' : 'ン' - } else { - throw new Error(`未知規則音節: ${音節}`); - } - }) - - return 假名列表.join('') -} - - -// return `${片假名化(聲母 + 韻母)} (${聲母 + 韻母})` +/* 推導日語漢音 + * + * 説明 + * 以下代碼爲生成推導日語漢音的函數體 + * + * 以字音假名遣形式表示,拗音用對應的小假名表示 + * + * 有開關可控制:-m -n 之分、-wi -we 合拗音、wiwe 小假名表示、狂 ク𛅥ャウ vs キャウ + * + * 函數接受音韻地位,返回對應的推導日語漢音 + * + */ + +const is = (x) => 音韻地位.屬於(x); + +const 開關 = {}; + +開關.分mn = true; // 開:サム 關:サン +開關.wiwe = true; // 開:ク𛅥ン 關:ケン +開關.小假名wiwe = true; // 開:ク𛅥ン 關:クヱン +開關.kwiyau = true; // 開:ク𛅥ャウ 關:キャウ + +function 聲母規則() { + if (is('幫母')) return 'f'; + if (is('滂母')) return 'f'; + if (is('並母')) return 'f'; + if (is('明母')) return 'm'; + if (is('端母')) return 't'; + if (is('透母')) return 't'; + if (is('定母')) return 't'; + if (is('泥母')) return 'd'; + if (is('知母')) return 't'; + if (is('徹母')) return 't'; + if (is('澄母')) return 't'; + if (is('孃母')) return 'd'; + if (is('精母')) return 's'; + if (is('清母')) return 's'; + if (is('從母')) return 's'; + if (is('心母')) return 's'; + if (is('邪母')) return 's'; + if (is('莊母')) return 's'; + if (is('初母')) return 's'; + if (is('崇母')) return 's'; + if (is('生母')) return 's'; + if (is('俟母')) return 's'; + if (is('章母')) return 's'; + if (is('昌母')) return 's'; + if (is('船母')) return 's'; + if (is('書母')) return 's'; + if (is('常母')) return 's'; + if (is('見母')) return 'k'; + if (is('溪母')) return 'k'; + if (is('羣母')) return 'k'; + if (is('疑母')) return 'g'; + if (is('影母')) return '0'; + if (is('曉母')) return 'k'; + if (is('匣母')) return 'k'; + if (is('云母')) return '0'; + if (is('以母')) return '0'; + if (is('來母')) return 'r'; + if (is('日母')) return 'z'; + throw new Error('無聲母規則'); +} + +function 韻母規則() { + // 果攝 + if (is('開口 一等 歌韻')) return 'a'; + if (is('開口 三等 戈韻')) return 'a'; + if (is('合口 一等 戈韻')) return 'wa'; + if (is('合口 三等 戈韻')) return 'wa'; + // 假攝 + if (is('開口 二等 麻韻')) return 'a'; + if (is('開口 三等 麻韻')) return 'ya'; + if (is('合口 二等 麻韻')) return 'wa'; + // 遇攝 + if (is('一等 模韻')) return 'o'; + if (is('三等 魚韻')) return is('莊組') ? 'o' : 'yo'; + if (is('三等 虞韻')) return is('幫見影組') ? 'u' : (is('知組') ? 'yuu' : 'yu'); + // 蟹攝 + if (is('開口 一等 咍韻')) return 'ai'; + if (is('開口 二等 佳韻')) return 'ai'; + if (is('開口 二等 皆韻')) return 'ai'; + if (is('開口 四等 齊韻')) return 'ei'; + if (is('開口 一等 泰韻')) return 'ai'; + if (is('開口 二等 夬韻')) return 'ai'; + if (is('開口 三等 祭韻')) return 'ei'; + if (is('開口 三等 廢韻')) return 'ai'; + if (is('合口 一等 灰韻')) return 'wai'; + if (is('合口 二等 佳韻')) return 'wai'; + if (is('合口 二等 皆韻')) return 'wai'; + if (is('合口 四等 齊韻')) return 'wei'; + if (is('合口 一等 泰韻')) return 'wai'; + if (is('合口 二等 夬韻')) return 'wai'; + if (is('合口 三等 祭韻')) return 'wei'; + if (is('合口 三等 廢韻')) return 'wai'; + // 止攝 + if (is('開口 三等 支韻')) return 'i'; + if (is('開口 三等 脂韻')) return 'i'; + if (is('開口 三等 之韻')) return 'i'; + if (is('開口 三等 微韻')) return 'i'; + if (is('合口 三等 支韻 重紐A類')) return 'i'; + if (is('合口 三等 支韻')) return 'wi'; + if (is('合口 三等 脂韻 重紐A類')) return 'i'; + if (is('合口 三等 脂韻')) return 'wi'; + if (is('合口 三等 微韻')) return 'wi'; + // 效攝 + if (is('一等 豪韻 幫組')) return 'ou'; + if (is('一等 豪韻')) return 'au'; + if (is('二等 肴韻')) return 'au'; + if (is('三等 宵韻')) return 'eu'; + if (is('四等 蕭韻')) return 'eu'; + // 流攝 + if (is('一等 侯韻')) return 'ou'; + if (is('三等 尤韻')) return is('幫組') ? (is('明母') ? 'ou' : 'uu') : 'iu'; + if (is('三等 幽韻')) return 'iu'; + // 咸攝 + if (is('開口 一等 談韻')) return 'am'; + if (is('開口 二等 銜韻')) return 'am'; + if (is('開口 二等 咸韻')) return 'am'; + if (is('開口 三等 鹽韻')) return 'em'; + if (is('開口 三等 嚴韻')) return 'em'; + if (is('開口 四等 添韻')) return 'em'; + if (is('開口 一等 覃韻')) return 'am'; + if (is('合口 三等 凡韻')) return 'am'; + // 深攝 + if (is('三等 侵韻')) return 'im'; + // 山攝 + if (is('開口 一等 寒韻')) return 'an'; + if (is('開口 二等 刪韻')) return 'an'; + if (is('開口 二等 山韻')) return 'an'; + if (is('開口 三等 仙韻')) return 'en'; + if (is('開口 四等 先韻')) return 'en'; + if (is('合口 一等 桓韻')) return 'wan'; + if (is('合口 二等 刪韻')) return 'wan'; + if (is('合口 二等 山韻')) return 'wan'; + if (is('合口 三等 仙韻')) return 'wen'; + if (is('合口 四等 先韻')) return 'wen'; + // 臻攝 + if (is('開口 一等 痕韻')) return 'on'; + if (is('開口 三等 眞韻')) return 'in'; + if (is('開口 三等 臻韻')) return 'in'; + if (is('開口 三等 欣韻')) return 'in'; + if (is('開口 三等 元韻')) return 'en'; + if (is('合口 一等 魂韻')) return 'on'; + if (is('合口 三等 眞韻')) return 'win'; + if (is('合口 三等 諄韻 重紐A類')) return 'in'; + if (is('合口 三等 諄韻')) return is('來母') ? 'in' : 'yun'; + if (is('合口 三等 文韻')) return 'un'; + if (is('合口 三等 元韻')) return is('幫組') ? 'wan' : 'wen'; + // 宕攝 + if (is('開口 一等 唐韻')) return 'aŋ'; + if (is('開口 三等 陽韻')) return is('莊組') ? 'aŋ' : 'yaŋ'; + if (is('合口 一等 唐韻')) return 'waŋ'; + if (is('合口 三等 陽韻')) return is('見組 或 影曉母') ? 'wiyaŋ' : 'waŋ'; + // 梗攝 + if (is('開口 二等 庚韻')) return is('見幫知組 或 匣母') ? 'aŋ' : 'eŋ'; + if (is('開口 二等 耕韻')) return 'aŋ'; + if (is('開口 三等 庚韻')) return 'eŋ'; + if (is('開口 三等 清韻')) return 'eŋ'; + if (is('開口 四等 青韻')) return 'eŋ'; + if (is('合口 二等 庚韻')) return 'waŋ'; + if (is('合口 二等 耕韻')) return 'waŋ'; + if (is('合口 三等 庚韻')) return 'weŋ'; + if (is('合口 三等 清韻')) return 'yeŋ'; + if (is('合口 四等 青韻')) return 'weŋ'; + // 曾攝 + if (is('開口 一等 登韻')) return 'oŋ'; + if (is('開口 三等 蒸韻')) return 'yoŋ'; + if (is('合口 一等 登韻')) return 'oŋ'; + if (is('合口 三等 蒸韻')) return 'yoŋ'; + // 通攝 + if (is('一等 東韻')) return 'oŋ'; + if (is('三等 鍾韻')) return 'yoŋ'; + if (is('一等 冬韻')) return 'oŋ'; + if (is('三等 東韻 幫組')) return !is('入聲') || is('明母') ? 'oŋ': 'uŋ'; + if (is('三等 東韻 知影組')) return 'iŋ'; + if (is('三等 東韻 日來以母')) return 'iŋ'; + if (is('三等 東韻 見組 入聲')) return 'iŋ'; + if (is('三等 東韻')) return 'yuŋ'; + // 江攝 + if (is('二等 江韻')) return 'aŋ'; + throw new Error('無韻母規則'); +} + +let 聲母 = 聲母規則(); +let 韻母 = 韻母規則(); + + +// == 韻尾規則 == + +// 入聲韻尾 +if (is('入聲')) { + if (韻母.endsWith('m')) { + 韻母 = 韻母.slice(0, -1) + 'fu'; + } else if (韻母.endsWith('n')) { + 韻母 = 韻母.slice(0, -1) + 'tu'; + } else if (韻母.endsWith('ŋ')) { + 韻母 = 韻母.slice(0, -1) + (韻母[韻母.length - 2] == 'e' ? 'ki' : 'ku'); + } +} + +// 鼻音韻尾同化鼻音聲母 +// NV > BV | NVN > NVN +// 例外:蚊 ブン NVN > NVN → mun > bun +if (聲母 == 'm' && (!韻母.endsWith('ŋ') || 韻母.startsWith('u') || is('唐陽東韻'))) { + 聲母 = 'b' +} + +// 後鼻音韻尾 +if (韻母.endsWith('ŋ')) { + 韻母 = 韻母.slice(0, -1) + (['e', 'i'].includes(韻母[韻母.length - 2]) ? 'i': 'u') +} + +// 汚 0o -> wo +// 翁 0ou -> wou +if (is('影母') && (is('模韻') || is('東韻'))) { + 聲母 = 'w' +} + +// == 韻頭規則 == + +// PyV > PV +if (is('幫組 三等') && (韻母.startsWith('y'))) { + 韻母 = 韻母.slice(1) +} + +// JwV > JV +if (is('以母 合口') && (韻母.startsWith('w'))) { + 韻母 = 韻母.slice(1) +} + + +// == 韻母規則 == + +// 水 swi > スイ | 類 rwi > ルイ | 對 twi > ツイ +if (['s', 't', 'r'].includes(聲母) && 韻母 == 'wi') { + 韻母 = 'u' + 韻母.slice(1) +} + +if (韻母 == 'ii') { + 韻母 = 'yuu' +} + +// == 特殊字規則 == +if (字頭 == '寧') { + 聲母 = 'n' +} + +function 片假名化(拉丁轉寫) { + const 五十音 = { + '0': {'a': 'ア', 'i': 'イ', 'u': 'ウ', 'e': 'エ', 'o': 'オ'}, + 'k': {'a': 'カ', 'i': 'キ', 'u': 'ク', 'e': 'ケ', 'o': 'コ'}, + 'g': {'a': 'ガ', 'i': 'ギ', 'u': 'グ', 'e': 'ゲ', 'o': 'ゴ'}, + 's': {'a': 'サ', 'i': 'シ', 'u': 'ス', 'e': 'セ', 'o': 'ソ'}, + 'z': {'a': 'ザ', 'i': 'ジ', 'u': 'ズ', 'e': 'ゼ', 'o': 'ゾ'}, + 't': {'a': 'タ', 'i': 'チ', 'u': 'ツ', 'e': 'テ', 'o': 'ト'}, + 'd': {'a': 'ダ', 'i': 'ヂ', 'u': 'ヅ', 'e': 'デ', 'o': 'ド'}, + 'n': {'a': 'ナ', 'i': 'ニ', 'u': 'ヌ', 'e': 'ネ', 'o': 'ノ'}, + 'f': {'a': 'ハ', 'i': 'ヒ', 'u': 'フ', 'e': 'ヘ', 'o': 'ホ'}, + 'b': {'a': 'バ', 'i': 'ビ', 'u': 'ブ', 'e': 'ベ', 'o': 'ボ'}, + 'm': {'a': 'マ', 'i': 'ミ', 'u': 'ム', 'e': 'メ', 'o': 'モ'}, + 'y': {'a': 'ヤ', 'i': '○', 'u': 'ユ', 'e': 'エ', 'o': 'ヨ'}, + 'r': {'a': 'ラ', 'i': 'リ', 'u': 'ル', 'e': 'レ', 'o': 'ロ'}, + 'w': {'a': 'ワ', 'i': 'ヰ', 'u': '○', 'e': 'ヱ', 'o': 'ヲ'}, + } + + let [wi, we] = 開關.wiwe ? 開關.小假名wiwe ? ['𛅤', '𛅥'] : ['ヰ', 'ヱ'] : ['○', '○'] + + const 小假名 = { + 'y': {'a': 'ャ', 'i': '○', 'u': 'ュ', 'e': '○', 'o': 'ョ'}, + 'w': {'a': 'ヮ', 'i': wi, 'u': '○', 'e': we, 'o': '𛅦'}, + } + + // 二合拗音:wiyau > 𛅤ャウ + if (拉丁轉寫 == 'kwiyau') { + if (開關.kwiyau && 開關.wiwe) + return 開關.小假名wiwe ? 'ク𛅤ャウ' : 'クヰヤウ' + else + return 'キャウ' + } + + if (拉丁轉寫 == 'gwiyau') { + if (開關.kwiyau && 開關.wiwe) + return 開關.小假名wiwe ? 'グ𛅤ャウ' : 'グヰヤウ' + else + return 'ギャウ' + } + + // CVVCV > CV.V.CV + // Ref: https://stackoverflow.com/a/49407494/2719898 + const 音節正則 = /[^aeiou]*[wy]?[aeioumn](?:$|[^aeiou](?=[^aeiou]))?/gi; + + 音節列表 = 拉丁轉寫.match(音節正則) + + 假名列表 = 音節列表.map((音節) => { + if (音節.length == 3) { + // CGV := CyV / CwV + let [C, G, V] = 音節; + + const GtoV = { + 'y': 'i', + 'w': 'u' + } + + if (C == '0') + return 五十音[G][V] + if (小假名[G][V] == '○') + return 五十音[C][V] + if (!['k', 'g'].includes(C) && G == 'w') + return 五十音[C][V] + + return 五十音[C][GtoV[G]] + 小假名[G][V] + } + + const C = 音節.length == 2 ? 音節[0] : '0' + const V = 音節.slice(-1) + + if (V.match(/[aiueo]/)) { + return 五十音[C][V] + } else if (V == 'n') { + return 'ン' + } else if (V == 'm') { + return 開關.分mn ? 'ム' : 'ン' + } else { + throw new Error(`未知規則音節: ${音節}`); + } + }) + + return 假名列表.join('') +} + + +// return `${片假名化(聲母 + 韻母)} (${聲母 + 韻母})` return 片假名化(聲母 + 韻母); \ No newline at end of file From 00a9d787378ebbe41c27256cb27df72a5e3ce7fb Mon Sep 17 00:00:00 2001 From: mkpoli Date: Thu, 24 Dec 2020 15:22:54 +0900 Subject: [PATCH 04/11] Style Improvements --- kan-on.js | 88 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/kan-on.js b/kan-on.js index 68979e8..0be656a 100644 --- a/kan-on.js +++ b/kan-on.js @@ -18,48 +18,50 @@ const 開關 = {}; 開關.分mn = true; // 開:サム 關:サン 開關.wiwe = true; // 開:ク𛅥ン 關:ケン 開關.小假名wiwe = true; // 開:ク𛅥ン 關:クヱン -開關.kwiyau = true; // 開:ク𛅥ャウ 關:キャウ +開關.kwiyau = true; // 開:ク𛅥ャウ 關:キャウ function 聲母規則() { - if (is('幫母')) return 'f'; - if (is('滂母')) return 'f'; - if (is('並母')) return 'f'; - if (is('明母')) return 'm'; - if (is('端母')) return 't'; - if (is('透母')) return 't'; - if (is('定母')) return 't'; - if (is('泥母')) return 'd'; - if (is('知母')) return 't'; - if (is('徹母')) return 't'; - if (is('澄母')) return 't'; - if (is('孃母')) return 'd'; - if (is('精母')) return 's'; - if (is('清母')) return 's'; - if (is('從母')) return 's'; - if (is('心母')) return 's'; - if (is('邪母')) return 's'; - if (is('莊母')) return 's'; - if (is('初母')) return 's'; - if (is('崇母')) return 's'; - if (is('生母')) return 's'; - if (is('俟母')) return 's'; - if (is('章母')) return 's'; - if (is('昌母')) return 's'; - if (is('船母')) return 's'; - if (is('書母')) return 's'; - if (is('常母')) return 's'; - if (is('見母')) return 'k'; - if (is('溪母')) return 'k'; - if (is('羣母')) return 'k'; - if (is('疑母')) return 'g'; - if (is('影母')) return '0'; - if (is('曉母')) return 'k'; - if (is('匣母')) return 'k'; - if (is('云母')) return '0'; - if (is('以母')) return '0'; - if (is('來母')) return 'r'; - if (is('日母')) return 'z'; - throw new Error('無聲母規則'); + switch (音韻地位.母) { + case '幫': return 'f'; + case '滂': return 'f'; + case '並': return 'f'; + case '明': return 'm'; + case '端': return 't'; + case '透': return 't'; + case '定': return 't'; + case '泥': return 'd'; + case '知': return 't'; + case '徹': return 't'; + case '澄': return 't'; + case '孃': return 'd'; + case '精': return 's'; + case '清': return 's'; + case '從': return 's'; + case '心': return 's'; + case '邪': return 's'; + case '莊': return 's'; + case '初': return 's'; + case '崇': return 's'; + case '生': return 's'; + case '俟': return 's'; + case '章': return 's'; + case '昌': return 's'; + case '船': return 's'; + case '書': return 's'; + case '常': return 's'; + case '見': return 'k'; + case '溪': return 'k'; + case '羣': return 'k'; + case '疑': return 'g'; + case '影': return '0'; + case '曉': return 'k'; + case '匣': return 'k'; + case '云': return '0'; + case '以': return '0'; + case '來': return 'r'; + case '日': return 'z'; + default: throw new Error('無聲母規則'); + } } function 韻母規則() { @@ -220,12 +222,12 @@ if (is('影母') && (is('模韻') || is('東韻'))) { // == 韻頭規則 == // PyV > PV -if (is('幫組 三等') && (韻母.startsWith('y'))) { +if (is('幫組 三等') && 韻母.startsWith('y')) { 韻母 = 韻母.slice(1) } // JwV > JV -if (is('以母 合口') && (韻母.startsWith('w'))) { +if (is('以母 合口') && 韻母.startsWith('w')) { 韻母 = 韻母.slice(1) } @@ -331,4 +333,4 @@ function 片假名化(拉丁轉寫) { // return `${片假名化(聲母 + 韻母)} (${聲母 + 韻母})` -return 片假名化(聲母 + 韻母); \ No newline at end of file +return 片假名化(聲母 + 韻母); From f7e9af4fd3a987b935a576c73641f041a6b569bf Mon Sep 17 00:00:00 2001 From: mkpoli Date: Thu, 24 Dec 2020 16:10:26 +0900 Subject: [PATCH 05/11] Add Latin transliteration switch --- kan-on.js | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/kan-on.js b/kan-on.js index 0be656a..950808a 100644 --- a/kan-on.js +++ b/kan-on.js @@ -15,6 +15,7 @@ const is = (x) => 音韻地位.屬於(x); const 開關 = {}; +開關.假名 = true; // 開:カン 關:kan 開關.分mn = true; // 開:サム 關:サン 開關.wiwe = true; // 開:ク𛅥ン 關:ケン 開關.小假名wiwe = true; // 開:ク𛅥ン 關:クヱン @@ -248,6 +249,24 @@ if (字頭 == '寧') { 聲母 = 'n' } +// TODO: Clear up romaji before getting into 片假名化 + +function 組合聲韻(聲母, 韻母) { + if (!["0", "k", "g"].includes(聲母) && 韻母.startsWith("w")) + 韻母 = 韻母.slice(1) + + if (聲母 == "0" && 韻母.startsWith("ye")) + 韻母 = 韻母.slice(1) + + if (!開關.分mn && 韻母.endsWith("m")) + 韻母 = 韻母.slice(0, -1) + "n" + + if (!開關.wiwe && 聲母 != "0") + 韻母 = 韻母.replace("wiy", "y").replace("wi", "i").replace("we", "e") + + return [聲母, 韻母].join("") +} + function 片假名化(拉丁轉寫) { const 五十音 = { '0': {'a': 'ア', 'i': 'イ', 'u': 'ウ', 'e': 'エ', 'o': 'オ'}, @@ -266,7 +285,7 @@ function 片假名化(拉丁轉寫) { 'w': {'a': 'ワ', 'i': 'ヰ', 'u': '○', 'e': 'ヱ', 'o': 'ヲ'}, } - let [wi, we] = 開關.wiwe ? 開關.小假名wiwe ? ['𛅤', '𛅥'] : ['ヰ', 'ヱ'] : ['○', '○'] + let [wi, we] = 開關.小假名wiwe ? ['𛅤', '𛅥'] : ['ヰ', 'ヱ'] const 小假名 = { 'y': {'a': 'ャ', 'i': '○', 'u': 'ュ', 'e': '○', 'o': 'ョ'}, @@ -275,17 +294,13 @@ function 片假名化(拉丁轉寫) { // 二合拗音:wiyau > 𛅤ャウ if (拉丁轉寫 == 'kwiyau') { - if (開關.kwiyau && 開關.wiwe) + if (開關.kwiyau) return 開關.小假名wiwe ? 'ク𛅤ャウ' : 'クヰヤウ' - else - return 'キャウ' } if (拉丁轉寫 == 'gwiyau') { if (開關.kwiyau && 開關.wiwe) return 開關.小假名wiwe ? 'グ𛅤ャウ' : 'グヰヤウ' - else - return 'ギャウ' } // CVVCV > CV.V.CV @@ -322,7 +337,7 @@ function 片假名化(拉丁轉寫) { } else if (V == 'n') { return 'ン' } else if (V == 'm') { - return 開關.分mn ? 'ム' : 'ン' + return 'ム' } else { throw new Error(`未知規則音節: ${音節}`); } @@ -331,6 +346,7 @@ function 片假名化(拉丁轉寫) { return 假名列表.join('') } +const 拉丁轉寫 = 組合聲韻(聲母, 韻母) -// return `${片假名化(聲母 + 韻母)} (${聲母 + 韻母})` -return 片假名化(聲母 + 韻母); +// return `${片假名化(拉丁轉寫)} (${拉丁轉寫.replace("0", "")})` +return 開關.假名 ? 片假名化(拉丁轉寫) : 拉丁轉寫.replace("0", ""); From 5c9edf6e05ce39123bb7e2f6abe991ccb8fe0001 Mon Sep 17 00:00:00 2001 From: mkpoli Date: Thu, 24 Dec 2020 16:12:24 +0900 Subject: [PATCH 06/11] Fix gwiyau --- kan-on.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kan-on.js b/kan-on.js index 950808a..1cc62f3 100644 --- a/kan-on.js +++ b/kan-on.js @@ -299,7 +299,7 @@ function 片假名化(拉丁轉寫) { } if (拉丁轉寫 == 'gwiyau') { - if (開關.kwiyau && 開關.wiwe) + if (開關.kwiyau) return 開關.小假名wiwe ? 'グ𛅤ャウ' : 'グヰヤウ' } From 1c1d59faee5e6f21f40ee4cbe914c452293f5031 Mon Sep 17 00:00:00 2001 From: mkpoli Date: Thu, 24 Dec 2020 16:24:14 +0900 Subject: [PATCH 07/11] Add small kana switch --- kan-on.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/kan-on.js b/kan-on.js index 1cc62f3..f706d66 100644 --- a/kan-on.js +++ b/kan-on.js @@ -16,11 +16,17 @@ const is = (x) => 音韻地位.屬於(x); const 開關 = {}; 開關.假名 = true; // 開:カン 關:kan +開關.小假名 = true; // 開:キャウ 關:キヤウ + 開關.分mn = true; // 開:サム 關:サン + 開關.wiwe = true; // 開:ク𛅥ン 關:ケン 開關.小假名wiwe = true; // 開:ク𛅥ン 關:クヱン 開關.kwiyau = true; // 開:ク𛅥ャウ 關:キャウ +if (!開關.小假名) + 開關.小假名wiwe = false; + function 聲母規則() { switch (音韻地位.母) { case '幫': return 'f'; @@ -292,16 +298,14 @@ function 片假名化(拉丁轉寫) { 'w': {'a': 'ヮ', 'i': wi, 'u': '○', 'e': we, 'o': '𛅦'}, } - // 二合拗音:wiyau > 𛅤ャウ - if (拉丁轉寫 == 'kwiyau') { - if (開關.kwiyau) - return 開關.小假名wiwe ? 'ク𛅤ャウ' : 'クヰヤウ' + if (!開關.小假名) { + 小假名['y'] = 五十音['y'] + 小假名['w'] = 五十音['w'] } - if (拉丁轉寫 == 'gwiyau') { - if (開關.kwiyau) - return 開關.小假名wiwe ? 'グ𛅤ャウ' : 'グヰヤウ' - } + // 二合拗音:wiyau > 𛅤ャウ + if (拉丁轉寫.endsWith('wiyau')) + return `${五十音[拉丁轉寫[0]]['u']}${開關.小假名wiwe ? '𛅤ャ' : 'ヰヤ'}ウ` // CVVCV > CV.V.CV // Ref: https://stackoverflow.com/a/49407494/2719898 From 8959c9ac86ae67ee9a4771d1b61ac33299871d87 Mon Sep 17 00:00:00 2001 From: mkpoli Date: Thu, 24 Dec 2020 16:28:15 +0900 Subject: [PATCH 08/11] Unify semicolons --- kan-on.js | 64 +++++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/kan-on.js b/kan-on.js index f706d66..67356fa 100644 --- a/kan-on.js +++ b/kan-on.js @@ -212,30 +212,30 @@ if (is('入聲')) { // NV > BV | NVN > NVN // 例外:蚊 ブン NVN > NVN → mun > bun if (聲母 == 'm' && (!韻母.endsWith('ŋ') || 韻母.startsWith('u') || is('唐陽東韻'))) { - 聲母 = 'b' + 聲母 = 'b'; } // 後鼻音韻尾 if (韻母.endsWith('ŋ')) { - 韻母 = 韻母.slice(0, -1) + (['e', 'i'].includes(韻母[韻母.length - 2]) ? 'i': 'u') + 韻母 = 韻母.slice(0, -1) + (['e', 'i'].includes(韻母[韻母.length - 2]) ? 'i': 'u'); } // 汚 0o -> wo // 翁 0ou -> wou if (is('影母') && (is('模韻') || is('東韻'))) { - 聲母 = 'w' + 聲母 = 'w'; } // == 韻頭規則 == // PyV > PV if (is('幫組 三等') && 韻母.startsWith('y')) { - 韻母 = 韻母.slice(1) + 韻母 = 韻母.slice(1); } // JwV > JV if (is('以母 合口') && 韻母.startsWith('w')) { - 韻母 = 韻母.slice(1) + 韻母 = 韻母.slice(1); } @@ -243,34 +243,34 @@ if (is('以母 合口') && 韻母.startsWith('w')) { // 水 swi > スイ | 類 rwi > ルイ | 對 twi > ツイ if (['s', 't', 'r'].includes(聲母) && 韻母 == 'wi') { - 韻母 = 'u' + 韻母.slice(1) + 韻母 = 'u' + 韻母.slice(1); } if (韻母 == 'ii') { - 韻母 = 'yuu' + 韻母 = 'yuu'; } // == 特殊字規則 == if (字頭 == '寧') { - 聲母 = 'n' + 聲母 = 'n'; } // TODO: Clear up romaji before getting into 片假名化 function 組合聲韻(聲母, 韻母) { if (!["0", "k", "g"].includes(聲母) && 韻母.startsWith("w")) - 韻母 = 韻母.slice(1) + 韻母 = 韻母.slice(1); if (聲母 == "0" && 韻母.startsWith("ye")) - 韻母 = 韻母.slice(1) + 韻母 = 韻母.slice(1); if (!開關.分mn && 韻母.endsWith("m")) - 韻母 = 韻母.slice(0, -1) + "n" + 韻母 = 韻母.slice(0, -1) + "n"; if (!開關.wiwe && 聲母 != "0") - 韻母 = 韻母.replace("wiy", "y").replace("wi", "i").replace("we", "e") + 韻母 = 韻母.replace("wiy", "y").replace("wi", "i").replace("we", "e"); - return [聲母, 韻母].join("") + return [聲母, 韻母].join(""); } function 片假名化(拉丁轉寫) { @@ -289,29 +289,29 @@ function 片假名化(拉丁轉寫) { 'y': {'a': 'ヤ', 'i': '○', 'u': 'ユ', 'e': 'エ', 'o': 'ヨ'}, 'r': {'a': 'ラ', 'i': 'リ', 'u': 'ル', 'e': 'レ', 'o': 'ロ'}, 'w': {'a': 'ワ', 'i': 'ヰ', 'u': '○', 'e': 'ヱ', 'o': 'ヲ'}, - } + }; - let [wi, we] = 開關.小假名wiwe ? ['𛅤', '𛅥'] : ['ヰ', 'ヱ'] + let [wi, we] = 開關.小假名wiwe ? ['𛅤', '𛅥'] : ['ヰ', 'ヱ']; const 小假名 = { 'y': {'a': 'ャ', 'i': '○', 'u': 'ュ', 'e': '○', 'o': 'ョ'}, 'w': {'a': 'ヮ', 'i': wi, 'u': '○', 'e': we, 'o': '𛅦'}, - } + }; if (!開關.小假名) { - 小假名['y'] = 五十音['y'] - 小假名['w'] = 五十音['w'] + 小假名['y'] = 五十音['y']; + 小假名['w'] = 五十音['w']; } // 二合拗音:wiyau > 𛅤ャウ if (拉丁轉寫.endsWith('wiyau')) - return `${五十音[拉丁轉寫[0]]['u']}${開關.小假名wiwe ? '𛅤ャ' : 'ヰヤ'}ウ` + return `${五十音[拉丁轉寫[0]]['u']}${開關.小假名wiwe ? '𛅤ャ' : 'ヰヤ'}ウ`; // CVVCV > CV.V.CV // Ref: https://stackoverflow.com/a/49407494/2719898 const 音節正則 = /[^aeiou]*[wy]?[aeioumn](?:$|[^aeiou](?=[^aeiou]))?/gi; - 音節列表 = 拉丁轉寫.match(音節正則) + 音節列表 = 拉丁轉寫.match(音節正則); 假名列表 = 音節列表.map((音節) => { if (音節.length == 3) { @@ -321,36 +321,36 @@ function 片假名化(拉丁轉寫) { const GtoV = { 'y': 'i', 'w': 'u' - } + }; if (C == '0') - return 五十音[G][V] + return 五十音[G][V]; if (小假名[G][V] == '○') - return 五十音[C][V] + return 五十音[C][V]; if (!['k', 'g'].includes(C) && G == 'w') - return 五十音[C][V] + return 五十音[C][V]; - return 五十音[C][GtoV[G]] + 小假名[G][V] + return 五十音[C][GtoV[G]] + 小假名[G][V]; } - const C = 音節.length == 2 ? 音節[0] : '0' - const V = 音節.slice(-1) + const C = 音節.length == 2 ? 音節[0] : '0'; + const V = 音節.slice(-1); if (V.match(/[aiueo]/)) { - return 五十音[C][V] + return 五十音[C][V]; } else if (V == 'n') { - return 'ン' + return 'ン'; } else if (V == 'm') { - return 'ム' + return 'ム'; } else { throw new Error(`未知規則音節: ${音節}`); } }) - return 假名列表.join('') + return 假名列表.join(''); } -const 拉丁轉寫 = 組合聲韻(聲母, 韻母) +const 拉丁轉寫 = 組合聲韻(聲母, 韻母); // return `${片假名化(拉丁轉寫)} (${拉丁轉寫.replace("0", "")})` return 開關.假名 ? 片假名化(拉丁轉寫) : 拉丁轉寫.replace("0", ""); From 9324efe47d52fb7d2b1578da7a47c8920d9d55f0 Mon Sep 17 00:00:00 2001 From: mkpoli Date: Thu, 24 Dec 2020 16:34:23 +0900 Subject: [PATCH 09/11] Group switch cases --- kan-on.js | 86 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/kan-on.js b/kan-on.js index 67356fa..e9f3c3d 100644 --- a/kan-on.js +++ b/kan-on.js @@ -29,44 +29,54 @@ if (!開關.小假名) function 聲母規則() { switch (音韻地位.母) { - case '幫': return 'f'; - case '滂': return 'f'; - case '並': return 'f'; - case '明': return 'm'; - case '端': return 't'; - case '透': return 't'; - case '定': return 't'; - case '泥': return 'd'; - case '知': return 't'; - case '徹': return 't'; - case '澄': return 't'; - case '孃': return 'd'; - case '精': return 's'; - case '清': return 's'; - case '從': return 's'; - case '心': return 's'; - case '邪': return 's'; - case '莊': return 's'; - case '初': return 's'; - case '崇': return 's'; - case '生': return 's'; - case '俟': return 's'; - case '章': return 's'; - case '昌': return 's'; - case '船': return 's'; - case '書': return 's'; - case '常': return 's'; - case '見': return 'k'; - case '溪': return 'k'; - case '羣': return 'k'; - case '疑': return 'g'; - case '影': return '0'; - case '曉': return 'k'; - case '匣': return 'k'; - case '云': return '0'; - case '以': return '0'; - case '來': return 'r'; - case '日': return 'z'; + case '幫': + case '滂': + case '並': + return 'f'; + case '明': + return 'm'; + case '端': + case '透': + case '定': + case '知': + case '徹': + case '澄': + return 't'; + case '泥': + case '孃': + return 'd'; + case '精': + case '清': + case '從': + case '心': + case '邪': + case '莊': + case '初': + case '崇': + case '生': + case '俟': + case '章': + case '昌': + case '船': + case '書': + case '常': + return 's'; + case '見': + case '溪': + case '羣': + case '曉': + case '匣': + return 'k'; + case '疑': + return 'g'; + case '影': + case '云': + case '以': + return '0'; + case '來': + return 'r'; + case '日': + return 'z'; default: throw new Error('無聲母規則'); } } From 1479fe897f00bc952ef3f43cb0d61f7a36b7d1db Mon Sep 17 00:00:00 2001 From: mkpoli Date: Thu, 24 Dec 2020 20:19:26 +0900 Subject: [PATCH 10/11] Add small ng switch --- kan-on.js | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/kan-on.js b/kan-on.js index e9f3c3d..f38bfc1 100644 --- a/kan-on.js +++ b/kan-on.js @@ -19,6 +19,7 @@ const 開關 = {}; 開關.小假名 = true; // 開:キャウ 關:キヤウ 開關.分mn = true; // 開:サム 關:サン +開關.小假名陽聲韻 = false; // 開:カゥ 關:カウ 開關.wiwe = true; // 開:ク𛅥ン 關:ケン 開關.小假名wiwe = true; // 開:ク𛅥ン 關:クヱン @@ -207,15 +208,17 @@ let 韻母 = 韻母規則(); // == 韻尾規則 == +var ŋ = false; + // 入聲韻尾 if (is('入聲')) { - if (韻母.endsWith('m')) { - 韻母 = 韻母.slice(0, -1) + 'fu'; - } else if (韻母.endsWith('n')) { - 韻母 = 韻母.slice(0, -1) + 'tu'; - } else if (韻母.endsWith('ŋ')) { - 韻母 = 韻母.slice(0, -1) + (韻母[韻母.length - 2] == 'e' ? 'ki' : 'ku'); - } + 入聲韻尾 = { + "m": 'fu', + "n": 'tu', + "ŋ": 韻母[韻母.length - 2] == 'e' ? 'ki' : 'ku' + } + + 韻母 = 韻母.slice(0, -1) + 入聲韻尾[韻母.slice(-1)] } // 鼻音韻尾同化鼻音聲母 @@ -228,6 +231,7 @@ if (聲母 == 'm' && (!韻母.endsWith('ŋ') || 韻母.startsWith('u') || is(' // 後鼻音韻尾 if (韻母.endsWith('ŋ')) { 韻母 = 韻母.slice(0, -1) + (['e', 'i'].includes(韻母[韻母.length - 2]) ? 'i': 'u'); + ŋ = true; } // 汚 0o -> wo @@ -357,6 +361,10 @@ function 片假名化(拉丁轉寫) { } }) + if (開關.小假名陽聲韻 && ŋ) { + 假名列表[假名列表.length - 1] = 假名列表[假名列表.length - 1] == "ウ" ? "ゥ" : "ィ" + } + return 假名列表.join(''); } From 0071030e201074da258f2dfb1a01d4222fbdf228 Mon Sep 17 00:00:00 2001 From: mkpoli Date: Thu, 24 Dec 2020 20:47:33 +0900 Subject: [PATCH 11/11] Add kwyok and fixed kwyau --- kan-on.js | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/kan-on.js b/kan-on.js index f38bfc1..e0b7ea1 100644 --- a/kan-on.js +++ b/kan-on.js @@ -9,6 +9,11 @@ * * 函數接受音韻地位,返回對應的推導日語漢音 * + * 已知問題: + * 况 クヰャウ キャウ + * 矍 クヰャク クヮク ○ キャク ✕ + * 洫 クヰョク キョク + * */ const is = (x) => 音韻地位.屬於(x); @@ -23,7 +28,7 @@ const 開關 = {}; 開關.wiwe = true; // 開:ク𛅥ン 關:ケン 開關.小假名wiwe = true; // 開:ク𛅥ン 關:クヱン -開關.kwiyau = true; // 開:ク𛅥ャウ 關:キャウ +開關.kwyau = true; // 開:ク𛅥ャウ 關:キャウ if (!開關.小假名) 開關.小假名wiwe = false; @@ -171,7 +176,7 @@ function 韻母規則() { if (is('開口 一等 唐韻')) return 'aŋ'; if (is('開口 三等 陽韻')) return is('莊組') ? 'aŋ' : 'yaŋ'; if (is('合口 一等 唐韻')) return 'waŋ'; - if (is('合口 三等 陽韻')) return is('見組 或 影曉母') ? 'wiyaŋ' : 'waŋ'; + if (is('合口 三等 陽韻')) return is('見組 或 影曉母') ? 'wyaŋ' : 'waŋ'; // 梗攝 if (is('開口 二等 庚韻')) return is('見幫知組 或 匣母') ? 'aŋ' : 'eŋ'; if (is('開口 二等 耕韻')) return 'aŋ'; @@ -187,7 +192,7 @@ function 韻母規則() { if (is('開口 一等 登韻')) return 'oŋ'; if (is('開口 三等 蒸韻')) return 'yoŋ'; if (is('合口 一等 登韻')) return 'oŋ'; - if (is('合口 三等 蒸韻')) return 'yoŋ'; + if (is('合口 三等 蒸韻')) return is('見組 或 影曉母') ? 'wyoŋ' : 'yoŋ'; // 通攝 if (is('一等 東韻')) return 'oŋ'; if (is('三等 鍾韻')) return 'yoŋ'; @@ -282,7 +287,7 @@ function 組合聲韻(聲母, 韻母) { 韻母 = 韻母.slice(0, -1) + "n"; if (!開關.wiwe && 聲母 != "0") - 韻母 = 韻母.replace("wiy", "y").replace("wi", "i").replace("we", "e"); + 韻母 = 韻母.replace("wy", "y").replace("wi", "i").replace("we", "e"); return [聲母, 韻母].join(""); } @@ -318,8 +323,14 @@ function 片假名化(拉丁轉寫) { } // 二合拗音:wiyau > 𛅤ャウ - if (拉丁轉寫.endsWith('wiyau')) - return `${五十音[拉丁轉寫[0]]['u']}${開關.小假名wiwe ? '𛅤ャ' : 'ヰヤ'}ウ`; + if (拉丁轉寫.includes("wy")){ + const wy = { + "wya": 開關.小假名wiwe ? '𛅤ャ' : 'ヰヤ', + "wyo": 開關.小假名wiwe ? '𛅤ョ' : 'ヰヨ' + } + return `${五十音[拉丁轉寫[0]]['u']}${wy[拉丁轉寫.slice(1, 4)]}ウ`; + } + // CVVCV > CV.V.CV // Ref: https://stackoverflow.com/a/49407494/2719898