Skip to content

Instantly share code, notes, and snippets.

@exceedsystem
Created February 23, 2024 03:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save exceedsystem/b87d3b98c2e7e38daf151b543bd03b31 to your computer and use it in GitHub Desktop.
Save exceedsystem/b87d3b98c2e7e38daf151b543bd03b31 to your computer and use it in GitHub Desktop.
Convert Kana to Hepburn romanization
const vscode = require('vscode');
/**
* マクロコンフィギュレーション(環境に合わせてお好みで設定)
*/
module.exports.macroCommands = {
'カナ→ヘボン式ローマ字': {
no: 1,
func: toHepburn
},
};
async function toHepburn() {
const editor = vscode.window.activeTextEditor;
if (!editor) {
return 'Editor is not open.';
}
// 選択範囲のテキストを取得
const document = editor.document;
const selection = editor.selection;
const text = document.getText(selection);
let kanaText = '';
if (text.length) {
kanaText = text;
} else {
kanaText = await vscode.window.showInputBox({ title: 'ローマ字変換する文字を全角カナで入力' });
if (!kanaText) {
return '';
}
}
const romaji = kanaToHepburnRomanization(kanaText);
editor.edit(editBuilder => {
// 処理結果を選択範囲に書き戻す
editBuilder.replace(selection, romaji);
});
}
function kanaToHepburnRomanization(kana) {
const kanaHepburnMap = {
'ア': 'a', 'イ': 'i', 'ウ': 'u', 'エ': 'e', 'オ': 'o',
'カ': 'ka', 'キ': 'ki', 'ク': 'ku', 'ケ': 'ke', 'コ': 'ko',
'サ': 'sa', 'シ': 'shi', 'ス': 'su', 'セ': 'se', 'ソ': 'so',
'タ': 'ta', 'チ': 'chi', 'ツ': 'tsu', 'テ': 'te', 'ト': 'to',
'ナ': 'na', 'ニ': 'ni', 'ヌ': 'nu', 'ネ': 'ne', 'ノ': 'no',
'ハ': 'ha', 'ヒ': 'hi', 'フ': 'fu', 'ヘ': 'he', 'ホ': 'ho',
'マ': 'ma', 'ミ': 'mi', 'ム': 'mu', 'メ': 'me', 'モ': 'mo',
'ヤ': 'ya', 'ユ': 'yu', 'ヨ': 'yo',
'ラ': 'ra', 'リ': 'ri', 'ル': 'ru', 'レ': 're', 'ロ': 'ro',
'ワ': 'wa', 'ヰ': 'i', 'ヱ': 'e', 'ヲ': 'o', 'ン': 'n',
'ガ': 'ga', 'ギ': 'gi', 'グ': 'gu', 'ゲ': 'ge', 'ゴ': 'go',
'ザ': 'za', 'ジ': 'ji', 'ズ': 'zu', 'ゼ': 'ze', 'ゾ': 'zo',
'ダ': 'da', 'ヂ': 'ji', 'ヅ': 'zu', 'デ': 'de', 'ド': 'do',
'バ': 'ba', 'ビ': 'bi', 'ブ': 'bu', 'ベ': 'be', 'ボ': 'bo',
'パ': 'pa', 'ピ': 'pi', 'プ': 'pu', 'ペ': 'pe', 'ポ': 'po',
'キャ': 'kya', 'キュ': 'kyu', 'キョ': 'kyo',
'シャ': 'sha', 'シュ': 'shu', 'ショ': 'sho',
'チャ': 'cha', 'チュ': 'chu', 'チョ': 'cho',
'ニャ': 'nya', 'ニュ': 'nyu', 'ニョ': 'nyo',
'ヒャ': 'hya', 'ヒュ': 'hyu', 'ヒョ': 'hyo',
'ミャ': 'mya', 'ミュ': 'myu', 'ミョ': 'myo',
'リャ': 'rya', 'リュ': 'ryu', 'リョ': 'ryo',
'ギャ': 'gya', 'ギュ': 'gyu', 'ギョ': 'gyo',
'ジャ': 'ja', 'ジュ': 'ju', 'ジョ': 'jo',
'ビャ': 'bya', 'ビュ': 'byu', 'ビョ': 'byo',
'ピャ': 'pya', 'ピュ': 'pyu', 'ピョ': 'pyo',
'シェ': 'she', 'チェ': 'che', 'ティ': 'ti', 'ニィ': 'ni', 'ニェ': 'nye',
'ファ': 'fa', 'フィ': 'fi', 'フェ': 'fe', 'フォ': 'fo', 'ジェ': 'je',
'ディ': 'di', 'デュ': 'dyu', 'ウィ': 'wi', 'ウェ': 'we', 'ウォ': 'wo',
'ヴァ': 'va', 'ヴィ': 'vi', 'ヴェ': 've', 'ヴォ': 'vo',
'ー': ''
};
function getRomaji(t) {
return kanaHepburnMap[t] ?? '';
}
let romaji = '';
for (let i = 0; i < kana.length; i++) {
const currentChar = kana[i]
const nextChar = kana[i + 1] ?? '';
if (currentChar === 'ン') {
// 撥音
if (['バ', 'ビ', 'ブ', 'ベ', 'ボ', 'パ', 'ピ', 'プ', 'ペ', 'ポ', 'マ', 'ミ', 'ム', 'メ', 'モ'].includes(nextChar)) {
// :B/M/Pの前の「ん」はMで表現
romaji += 'm';
} else {
// nで表現
romaji += 'n';
}
} else if (currentChar === 'ッ') {
// 促音
if (['チ', 'チャ', 'チュ', 'チョ'].includes(nextChar)) {
// チ(chi)/チャ(cha)/チュ(chu)/チョ(cho)の場合はtを付加
romaji += 't';
} else {
// 子音を重ねる
romaji += getRomaji(nextChar)[0] ?? '';
}
}
else {
// 撥音・促音以外
let hepburn = getRomaji(currentChar + nextChar);
if (hepburn && nextChar) {
// 2文字処理した場合は次の文字をスキップ
++i;
} else {
// そのまま出力
hepburn = getRomaji(currentChar);
}
romaji += hepburn;
}
}
// 「オ」を含む長音オオ(oo)の場合はoを重ねない
romaji = romaji.replace(/oo(?!$)/g, 'o');
// 「ウ」を含む長音ウウ(uu))の場合はuを重ねない
romaji = romaji.replace(/uu/g, 'u');
// 「オウ」音でヨミカタが「ウ」の場合uを付加しない
romaji = romaji.replace(/ou/g, 'o');
return romaji;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment