require 'io/console'
dubeolsik = {
"q" => "ㅂ",
"Q" => "ㅃ",
"w" => "ㅈ",
"W" => "ㅉ",
"e" => "ㄷ",
"E" => "ㄸ",
"r" => "ㄱ",
"R" => "ㄲ",
"t" => "ㅅ",
"T" => "ㅆ",
"a" => "ㅁ",
"s" => "ㄴ",
"d" => "ㅇ",
"f" => "ㄹ",
"g" => "ㅎ",
"z" => "ㅋ",
"x" => "ㅌ",
"c" => "ㅊ",
"v" => "ㅍ",
"y" => "ㅛ",
"u" => "ㅕ",
"i" => "ㅑ",
"o" => "ㅐ",
"O" => "ㅒ",
"p" => "ㅔ",
"P" => "ㅖ",
"h" => "ㅗ",
"j" => "ㅓ",
"k" => "ㅏ",
"l" => "ㅣ",
"b" => "ㅠ",
"n" => "ㅜ",
"m" => "ㅡ"
}
@l_index = {
"ㄱ" => 0,
"ㄲ" => 1,
"ㄴ" => 2,
"ㄷ" => 3,
"ㄸ" => 4,
"ㄹ" => 5,
"ㅁ" => 6,
"ㅂ" => 7,
"ㅃ" => 8,
"ㅅ" => 9,
"ㅆ" => 10,
"ㅇ" => 11,
"ㅈ" => 12,
"ㅉ" => 13,
"ㅊ" => 14,
"ㅋ" => 15,
"ㅌ" => 16,
"ㅍ" => 17,
"ㅎ" => 18
}
@v_index = {
"ㅏ" => 0,
"ㅐ" => 1,
"ㅑ" => 2,
"ㅒ" => 3,
"ㅓ" => 4,
"ㅔ" => 5,
"ㅕ" => 6,
"ㅖ" => 7,
"ㅗ" => 8,
"ㅘ" => 9,
"ㅙ" => 10,
"ㅚ" => 11,
"ㅛ" => 12,
"ㅜ" => 13,
"ㅝ" => 14,
"ㅞ" => 15,
"ㅟ" => 16,
"ㅠ" => 17,
"ㅡ" => 18,
"ㅢ" => 19,
"ㅣ" => 20
}
@t_index = {
nil => 0,
"ㄱ" => 1,
"ㄲ" => 2,
"ㄳ" => 3,
"ㄴ" => 4,
"ㄵ" => 5,
"ㄶ" => 6,
"ㄷ" => 7,
"ㄹ" => 8,
"ㄺ" => 9,
"ㄻ" => 10,
"ㄼ" => 11,
"ㄽ" => 12,
"ㄾ" => 13,
"ㄿ" => 14,
"ㅀ" => 15,
"ㅁ" => 16,
"ㅂ" => 17,
"ㅄ" => 18,
"ㅅ" => 19,
"ㅆ" => 20,
"ㅇ" => 21,
"ㅈ" => 22,
"ㅊ" => 23,
"ㅋ" => 24,
"ㅌ" => 25,
"ㅍ" => 26,
"ㅎ" => 27
}
cc_rules = {
"ㄱㅅ" => "ㄳ",
"ㄴㅈ" => "ㄵ",
"ㄴㅎ" => "ㄶ",
"ㄹㄱ" => "ㄺ",
"ㄹㅁ" => "ㄻ",
"ㄹㅂ" => "ㄼ",
"ㄹㅅ" => "ㄽ",
"ㄹㅌ" => "ㄾ",
"ㄹㅍ" => "ㄿ",
"ㄹㅎ" => "ㅀ",
"ㅂㅅ" => "ㅄ",
}
vv_rules = {
"ㅗㅏ" => "ㅘ",
"ㅗㅐ" => "ㅙ",
"ㅗㅣ" => "ㅚ",
"ㅜㅓ" => "ㅝ",
"ㅜㅔ" => "ㅞ",
"ㅜㅣ" => "ㅟ",
"ㅡㅣ" => "ㅢ"
}
@state = :none
@seq = []
def reset
puts @c
@seq = []
@state = :none
end
def compose_hangul (l, v, t)
(@l_index[l] * 588 + @v_index[v] * 28 + @t_index[t] + 0xac00).chr("utf-8")
end
loop do
@c = STDIN.getch
@c.chomp!
if @c.empty?
puts
exit
end
unless dubeolsik[@c]
reset
next
end
case @state
when :none
puts "preedit: " + dubeolsik[@c]
@seq << @c
@state = :c if @l_index.include? dubeolsik[@c]
@state = :v if @v_index.include? dubeolsik[@c]
when :c
if @l_index.include? dubeolsik[@c]
cc = cc_rules[dubeolsik[@seq[0]] + dubeolsik[@c]]
if cc
puts "preedit: " + cc
@seq << @c
@state = :cc
else
puts "commit: " + dubeolsik[@seq[0]]
puts "preedit: " + dubeolsik[@c]
@seq = []
@seq << @c
@state = :c
end
elsif @v_index.include? dubeolsik[@c]
puts "preedit: " + compose_hangul(dubeolsik[@seq[0]], dubeolsik[@c], nil)
@seq << @c
@state = :lv
end
when :v
if @l_index.include? dubeolsik[@c]
puts "commit: " + dubeolsik[@seq[0]]
puts "preedit: " + dubeolsik[@c]
@seq = []
@seq << @c
@state = :c
elsif @v_index.include? dubeolsik[@c]
vv = vv_rules[dubeolsik[@seq[0]] + dubeolsik[@c]]
if vv
puts "preedit: " + vv
@seq << @c
@state = :vv
else
puts "commit: " + dubeolsik[@seq[0]]
puts "preedit: " + dubeolsik[@c]
@seq = []
@seq << @c
@state = :v
end
end
when :lv
if @t_index.include? dubeolsik[@c]
puts "preedit: " + compose_hangul(dubeolsik[@seq[0]], dubeolsik[@seq[1]], dubeolsik[@c])
@seq << @c
@state = :lvt
elsif @l_index.include? dubeolsik[@c]
puts "commit: " + compose_hangul(dubeolsik[@seq[0]], dubeolsik[@seq[1]], nil)
puts "preedit: " + dubeolsik[@c]
@seq = []
@seq << @c
@state = :c
elsif @v_index.include? dubeolsik[@c]
vv = vv_rules[dubeolsik[@seq[1]] + dubeolsik[@c]]
if vv
puts "preedit: " + compose_hangul(dubeolsik[@seq[0]], vv, nil)
@seq << @c
@state = :lvv
else
puts "commit: " + compose_hangul(dubeolsik[@seq[0]], dubeolsik[@seq[1]], nil)
puts "preedit: " + dubeolsik[@c]
@seq = []
@seq << @c
@state = :v
end
end
when :cc
if @l_index.include? dubeolsik[@c]
puts "commit: " + cc_rules[dubeolsik[@seq[0]] + dubeolsik[@seq[1]]]
puts "preedit: " + dubeolsik[@c]
@seq = []
@seq << @c
@state = :c
elsif @v_index.include? dubeolsik[@c]
puts "commit: " + dubeolsik[@seq[0]]
puts "preedit: " + compose_hangul(dubeolsik[@seq[1]], dubeolsik[@c], nil)
@seq.shift 1
@seq << @c
@state = :lv
end
when :vv
puts "commit: " + vv_rules[dubeolsik[@seq[0]] + dubeolsik[@seq[1]]]
puts "preedit: " + dubeolsik[@c]
@seq = []
@seq << @c
if @l_index.include? dubeolsik[@c]
@state = :c
elsif @v_index.include? dubeolsik[@c]
@state = :v
end
when :lvv
vv = vv_rules[dubeolsik[@seq[1]] + dubeolsik[@seq[2]]]
if @t_index.include? dubeolsik[@c]
puts "preedit: " + compose_hangul(dubeolsik[@seq[0]], vv, dubeolsik[@c])
@seq << @c
@state = :lvvt
elsif @l_index.include? dubeolsik[@c]
puts "commit: " + compose_hangul(dubeolsik[@seq[0]], vv, nil)
puts "preedit: " + dubeolsik[@c]
@seq = []
@seq << @c
@state = :c
elsif @v_index.include? dubeolsik[@c]
puts "commit: " + compose_hangul(dubeolsik[@seq[0]], vv, nil)
puts "preedit: " + dubeolsik[@c]
@seq = []
@seq << @c
@state = :v
end
when :lvt
if @l_index.include? dubeolsik[@c]
cc = cc_rules[dubeolsik[@seq[2]] + dubeolsik[@c]]
if cc
puts "preedit: " + compose_hangul(dubeolsik[@seq[0]], dubeolsik[@seq[1]], cc)
@seq << @c
@state = :lvtt
else
puts "commit: " + compose_hangul(dubeolsik[@seq[0]], dubeolsik[@seq[1]], dubeolsik[@seq[2]])
puts "preedit: " + dubeolsik[@c]
@seq = []
@seq << @c
@state = :c
end
elsif @v_index.include? dubeolsik[@c]
puts "commit: " + compose_hangul(dubeolsik[@seq[0]], dubeolsik[@seq[1]], nil)
puts "preedit: " + compose_hangul(dubeolsik[@seq[2]], dubeolsik[@c], nil)
@seq.shift 2
@seq << @c
@state = :lv
end
when :lvvt
if @l_index.include? dubeolsik[@c]
vv = vv_rules[dubeolsik[@seq[1]] + dubeolsik[@seq[2]]]
cc = cc_rules[dubeolsik[@seq[3]] + dubeolsik[@c]]
if cc
puts "preedit: " + compose_hangul(dubeolsik[@seq[0]], vv, cc)
@seq << @c
@state = :lvvtt
else
puts "commit: " + compose_hangul(dubeolsik[@seq[0]], vv, dubeolsik[@seq[3]])
puts "preedit: " + dubeolsik[@c]
@seq = []
@seq << @c
@state = :c
end
elsif @v_index.include? dubeolsik[@c]
vv = vv_rules[dubeolsik[@seq[1]] + dubeolsik[@seq[2]]]
puts "commit: " + compose_hangul(dubeolsik[@seq[0]], vv, nil)
puts "preedit: " + compose_hangul(dubeolsik[@seq[3]], dubeolsik[@c], nil)
@seq.shift 3
@seq << @c
@state = :lv
end
when :lvtt
if @l_index.include? dubeolsik[@c]
cc = cc_rules[dubeolsik[@seq[2]] + dubeolsik[@seq[3]]]
puts "commit: " + compose_hangul(dubeolsik[@seq[0]], dubeolsik[@seq[1]], cc)
puts "preedit: " + dubeolsik[@c]
@seq = []
@seq << @c
@state = :c
elsif @v_index.include? dubeolsik[@c]
puts "commit: " + compose_hangul(dubeolsik[@seq[0]], dubeolsik[@seq[1]], dubeolsik[@seq[2]])
puts "preedit: " + compose_hangul(dubeolsik[@seq[3]], dubeolsik[@c], nil)
@seq.shift 3
@seq << @c
@state = :lv
end
when :lvvtt
cc = cc_rules[dubeolsik[@seq[3]] + dubeolsik[@seq[4]]]
vv = vv_rules[dubeolsik[@seq[1]] + dubeolsik[@seq[2]]]
if @l_index.include? dubeolsik[@c]
puts "commit: " + compose_hangul(dubeolsik[@seq[0]], vv, cc)
puts "preedit: " + dubeolsik[@c]
@seq = []
@seq << @c
@state = :c
elsif @v_index.include? dubeolsik[@c]
puts "commit: " + compose_hangul(dubeolsik[@seq[0]], vv, dubeolsik[@seq[3]])
puts "preedit: " + compose_hangul(dubeolsik[@seq[4]], dubeolsik[@c], nil)
@seq.shift 4
@seq << @c
@state = :lv
end
else
raise "Unknown state #{@state.to_s}"
end
end
저거 c 로 포팅하는데, c 표준 api 가 뭐 같아서 그냥 glib 또 써야겠다. c 에 내장 hash 있어서 좀 알아봤더니... hcreate, hsearch 너무 그지같다
루비다루비
수백줄을 하이라이킹도 안하고 이렇게 툭 던져두면 누가 보라는거
저거 하이라이트 안 될 걸? 용량 초과 뜰거 같은데
그러니까 중요부분만 발췌하고 깃헙링크만 걸고 이래야지 왜 전부 올려
심심해서 올림 ㅋㅋㅋ
300백줄 밖에 안 되는데 놀라긴 ㅋㅋ
나도 3만줄 코드 있는데 심심하다고 올려봄?
양이 문제가 아니라 가독성이 넘 구려
해당 댓글은 삭제되었습니다.
저거 상태 머신임. 아무 입력 없을 때, :none 상태, :c 는 자음(초성, 종성 결정 전) :v 는 모음 :lv 는 초성 + 모음 상태 :cc 는 자음 + 자음 (초성, 종성 결정 전) :vv 는 모음 + 모음 (이중모음, ㅢ,ㅟ 이런거) :lvv 는 초성 + 모음 + 모음 (:c 상태에서 :vv 가 결합되면 :lvv 상태) :lvt 는 초성 + 모음 + 종성
:lvvt 는 초성 + 모음 + 모음 + 종성 :lvtt 는 초성 + 모음 + 종성 + 종성 (쌍자음) :lvvtt 는 초성 + 모음 + 모음(이중모음) + 종성 + 종성(쌍자음) :none 포함하여 11가지의 상태가 있음
세벌식는 받침에도 따로 할당해서 비슷하게 돌아가나?
아마 그럴거임. 위에서는 자음을 치면 그게 초성인지 종성인지 알 수 없는데, 세벌식은 명확히 알 수 있음. 다만, 모아치기 구현하려면 조금 번거로워지지. 위키문서인가... 세벌식이 두벌식보다 오토마타 만들기 쉽다고 그렇게 쓰여있던거 같은데, 내가 볼 때는 세벌식이 더 까다로움.
모아치기 빼면 더 쉽게 만들수 있으니 공병우께서 맨처음 만들었을것 같은데, 모아치기 처리는 어렵네
ㄱ +ㅏ+ ㄴ = 간, 1개 방법인데, 모아치기면 3 * 2 * 1 = 6가지 방법을 코드로 작성해야 함. 더 어렵지. 세벌식 장점은 모아치기인데, 사실은 세벌식이 두벌식보다 오토마타 설계가 어려워.
그렇게 설명해봤자 모른당께 책을 쓰랑께