Skip to content

Instantly share code, notes, and snippets.

@skytomo221
Last active February 5, 2023 10:10
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 skytomo221/a164aa746a9c8d5d55bc5c64aa724ac1 to your computer and use it in GitHub Desktop.
Save skytomo221/a164aa746a9c8d5d55bc5c64aa724ac1 to your computer and use it in GitHub Desktop.
# 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