@wagurano 줄여서 와그, 루비니언, 평화를 사랑하며 코딩하는 프로그래머
서울 펄 몽거스의 펄 크리스마스 달력을 참고하여 루비 크리스마스 달력(Advent Calendar)에 참여하는 글입니다.
무엇보다 한글처리에 도움을 주신 neocoin 님에게 감사드립니다.
지난 11월 레일스럼블에 비타3천(vita3k) 프로젝트로 참여하였습니다. 누구나 한번쯤 친구들과 재미삼아 이름에 있는 글자를 획수로 하나둘씩 세면서 궁합점수를 계산해봤을텐데요. 봉봉과 ㅍㅍㅅㅅ에서도 해볼 수 있습니다. 배우 '장동건'씨와, '고소영'씨의 이름 궁합은 '1'으로 계산결과가 의미없다는 것을 잘 보여줍니다. 그러면 한글을 자모로 나누고 각 획수를 계산하는 과정을 보여드리겠습니다.
- ruby 1.9.3 이상
- 전체 소스코드
이름 궁합은 두사람의 이름을 한 글자씩 섞어서 나열한 다음 한글 자모의 획수를 그 아래에 적습니다. 획수를 순서대로 둘씩 짝지어 덧셈합니다. 다만, 그 아래에 적을 때는 한자리수만 적습니다. 예를 들면 '동'은 6, '소'는 4 이고 덧셈은 '10'이라서 '0'을 적습니다. 둘씩 짝지어 덧셈하는 과정을 두개가 남을때까지 반복합니다. '성유리'와 '이효리'를 예를 들어 계산해보겠습니다.
성 이 유 효 리 리 5 2 4 6 6 6 7 6 0 2 2 3 6 2 4 9 8 6 7 4
한글 자모를 처리하는 참고자료는 아래와 같습니다.
- 한글 인코딩의 이해 2편: 유니코드와 Java를 이용한 한글 처리
- 유니코드 정규화
- 한글 자모
참고자료를 토대로 neocoin님의 만들어둔 루비코드를 사용하였습니다.
한글 자모 중에서 'ㄱ'은 한획으로 쓰지만 이름 궁합으로 계산할 때는 가로 한번, 세로 한번으로 'ㄱ'을 2획으로 계산합니다.
따라서 아래와 같이
자음 | 획수 |
---|---|
ㄱ | 2 |
ㄲ | 4 |
ㄴ | 2 |
ㄷ | 3 |
ㄸ | 6 |
ㄹ | 5 |
ㅁ | 4 |
ㅂ | 4 |
ㅃ | 8 |
ㅅ | 2 |
ㅆ | 4 |
ㅇ | 1 |
ㅈ | 3 |
ㅉ | 6 |
ㅊ | 4 |
ㅋ | 3 |
ㅌ | 4 |
ㅍ | 4 |
ㅎ | 3 |
모음 | 획수 |
---|---|
ㅏ | 2 |
ㅐ | 3 |
ㅑ | 3 |
ㅒ | 4 |
ㅓ | 2 |
ㅔ | 3 |
ㅕ | 3 |
ㅖ | 4 |
ㅗ | 2 |
ㅘ | 4 |
ㅙ | 5 |
ㅚ | 3 |
ㅛ | 3 |
ㅜ | 2 |
ㅝ | 4 |
ㅞ | 5 |
ㅟ | 3 |
ㅠ | 3 |
ㅡ | 1 |
ㅢ | 2 |
ㅣ | 1 |
이중자모 | 획수 |
---|---|
ㄳ | 4 |
ㄵ | 5 |
ㄶ | 5 |
ㄺ | 7 |
ㄻ | 9 |
ㄼ | 9 |
ㄽ | 7 |
ㄾ | 9 |
ㄿ | 9 |
ㅀ | 8 |
ㅄ | 6 |
미리 정해두었습니다.
여기서는 String 클래스를 오픈하여 코드를 추가할 수 있으나 모듈로 구분하여 만들었습니다.
# '한'을 초성, 중성, 종성인 'ㅎ,ㅏ,ㄴ'으로 나눕니다.
def split_hangul char
point = char.codepoints.first
case point
when HANGUL_SYLLABLES_RANGE
uni_value = point - 0xAC00
jong = uni_value % 28
cho = ( ( uni_value - jong ) / 28 ) / 21
jung = ( ( uni_value - jong ) / 28 ) % 21
[TABLE_FOR_CHO[cho], TABLE_FOR_JUNG[jung], TABLE_FOR_JONG[jong]]
else
char
end
end
# 미리 정해둔 한글의 자모에 대한 획수를 계산합니다.
def count_strokes string
string.chars.map{ |char|
(split_hangul char).map{ |c| STROKES[c] }.inject(:+)
}
end
획수에 따라 두 사람의 이름 궁합을 계산하는 코드는 아래와 같습니다.
def to_strokes foo, bar
f = foo.chars
b = bar.chars
baz = Array.new(foo.size){ "#{f.shift}#{b.shift}" }.join ''
((count_strokes baz).join '').to_i
z = count_strokes baz
loop {
break if z.size <= 2
(z.size - 1).times { z << (z.shift + z[0]) % 10 }
z.shift
}
z.join('').to_i
end
- String#chars 메소드는 문자열을 낱글자 배열로 만듭니다.
- 두사람의 이름을 한글자씩 섞어서 문자열 하나로 만듭니다. 예를 들어 '장동건' + '고소영'은 '장고동소건영'으로 만듭니다.
- 합친 문자열의 획수를 배열로 먼저 만들고
- 둘씩 짝지어 덧셈하는 과정을 두자리가 남을 때까지 반복합니다.
- 최종 결과는 '00'~'99' 까지입니다.
세사람이상 하고 싶거나 알파벳으로 되어있는 이름도 궁합을 계산할 수 있도록
# 세사람 이상 이름 궁합 계산합니다.
def to_strokes_from list
c_list = list.map{ |x| x.chars }
baz = Array.new(c_list.first.size){ c_list.map{ |x| x.shift }.join '' }.join ''
((count_strokes baz).join '').to_i
z = count_strokes baz
loop {
break if z.size <= 2
(z.size - 1).times { z << (z.shift + z[0]) % 10 }
z.shift
}
z.join('').to_i
end
# 네이버 사전을 사용해서 알파벳으로 된 이름을 '한국어'로 읽을 때 '한글'로 표기합니다.
def to_korean word
a = Net::HTTP.get("translate.naver.com",
"/koreaPron.dic?query=#{word}&srcLang=en&tarLang=ko")
a.force_encoding('UTF-8').strip
end
# 한글, 알파벳 구분없이 두사람 이름 궁합을 계산합니다.
def to_strokes_global foo, bar
foo = foo.split.map{ |x| to_korean x }.join '' unless hangul? foo
bar = bar.split.map{ |x| to_korean x }.join '' unless hangul? bar
[foo, bar, to_strokes(foo, bar)]
end
이름 궁합은 즉흥적으로 만들어서 좀 더 다듬고 있습니다. 루비 1.9 에서도 하려면 shift 메소드에 대한 대안이 필요하고 라이브러리로 활용할 수 있도록 메소드 이름을 정리하고 있습니다. 이름 궁합이나 한글처리에 관심있으신분은 위의 코드를 참고하여 '젬'으로 만들어서 배포하면 좋겠습니다.
감사합니다.
EOT