Presentation is loading. Please wait.

Presentation is loading. Please wait.

Ruby 프로그래밍 한글 로마자화 한국어 정보의 전산 처리 2017. 5. 17..

Similar presentations


Presentation on theme: "Ruby 프로그래밍 한글 로마자화 한국어 정보의 전산 처리 2017. 5. 17.."— Presentation transcript:

1 Ruby 프로그래밍 한글 로마자화 한국어 정보의 전산 처리

2 jaso_call_me.rb의 함수들을 메소드로 바꾸기
한글인지 아닌지 판정, 초성,중성,종성 알아내기는 문자열에 대해서만 수행하는 일이므로, 이들 함수를 free function보다는 String class 내의 메소드로 정의하는 것이 합리적임. class String def hangeul? (0xac00..0xd7a3).include? self.ord end def onset #반환값은 0~18, 0: ㄱ. 1: ㄲ, ..., 18: ㅎ (self.ord - 0xac00) / 588 def nucleus #반환값은 0~20, 0: ㅏ, 1: ㅐ, ..., 20: ㅣ ( (self.ord - 0xac00) % 588 ) / 28 def coda # 반환값은 0~27, 0: 받침없음, 1: ㄱ, 2: ㄲ, : ㅎ (self.ord - 0xac00) % 28

3 로마자화 프로그램의 구조 입력: 한글 문자열 (한글 아닌 문자가 중간에 들어 있어도 무방)
출력: 한글을 로마자로 변환하여 출력. 기타 문자는 그대로 출력. String 클래스에 romanize 메소드 추가 Syllable 클래스 추가: 초성, 중성, 종성 3개의 멤버 변수를 포함 음운규칙의 적용 방식 방법1: 한글->로마자화->음운규칙 방법2: 한글->음운규칙->로마자화 : 방법2를 택함. 음운규칙 적용을 위해 String을 우선 Syllable들의 Array로 변환 phon 함수: Syllable들의 Array를 입력으로 받아, 음운규칙 적용한 뒤, Syllable들의 Array를 반환 phon 함수 내부에서 각종 음운규칙 함수를 호출하여 사용 romanize 메소드에서 phon 함수를 호출하여 음운규칙이 적용된 Syllable들의 Array를 받아서 각 syllable의 초성, 중성, 종성을 각각 로마자로 변환 이렇게 로마자로 변환된 결과를 문자열로 통합: join 메소드 이용

4 Syllable class 정의 class Syllable #음절 클래스. 초성, 중성, 종성 3개의 멤버로 이루어져 있음.
attr_accessor :onset, :nucleus, :coda #이 class의 3개의 멤버를 class 외부에서도 참조할 수 있도록 개방. #음운규칙 적용시 필요함. def initialize(onset=nil, nucleus=nil, coda=nil) #이 class에 속하는 object를 만들 때(new) 멤버들의 값을 초기화 #값을 주지 않으면 nil로 초기화 @onset = onset @nucleus = nucleus @coda = coda end

5 String class에 to_syls 메소드 추가
def to_syls #Syllable들의 Array로 변환. 나중에 음운규칙의 적용을 위해) syls = [] #결과를 저장할 Syllable들의 Array self.each_char do |c| #입력 문자열의 각 문자 c에 대해 c = 'U' if c.ord #c가 한자이면 이것을 대응하는 한글로 바꿔줌 syls << (c.hangeul? ? Syllable.new(c.onset, c.nucleus, c.coda) : c) #c가 한글이면 한글 음절의 초성,중성,종성 값을 구하여 이 셋으로 #Syllable instance를 만들어 syls에 추가 #c가 한글이 아니면 그냥 c 자체를 syls에 추가 end #syls: [제1음절[초,중,종],제2음절[초,중,종], ..., 끝음절[초,중,종]] syls #syls Array 반환 end

6 String class에 romanize 메소드 추가
def romanize #romanize 메소드 추가 #onsets=['ㄱ','ㄲ','ㄴ','ㄷ','ㄸ','ㄹ','ㅁ','ㅂ','ㅃ','ㅅ','ㅆ','ㅇ','ㅈ','ㅉ','ㅊ','ㅋ','ㅌ','ㅍ','ㅎ'] onset2alpha=['g','kk','n','d','tt','r','m','b','pp','s','ss','','j','jj','ch','k','t','p','h','l'] #맨끝에 ㄹ→l 추가. 보통의 초성 ㄹ=r, ㄹ 뒤의 초성 ㄹ=l #nuclei=['ㅏ','ㅐ','ㅑ','ㅒ','ㅓ','ㅔ','ㅕ','ㅖ','ㅗ','ㅘ','ㅙ','ㅚ','ㅛ','ㅜ','ㅝ','ㅞ','ㅟ','ㅠ','ㅡ','ㅢ','ㅣ'] nucleus2alpha = ['a','ae','ya','yae','eo','e','yeo','ye','o','wa','wae','oe','yo','u','wo','we','wi','yu','eu','ui','i'] #codas = ['채움','ㄱ','ㄲ','ㄳ','ㄴ','ㄵ','ㄶ','ㄷ','ㄹ','ㄺ','ㄻ','ㄼ','ㄽ','ㄾ','ㄿ','ㅀ','ㅁ',' ㅂ','ㅄ','ㅅ','ㅆ','ㅇ','ㅈ','ㅊ','ㅋ','ㅌ','ㅍ','ㅎ'] coda2alpha = #ㄱ,ㄷ,ㅂ 초성은 g, d, b인 데 비해 종성은 k, t, p ['','k','k','k','n','n','n','t','l','k','m','p','l','l','p','l','m','p','p','t','t','ng','t','t','k','t','p','t'] self.to_syls.map{ |syl| syl.class()==Syllable ? onset2alpha[syl.onset] + nucleus2alpha[syl.nucleus] + coda2alpha[syl.coda] : syl }.join("") end #Syllable인 것은 위의 세 Array에서 대응하는 로마자로 바꿈 #Syllable이 아닌 것은 원래 것 그대로

7 음운규칙 적용 국어의 로마자 표기법에서 경음화는 반영하지 않음. ㅎ 축약은 명사에서는 반영하지 않고, 용언에서만 반영.
한국어의 대개의 음운 규칙은 앞 음절의 종성과 뒤 음절의 초성 사이 에서 일어남. 다음의 순서로 반영함. 재음절화 (연음법칙): 밥이→바비, 숲을→수플 초성 ㄹ 관련 규칙: 역행 유음화, 초성 ㄹ 제약 순행 유음화 비음화: {ㅂ, ㄷ, ㄱ} → {ㅁ, ㄴ, ㅇ} / __ 비음 ㅎ 축약: {ㅂ, ㄷ, ㅈ, ㄱ} ~ ㅎ → {ㅍ, ㅌ, ㅊ, ㅋ} 구개음화 일부 반영: 닫히다 /다치다/, 묻히다 /무치다/ 음절말 중화: romanize 메소드에서 반영 String class 내의 함수로 phon을 만들고, 여러 음운규칙에 해당하는 함수를 phon이 호출하도록 함. 이들 함수는 클래스 내부에서만 사용. romanize 메소드에서 phon 함수 호출

8 def resyllabification(coda) #재음절화
coda2resyl = [ #재음절화가 일어날 때, 앞 음 절 종성이 무엇인가에 따라 앞 음절 종성 및 뒤 음절 초성이 무엇으로 바뀔지를 정해 놓은 Array [0,11], #0채움: 채움, ㅇ [0,0], #1ㄱ: 채움, ㄱ [0,1], #2ㄲ: 채움, ㄲ [1,9], #3ㄳ: ㄱ, ㅅ [0,2], #4ㄴ: 채움, ㄴ [4,12], #5ㄵ: ㄴ, ㅈ [0,2], #6ㄶ: 채움, ㄴ 않아->아나 #실제 발음이 '안하'가 아님) [0,3], #7ㄷ: 채움, ㄷ [0,5], #8ㄹ: 채움, ㄹ [8,0], #9ㄺ: ㄹ, ㄱ [8,6], #10ㄻ: ㄹ, ㅁ [8,7], #11ㄼ, ㄹ, ㅂ [8,9], #12ㄽ: ㄹ, ㅅ [8,16], #13ㄾ: ㄹ, ㅌ [8,17], #14ㄿ: ㄹ, ㅍ [0,5], #15ㅀ: 채움, ㄹ 앓아→아라 #실제 발음이 '알하'가 아님 [0,6], #16ㅁ: 채움, ㅁ [0,7], #17ㅂ: 채움, ㅂ [17,9], #18ㅄ: ㅂ, ㅅ [0,9], #19ㅅ: 채움, ㅅ [0,10], #20ㅆ: 채움, ㅆ [21,11], #21ㅇ: ㅇ, ㅇ [0,12], #22ㅈ: 채움, ㅈ [0,14], #23ㅊ: 채움, ㅊ [0,15], #24ㅋ: 채움, ㅋ [0,16], #25ㅌ: 채움, ㅌ [0,17], #26ㅍ: 채움, ㅍ [0,11], #27ㅎ: 채움, ㅇ 좋아→조아 #실제 발음이 '조하'가 아님 ] [coda2resyl[coda][0], coda2resyl[coda][1]] # 앞음절 종성, 뒤음절 초성 end

9 비음화 메소드 def nasalization(coda) #앞음절 종성과 뒤음절 초성 ㄴ,ㅁ이 만났을 때 일어나는 비음화를 다룸
#앞음절 종성의 변화만 다룸. case coda #앞음절 종성이 when 1 ; 21 #ㄱ이면 ㅇ으로 바꿈. 예: 독립→독닙→동닙 when 7,27 ; 4 #ㄷ,ㅎ이면 ㄴ으로 바꿈. #예: 묻니→문니, 좋니→졷니→존니 when 17 ; 16 #ㅂ이면 ㅁ으로 바꿈. 예: 법라→법나→범나 else ; coda #기타의 경우 coda를 그대로 둠 end

10 ㅎ 축약: 용언 어간말 자음이 ㅎ인 경우 def aspiration_verb(onset)
#앞음절 종성 ㅎ과 뒤음절 초성의 축약을 다룸 #뒤음절 초성의 변화만 다룸. case onset #뒤음절 초성이 when 0 ; 15 #ㄱ이면 ㅋ으로 바꿈 #예: 않고→않코, 앓고→알코, 좋고→좋코 when 3 ; 16 #ㄷ이면 ㅌ으로 바꿈. 예: 좋더라→좋터라 when 7 ; 17 #ㅂ이면 ㅍ으로 바꿈. when 12 ; 14 #ㅈ이면 ㅊ으로 바꿈. 예: 좋지→조치 else ; onset #기타의 경우 onset을 그대로 둠 end

11 ㅎ 축약: 접미사 '-히-'의 경우 def aspiration_hi(coda, onset) #앞음절 종성, 뒤음절 초성 둘 다 고려해야 함 #앞음절 종성과 뒤음절 초성 ㅎ이 만났을 때의 축약을 다룸 #뒤음절 초성의 변화만 다룸. case coda when 1 ; 15 #앞음절 종성이 ㄱ이면 뒤음절 초성을 ㅋ으로 바꿈 #예: 먹히고→머키고 when 7,22 ; 14 #앞음절 종성이 ㄷ,ㅈ이면 뒤음절 초성을 ㅊ으로 바꿈 #예: 묻혀→무텨→무쳐(구개음화), 젖힐→저칠 when 17 ; 17 #앞음절 종성이 ㅂ이면 뒤음절 초성을 ㅍ으로 바꿈 #예: 잡혀→자펴 else ; onset #기타의 경우 onset을 그대로 둠 end

12 def phon(syls) #Syllable들의 Array를 input으로 받아서, 음운규칙이 적용된 결과를 Syllable들의 Array로 반환
syls.each_cons(2) do |ap,dui| #각각의 인접한 두 음절에 대해. ap==앞음절, dui==뒤음절 next if ap.class() != Syllable or dui.class() != Syllable #둘 중 하나라도 한글음절이 아니면 그냥 통과 case dui.onset #뒤음절 초성이 when 11 #ㅇ이면 ap.coda, dui.onset = resyllabification(ap.coda) #재음절화(연음법칙) when 5 #ㄹ이면 초성 ㄹ 관련 음운규칙을 적용 if ap.coda == 4 #앞음절 종성이 ㄴ이면 ap.coda = 8 #ㄹ로 바꿈(역행 유음화) 예: 신라->실라 elsif ap.coda != 0 and ap.coda != 8 #앞음절 종성이 채움, ㄹ이 아니면 dui.onset = 2 #뒤음절 초성을 ㄴ으로 바꿈(초성 ㄹ의 분포 제약) 예: 종로->종노, 독립->독닙 ap.coda = nasalization(ap.coda) end dui.onset = 19 if ap.coda == 8 #종성 ㄹ 뒤의 초성 ㄹ은 'l'로 바꿈. when 2 #ㄴ이면 if ap.coda == 8 #앞음절 종성이 ㄹ이면 순행 유음화 적용 dui.onset = 19 #뒤음절 초성을 ㄹ[l]로 바꿈. 예: 별내->별래 else ap.coda = nasalization(ap.coda) #비음화 when 6 #ㅁ이면 비음화 적용

13 when 18 #ㅎ이면 if ((dui.nucleus==6 and (dui.coda==0 or dui.coda==20) ) or (dui.nucleus==20 and [0,4,8,16].include? dui.coda)) and [1,7,17,22].include? ap.coda #((중성 ㅕ and (종성 무,ㅆ) ) or (중성 ㅣ and (종성 무,ㄴ,ㄹ,ㅁ) )) and 앞음절 종성이 ㄱ,ㄷ,ㅂ,ㅈ #즉, 종성 ㄱ,ㄷ,ㅂ,ㅈ 뒤에 '혀,혔,히,힌,힐,힘'이 오는 경우 dui.onset = aspiration_hi(ap.coda, dui.onset) ap.coda = 0 #앞음절 종성을 없앰. 먹힌->먹킨->머킨 end #평장애음과 ㅎ의 축약: 피사동 접사 '-히-'의 경우에만 반영함 #기타 경우는 반영 안 함. 예: 각하 gakha, 법학 beophak else #뒤음절의 초성이 ㅇ,ㄹ,ㄴ,ㅁ,ㅎ이 아닌 경우. 여기서는 앞음절 종성 ㅎ과 뒤음절 초성의 축약만 다룸. case ap.coda #앞음절 종성이 when 6, 15 #ㄶ, ㅀ이면(예: 않,앓) ㅎ과 평장애음의 축약 dui.onset = aspiration_verb(dui.onset) #앞음절 종성은 그대로 놔둬도 됨. ㄶ은 n으로, ㅀ은 l로 변환될 것이기 때문 when 27 #ㅎ이면(예: 좋) ㅎ과 평장애음의 축약 ap.coda = 0 #앞음절 종성을 없앰. 좋고->좋코->조코 end #case dui.onset 의 끝 end #syls.each_cons(2) do |ap,dui|의 끝 syls #음운규칙 적용 결과를 Syllable들의 Array로 반환 end #phon 함수의 끝

14 romanize 메소드 수정: 음운 규칙 반영
romanize 메소드의 마지막 부분에서 phon 함수 호출 추가 def romanize …… phon(self.to_syls).map{ |syl| syl.class()==Syllable ? onset2alpha[syl.onset] + nucleus2alpha[syl.nucleus] + coda2alpha[syl.coda] : syl }.join("") end

15 자습 문제: 예일식 로마자 표기법 한국 정부에서 고시한 로마자 표기법과 별도로 한국어/한글의 로마자 표기법에는
매퀸-라이샤워式 표기법과 예일(Yale)式 표기법이 있음. 언어학계에서는 예일식 표기법이 주로 쓰임. 한글 표기를 예일식 로마자 표기법으로 변환하는 ruby 스크립 트를 작성해 보시오.

16 한자의 중국음과 한국음 비교 통계 입력: 약 4000자의 한자에 대해 한국음과 중국음을 대비한 자료
음절별, 초성별, 중성별, 초·중성별, 중·종설별 출력: 한국음을 기준으로 이에 대응하는 중국음의 빈도, 예시 글자들

17 dic = Hash.new #결과를 저장할 Hash를 만듦. 한국음=>(중국음=>한자)
File.open(ARGV[0],"r:UTF-8").each do |line| #입력 파일의 각 라인에 대해 comb, kor, chi = line.chomp.split("\t") #탭으로 분리 → 한자,한국음,중국음 dic[kor] ||= Hash.new #dic[kor]가 nil이면 빈 Hash를 만듦 dic[kor][chi] ||= Array.new #dic[kor][chi]가 nil이면 빈 Array를 만듦 dic[kor][chi] << comb #dic[kor[chi]에 한자 추가 end File.open(ARGV[1], "w:UTF-8") do |of| #출력 파일을 엶 dic.sort.each do |k, c_combs| #dic을 소트(한국음 가나다순). k=한국음 of << k << "\t" #한국음 출력. c_combs == Hash (중국음=>한자목록) c_combs.sort{ |x,y| y[1].length<=>x[1].length }.each do |c, combs| #한자목록의 길이(한자 수)로 소트. c=중국음, combs=한자목록 of << c << "\t" << combs.length << "\t" << combs.join("/") << "\n" end # 중국음, 탭, 한자 수, 탭, 한자/한자/한자/…, 줄바꿈


Download ppt "Ruby 프로그래밍 한글 로마자화 한국어 정보의 전산 처리 2017. 5. 17.."

Similar presentations


Ads by Google