Last active
February 5, 2023 10:10
-
-
Save skytomo221/a164aa746a9c8d5d55bc5c64aa724ac1 to your computer and use it in GitHub Desktop.
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
# frozen_string_literal: true | |
require 'io/console' | |
VV_ROMAJIS = { | |
'3' => 'oo', | |
'7' => 'ua', | |
'8' => 'ia', | |
'9' => 'oa', | |
'q' => 'ae', | |
's' => 'ai', | |
'f' => 'ei', | |
'h' => 'oi', | |
';' => 'ou', | |
'x' => 'ui', | |
'm' => 'uu', | |
',' => 'ii' | |
}.freeze | |
VN_ROMAJIS = { | |
'd' => 'eq', | |
'j' => 'uq', | |
'k' => 'iq', | |
'l' => 'oq', | |
'z' => 'aq' | |
}.freeze | |
W_ROMAJIS = VV_ROMAJIS.merge VN_ROMAJIS | |
VC_ROMAJIS = { | |
't' => 'aw', | |
'p' => 'ur', | |
'@' => 'er', | |
'g' => 'ek', | |
':' => 'or', | |
'c' => 'ir', | |
'v' => 'ak', | |
'n' => 'uk', | |
'.' => 'ok', | |
'/' => 'ik' | |
}.freeze | |
CONSONANTS = %w[l ly k ky g gy s sy x z zy j c t ty t5 d dy d5 d6 n ny h hy f p py b by bb m my y r ry w wy].freeze | |
# input methods | |
# - V | |
# - C + V | |
# - N | |
# - C + W | |
# - C + VC + V | |
# - C + VC + W | |
# - others | |
# - symbols | |
# - any + r | |
# - q + any | |
# - shortcuts | |
V = { | |
'a' => 'あ', | |
'i' => 'い', | |
'u' => 'う', | |
'e' => 'え', | |
'o' => 'お' | |
}.freeze | |
C_V = { | |
'la' => 'ぁ', | |
'li' => 'ぃ', | |
'lu' => 'ぅ', | |
'le' => 'ぇ', | |
'lo' => 'ぉ', | |
'lya' => 'ゃ', | |
'lyi' => 'ぃ', | |
'lyu' => 'ゅ', | |
'lye' => 'ぇ', | |
'lyo' => 'ょ', | |
'ka' => 'か', | |
'ki' => 'き', | |
'ku' => 'く', | |
'ke' => 'け', | |
'ko' => 'こ', | |
'kya' => 'きゃ', | |
'kyi' => 'きい', | |
'kyu' => 'きゅ', | |
'kye' => 'きぇ', | |
'kyo' => 'きょ', | |
'ga' => 'が', | |
'gi' => 'ぎ', | |
'gu' => 'ぐ', | |
'ge' => 'げ', | |
'go' => 'ご', | |
'gya' => 'ぎゃ', | |
'gyi' => 'ぎい', | |
'gyu' => 'ぎゅ', | |
'gye' => 'ぎぇ', | |
'gyo' => 'ぎょ', | |
'sa' => 'さ', | |
'si' => 'し', | |
'su' => 'す', | |
'se' => 'せ', | |
'so' => 'そ', | |
'sya' => 'しゃ', | |
'syi' => 'しい', | |
'syu' => 'しゅ', | |
'sye' => 'しぇ', | |
'syo' => 'しょ', | |
'xa' => 'しゃ', | |
'xi' => 'し', | |
'xu' => 'しゅ', | |
'xe' => 'しぇ', | |
'xo' => 'しょ', | |
'za' => 'ざ', | |
'zi' => 'じ', | |
'zu' => 'ず', | |
'ze' => 'ぜ', | |
'zo' => 'ぞ', | |
'zya' => 'じゃ', | |
'zyi' => 'じい', | |
'zyu' => 'じゅ', | |
'zye' => 'じぇ', | |
'zyo' => 'じょ', | |
'ja' => 'じゃ', | |
'ji' => 'じ', | |
'ju' => 'じゅ', | |
'je' => 'じぇ', | |
'jo' => 'じょ', | |
'ca' => 'ちゃ', | |
'ci' => 'ち', | |
'cu' => 'ちゅ', | |
'ce' => 'ちぇ', | |
'co' => 'ちょ', | |
'ta' => 'た', | |
'ti' => 'ち', | |
'tu' => 'つ', | |
'te' => 'て', | |
'to' => 'と', | |
'tya' => 'てゃ', | |
'tyi' => 'てぃ', | |
'tyu' => 'とぅ', | |
'tye' => 'てぇ', | |
'tyo' => 'てょ', | |
't5a' => 'つぁ', | |
't5i' => 'つぃ', | |
't5u' => 'つ', | |
't5e' => 'つぇ', | |
't5o' => 'つぉ', | |
'da' => 'だ', | |
'di' => 'ぢ', | |
'du' => 'づ', | |
'de' => 'で', | |
'do' => 'ど', | |
'dya' => 'ぢゃ', | |
'dyi' => 'ぢぃ', | |
'dyu' => 'ぢゅ', | |
'dye' => 'ぢぇ', | |
'dyo' => 'ぢょ', | |
'd5a' => 'だぁ', | |
'd5i' => 'でぃ', | |
'd5u' => 'どぅ', | |
'd5e' => 'でぇ', | |
'd5o' => 'どぉ', | |
'd6a' => 'でゃ', | |
'd6i' => 'でぃ', | |
'd6u' => 'でゅ', | |
'd6e' => 'でぇ', | |
'd6o' => 'でょ', | |
'na' => 'な', | |
'ni' => 'に', | |
'nu' => 'ぬ', | |
'ne' => 'ね', | |
'no' => 'の', | |
'nya' => 'にゃ', | |
'nyi' => 'にい', | |
'nyu' => 'にゅ', | |
'nye' => 'にぇ', | |
'nyo' => 'にょ', | |
'ha' => 'は', | |
'hi' => 'ひ', | |
'hu' => 'ふ', | |
'he' => 'へ', | |
'ho' => 'ほ', | |
'hya' => 'ひゃ', | |
'hyi' => 'ひい', | |
'hyu' => 'ひゅ', | |
'hye' => 'ひぇ', | |
'hyo' => 'ひょ', | |
'fa' => 'ふぁ', | |
'fi' => 'ふぃ', | |
'fu' => 'ふ', | |
'fe' => 'ふぇ', | |
'fo' => 'ふぉ', | |
'pa' => 'ぱ', | |
'pi' => 'ぴ', | |
'pu' => 'ぷ', | |
'pe' => 'ぺ', | |
'po' => 'ぽ', | |
'pya' => 'ぴゃ', | |
'pyi' => 'ぴい', | |
'pyu' => 'ぴゅ', | |
'pye' => 'ぴぇ', | |
'pyo' => 'ぴょ', | |
'ba' => 'ば', | |
'bi' => 'び', | |
'bu' => 'ぶ', | |
'be' => 'べ', | |
'bo' => 'ぼ', | |
'bya' => 'びゃ', | |
'byi' => 'びい', | |
'byu' => 'びゅ', | |
'bye' => 'びぇ', | |
'byo' => 'びょ', | |
'bba' => 'ゔぁ', | |
'bbi' => 'ゔぃ', | |
'bbu' => 'ゔ', | |
'bbe' => 'ゔぇ', | |
'bbo' => 'ゔぉ', | |
'ma' => 'ま', | |
'mi' => 'み', | |
'mu' => 'む', | |
'me' => 'め', | |
'mo' => 'も', | |
'mya' => 'みゃ', | |
'myi' => 'みい', | |
'myu' => 'みゅ', | |
'mye' => 'みぇ', | |
'myo' => 'みょ', | |
'ya' => 'や', | |
'yi' => 'ゆい', | |
'yu' => 'ゆ', | |
'ye' => 'ゆえ', | |
'yo' => 'よ', | |
'ra' => 'ら', | |
'ri' => 'り', | |
'ru' => 'る', | |
're' => 'れ', | |
'ro' => 'ろ', | |
'rya' => 'りゃ', | |
'ryi' => 'りい', | |
'ryu' => 'りゅ', | |
'rye' => 'りぇ', | |
'ryo' => 'りょ', | |
'wa' => 'わ', | |
'wi' => 'うぃ', | |
'wu' => 'う', | |
'we' => 'うぇ', | |
'wo' => 'を', | |
'wya' => 'わ', | |
'wyi' => 'ゐ', | |
'wyu' => 'う', | |
'wye' => 'ゑ', | |
'wyo' => 'を' | |
}.freeze | |
N = { | |
'q' => 'ん', | |
'v' => 'ん' | |
}.freeze | |
# String Extension | |
class String | |
def frist_romaji_chunk_to_kana(replaces, replaced) | |
replaces.each do |pattern, replace| | |
next unless start_with?(pattern) | |
return [replaced + replace, self[pattern.length..]] | |
end | |
end | |
def romaji_to_kana(replaces) | |
romaji = self | |
kana = '' | |
kana, romaji = romaji.frist_romaji_chunk_to_kana(replaces, kana) until romaji.empty? | |
kana | |
end | |
end | |
def c_w | |
CONSONANTS.map do |consonant| | |
W_ROMAJIS.map do |pattern, replace| | |
[consonant + pattern, (consonant + replace).romaji_to_kana(C_V.merge(V).merge(N))] | |
end | |
end.flatten(1).to_h | |
end | |
def c_vc_v | |
CONSONANTS.map do |consonant| | |
VC_ROMAJIS.map do |vc_pattern, vc_replace| | |
V.map do |v, _| | |
[consonant + vc_pattern + v, (consonant + vc_replace + v).romaji_to_kana(C_V.merge(V).merge(N))] | |
end | |
end | |
end.flatten(2).to_h | |
end | |
def c_vc_w | |
CONSONANTS.map do |consonant| | |
VC_ROMAJIS.map do |vc_pattern, vc_replace| | |
W_ROMAJIS.map do |w_pattern, w_replace| | |
[consonant + vc_pattern + w_pattern, (consonant + vc_replace + w_replace).romaji_to_kana(C_V.merge(V).merge(N))] | |
end | |
end | |
end.flatten(2).to_h | |
end | |
SYMBOLS = { | |
'\d' => '°', | |
'\j' => '←', | |
'\k' => '↓', | |
'\l' => '↑', | |
'\;' => '→', | |
'\p' => '¶', | |
'\pp' => '⁋', | |
'\ppp' => '❡', | |
'\s' => '§' | |
}.freeze | |
OTHERS = { | |
'y' => 'いい', | |
';' => 'っ', | |
'-' => 'ー', | |
"'" => 'ー', | |
',' => '、', | |
'.' => '。', | |
'{' => '「', | |
'}' => '」' | |
}.freeze | |
ANY_R = { | |
'qr' => 'かる', | |
'kr' => 'くる', | |
'gr' => 'ぐる', | |
'cr' => 'ちる', | |
'sr' => 'する', | |
'xr' => 'さる', | |
'zr' => 'ざる', | |
'tr' => 'とる', | |
'dr' => 'だる', | |
'nr' => 'なる', | |
'ny' => 'にゃる', | |
'hr' => 'はる', | |
'br' => 'べる', | |
'vr' => 'ばる', | |
'mr' => 'みる', | |
'yr' => 'いる', | |
'jr' => 'やる', | |
'rr' => 'れる', | |
'wr' => 'うる' | |
}.freeze | |
Q_ANY = { | |
'q,' => '…', | |
'q.' => '‥', | |
'q/' => '・' | |
}.freeze | |
SHORTCUTS = { | |
'::' => 'ー', | |
':,' => ',', | |
':.' => '.', | |
':;t' => 'なった', | |
':a' => 'ああ', | |
':i' => 'いい', | |
':u' => 'うう', | |
':e' => 'ええ', | |
':o' => 'おお', | |
':d' => 'ので', | |
':dh' => 'のでは', | |
':ds' => 'ください', | |
':hy' => 'もはや', | |
':h' => 'のは', | |
':l' => 'であり', | |
':lm' => 'であります', | |
':s' => 'ます', | |
':sk' => 'ますか', | |
':sg' => 'ますが', | |
':st' => 'ました', | |
':sn' => 'ますね', | |
':s3' => 'ますけど', | |
':sv' => 'ますから', | |
':s.' => 'ますので', | |
':t' => 'こと', | |
':tm' => 'とても', | |
':th' => 'しては', | |
':t9' => 'してください', | |
':tg' => 'ことが', | |
':tt' => 'ことと', | |
':td' => 'ことで', | |
':tn' => 'ほんとうに', | |
':c' => 'です', | |
':ck' => 'ですか', | |
':cg' => 'ですが', | |
':ct' => 'でした', | |
':cn' => 'ですね', | |
':c3' => 'ですけど', | |
':cv' => 'ですから', | |
':c.' => 'ですので', | |
':z' => 'まず', | |
':jn' => 'ひじょうに', | |
':k' => 'ないか', | |
':ks' => 'しかし', | |
':km' => 'できます', | |
':k,' => 'できません', | |
':kn' => 'おこな', | |
':kd' => 'だけど', | |
':n' => 'えん', | |
':ng' => 'おねがい', | |
':nh' => 'るのは', | |
':nt' => 'ものと', | |
':nd' => 'なので', | |
':nk' => 'きなく', | |
':r' => 'する', | |
':rm' => 'やります', | |
':rk' => 'するか', | |
':rg' => 'するが', | |
':rn' => 'するね', | |
':rb' => 'ければ', | |
':r3' => 'するけど', | |
':rv' => 'するから', | |
':r.' => 'するので', | |
':63' => 'やるけど', | |
':6v' => 'やるから', | |
':6.' => 'やるので', | |
':r9' => 'ごらんください', | |
':rh' => 'それは', | |
':rd' => 'それで', | |
':x' => 'である', | |
':xg' => 'であるが', | |
':,h' => 'としては', | |
':xt' => 'として', | |
':9' => 'てください', | |
':gt' => 'ぼごた', | |
':g' => 'だが', | |
':m' => 'します', | |
':vn' => 'こんな', | |
':vj' => 'かんじ' | |
}.freeze | |
# String Extension | |
class String | |
def split_to_chunks(replaces, splited_romaji = [], splited_kana = []) | |
replaces.each do |pattern, replace| | |
next unless start_with?(pattern) | |
return self[pattern.length..] | |
.split_to_chunks(replaces, splited_romaji.append(pattern), splited_kana.append(replace)) | |
end | |
[splited_romaji, splited_kana, self] | |
end | |
def to_three_letters | |
return self[...3] if length > 3 | |
"#{length < 3 ? ' ' : ''}#{self}#{length < 2 ? ' ' : ''}#{length < 1 ? ' ' : ''}" | |
end | |
end | |
def color_chunks(strings, palette) | |
strings.map.with_index do |string, i| | |
"#{palette[i % palette.length]}#{string}\e[0m" | |
end | |
end | |
ROMAJI_TABLE = V.merge(C_V) | |
.merge(c_w) | |
.merge(c_vc_v) | |
.merge(c_vc_w) | |
.merge(N) | |
.merge(SYMBOLS) | |
.merge(OTHERS) | |
.merge(ANY_R) | |
.merge(Q_ANY) | |
.merge(SHORTCUTS) | |
.filter { |input, _| input.length < 4 } | |
.freeze | |
KEYBOARD_AA = "┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐\n" \ | |
"│ │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ - │ ^ │ │\n" \ | |
"├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤\n" \ | |
"│ │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │ @ │ [ │ │\n" \ | |
"├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐ │\n" \ | |
"│ │ A │ S │ D │ F │ G │ H │ J │ K │ L │ ; │ : │ ] │ │\n" \ | |
"├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────┤\n" \ | |
"│ │ Z │ X │ C │ V │ B │ N │ M │ , │ . │ / │ \\ │ │\n" \ | |
'└────────┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴──────┘' | |
def colored_typeable_keyboard(keyboard, remain, replaces) | |
(('0'..'9').to_a + ('a'..'z').to_a + ['-', '^', '@', '[', ';', ':', ']', ',', '.', ' ]']).each do |pattern, _| | |
color = replaces.any? { |r_pattern, _| r_pattern.start_with? "#{remain}#{pattern}" } ? "\e[1m\e[37m" : "\e[2m" | |
keyboard = keyboard.gsub(" #{pattern.upcase} ", "#{color}#{pattern.upcase.to_three_letters}\e[0m") | |
end | |
keyboard | |
end | |
def colored_keyboard(remain, replaces, romajis) | |
keyboard = KEYBOARD_AA | |
return colored_typeable_keyboard(keyboard, remain, replaces) unless CONSONANTS.include?(remain) | |
romajis.each do |pattern, replace| | |
keyboard = keyboard.gsub(" #{pattern[0].upcase} ", "\e[36m#{replace.to_three_letters}\e[0m") | |
end | |
colored_typeable_keyboard(keyboard, remain, replaces) | |
end | |
PALETTE = %W(\e[32m \e[33m \e[34m \e[35m).freeze | |
if ARGV.empty? | |
ROMAJI_TABLE.map { |input, output| puts "#{input}\t#{output}" } | |
elsif ARGV[0] == 'memo' | |
input = '' | |
first = true | |
puts '何か入力してください' | |
while (key = $stdin.getch) | |
print "\e[2K\e[1A" * (first ? 1 : 11) | |
print "\e[2K" | |
first = false | |
case key | |
when ?\C-c | |
exit | |
when "\u007f" | |
input = input[..-2] | |
when %r{[0-9a-z\-\^@\[;:\],./\\]} | |
input += key | |
end | |
splited_input, splited_output, remain = input.split_to_chunks(ROMAJI_TABLE) | |
colored_input = color_chunks(splited_input, PALETTE) | |
colored_output = color_chunks(splited_output, PALETTE) | |
puts "Input << #{colored_input.join}\e[31m#{remain}\e[0m" | |
puts "Output >> #{colored_output.join}\e[31m#{remain}\e[0m" | |
puts colored_keyboard(remain, ROMAJI_TABLE, W_ROMAJIS.merge(VC_ROMAJIS)) | |
end | |
elsif ARGV[0] == 'check' | |
ROMAJI_TABLE.each do |p1, r1| | |
ROMAJI_TABLE.each do |p2, r2| | |
next if p1 == p2 | |
puts "\e[33mWarning: Conflict {\"#{p1}\" => \"#{r1}\", \"#{p2}\" => \"#{r2}\"}\e[0m" if p1.start_with? p2 | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment