gimchi 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,28 +2,28 @@ $KCODE = 'U'
2
2
 
3
3
  module Gimchi
4
4
  class Korean
5
- # Checks if the given character is a korean character.
6
- # @param [String] ch A string of size 1
7
- def korean_char? ch
8
- raise ArgumentError.new('Lengthy input') if str_length(ch) > 1
5
+ # Checks if the given character is a korean character.
6
+ # @param [String] ch A string of size 1
7
+ def korean_char? ch
8
+ raise ArgumentError.new('Lengthy input') if str_length(ch) > 1
9
9
 
10
- complete_korean_char?(ch) ||
11
- (chosungs + jungsungs + jongsungs).include?(ch)
12
- end
10
+ complete_korean_char?(ch) ||
11
+ (chosungs + jungsungs + jongsungs).include?(ch)
12
+ end
13
13
 
14
- # Checks if the given character is a "complete" korean character.
15
- # "Complete" Korean character must have chosung and jungsung, with optional jongsung.
16
- # @param [String] ch A string of size 1
17
- def complete_korean_char? ch
18
- raise ArgumentError.new('Lengthy input') if str_length(ch) > 1
14
+ # Checks if the given character is a "complete" korean character.
15
+ # "Complete" Korean character must have chosung and jungsung, with optional jongsung.
16
+ # @param [String] ch A string of size 1
17
+ def complete_korean_char? ch
18
+ raise ArgumentError.new('Lengthy input') if str_length(ch) > 1
19
19
 
20
- # Range of Korean chracters in Unicode 2.0: AC00(가) ~ D7A3(힣)
21
- ch.unpack('U').all? { | c | c >= 0xAC00 && c <= 0xD7A3 }
22
- end
20
+ # Range of Korean chracters in Unicode 2.0: AC00(가) ~ D7A3(힣)
21
+ ch.unpack('U').all? { | c | c >= 0xAC00 && c <= 0xD7A3 }
22
+ end
23
23
 
24
24
  private
25
- def str_length str
26
- str.scan(/./mu).length
27
- end
25
+ def str_length str
26
+ str.scan(/./mu).length
27
+ end
28
28
  end#Korean
29
29
  end#Gimchi
@@ -2,493 +2,493 @@
2
2
 
3
3
  module Gimchi
4
4
  class Korean
5
- # Private class.
6
- # Partial implementation of Korean pronouncement pronunciation rules specified in
7
- # http://http://www.korean.go.kr/
8
- class Pronouncer
9
- private
10
- def initialize korean
11
- @korean = korean
12
- @pconfig = korean.config['pronouncer']
13
- end
14
-
15
- def pronounce! str, options = {}
16
- @sequence = @pconfig['transformation']['sequence for ' +
17
- (options[:pronounce_each_char] ? '1' : '2')] - options[:except]
18
-
19
- # Dissecting
20
- @chars = @korean.dissect str
21
- @orig_chars = @chars.dup
22
-
23
- # Padding
24
- @chars.each { |c| pad c }
25
-
26
- # Two-phase processing
27
- # - For `slur'
28
- applied = []
29
- 2.times do | phase |
30
- @chars = @chars.reject { |c| c =~ /\s/ } if phase == 1 # slur-phase
31
-
32
- # Deep-fried...no copied backup
33
- @initial_chars = @chars.map { |c| c.dup }
34
-
35
- # Transform one by one
36
- applied += (0...@chars.length).inject([]) { | arr, i | arr + transform(i); }
37
-
38
- # Post-processing (actually just for :pronounce_each_char option)
39
- @chars.select { |c| c.is_a?(Korean::Char) && c.jongsung }.each do | c |
40
- c.jongsung = @pconfig['jongsung sound'][c.jongsung]
41
- end
42
-
43
- break unless options[:slur]
44
- end
45
-
46
- return @orig_chars.join, applied
47
- end
48
-
49
- private
50
- def transform idx
51
- @cursor = idx
52
- kc = @chars[@cursor]
53
-
54
- # Not korean
55
- return [] unless kc.is_a? Korean::Char
56
-
57
- # Setting up variables for fast lookup
58
- @kc = kc
59
- @next_kc = (nkc = @chars[@cursor + 1]).is_a?(Korean::Char) ? nkc : nil
60
- @kc_org = @initial_chars[@cursor]
61
- @next_kc_org = (nkco = @initial_chars[@cursor + 1]).is_a?(Korean::Char) ? nkco : nil
62
-
63
- # Cannot properly pronounce
64
- return [] if @kc.chosung.nil? && @kc.jungsung.nil? && @kc.jongsung.nil?
65
-
66
- applied = []
67
- not_todo = []
68
- blocking_rule = @pconfig['transformation']['blocking rule']
69
- @sequence.each do | rule |
70
- next if not_todo.include?(rule)
71
-
72
- if self.send(rule)
73
- applied << rule
74
- not_todo += blocking_rule[rule] if blocking_rule.has_key?(rule)
75
- end
76
- end
77
- applied
78
- end
79
-
80
- def pad c
81
- return unless c.is_a? Korean::Char
82
-
83
- c.chosung = 'ㅇ' if c.chosung.nil?
84
- c.jungsung = 'ㅡ' if c.jungsung.nil?
85
- end
86
-
87
- # shortcut
88
- def fortis_map
89
- @korean.config['structure']['fortis map']
90
- end
91
-
92
- # shortcut
93
- def double_consonant_map
94
- @korean.config['structure']['double consonant map']
95
- end
96
-
97
- # 제5항: ‘ㅑ ㅒ ㅕ ㅖ ㅘ ㅙ ㅛ ㅝ ㅞ ㅠ ㅢ’는 이중 모음으로 발음한다.
98
- # 다만 1. 용언의 활용형에 나타나는 ‘져, 쪄, 쳐’는 [저, 쩌, 처]로 발음한다.
99
- # 다만 3. 자음을 첫소리로 가지고 있는 음절의 ‘ㅢ’는 [ㅣ]로 발음한다.
100
- def rule_5_1
101
- if %w[져 쪄 쳐].include? @kc.to_s
102
- @kc.jungsung = 'ㅓ'
103
-
104
- true
105
- end
106
- end
107
-
108
- def rule_5_3
109
- if @kc.jungsung == 'ㅢ' && @kc_org.chosung.consonant?
110
- @kc.jungsung = 'ㅣ'
111
-
112
- true
113
- end
114
- end
115
-
116
- # 제9항: 받침 ‘ㄲ, ㅋ’, ‘ㅅ, ㅆ, ㅈ, ㅊ, ㅌ’, ‘ㅍ’은 어말 또는 자음 앞에서
117
- # 각각 대표음 [ㄱ, ㄷ, ㅂ]으로 발음한다.
118
- def rule_9
119
- map = {
120
- %w[ㄲ ㅋ] => 'ㄱ',
121
- %w[ㅅ ㅆ ㅈ ㅊ ㅌ] => 'ㄷ',
122
- %w[ㅍ] => 'ㅂ'
123
- }
124
- if map.keys.flatten.include?(@kc.jongsung) && (@next_kc.nil? || @next_kc.chosung.consonant?)
125
- @kc.jongsung = map[ map.keys.find { |e| e.include? @kc.jongsung } ]
126
-
127
- true
128
- end
129
- end
130
-
131
- # 제10항: 겹받침 ‘ㄳ’, ‘ㄵ’, ‘ㄼ, ㄽ, ㄾ’, ‘ㅄ’은 어말 또는 자음 앞에서
132
- # 각각 [ㄱ, ㄴ, ㄹ, ㅂ]으로 발음한다.
133
- def rule_10
134
- map = {
135
- %w[ㄳ] => 'ㄱ',
136
- %w[ㄵ] => 'ㄴ',
137
- %w[ㄼ ㄽ ㄾ] => 'ㄹ',
138
- %w[ㅄ] => 'ㅂ'
139
- }
140
- if map.keys.flatten.include?(@kc.jongsung) && (@next_kc.nil? || @next_kc.chosung.consonant?)
141
- # Exceptions
142
- if @next_kc && (
143
- (@kc.to_s == '밟' && @next_kc.chosung.consonant?) ||
144
- (@kc.to_s == '넓' && @next_kc && %w[적 죽 둥].include?(@next_kc_org.to_s))) # PATCH
145
- @kc.jongsung = 'ㅂ'
146
- else
147
- @kc.jongsung = map[ map.keys.find { |e| e.include? @kc.jongsung } ]
148
- end
149
-
150
- true
151
- end
152
- end
153
-
154
- # 제11항: 겹받침 ‘ㄺ, ㄻ, ㄿ’은 어말 또는 자음 앞에서 각각 [ㄱ, ㅁ, ㅂ]으로 발음한다.
155
- def rule_11
156
- map = {
157
- 'ㄺ' => 'ㄱ',
158
- 'ㄻ' => 'ㅁ',
159
- 'ㄿ' => 'ㅂ'
160
- }
161
- if map.keys.include?(@kc.jongsung) && (@next_kc.nil? || @next_kc.chosung.consonant?)
162
- # 다만, 용언의 어간 말음 ‘ㄺ’은 ‘ㄱ’ 앞에서 [ㄹ]로 발음한다.
163
- # - 용언 여부 판단은?: 중성으로 판단 (PATCH)
164
- if @next_kc && @kc.jongsung == 'ㄺ' &&
165
- @next_kc_org.chosung == 'ㄱ' &&
166
- %w[맑 얽 섥 밝 늙 묽 넓].include?(@kc.to_s) # PATCH
167
- @kc.jongsung = 'ㄹ'
168
- else
169
- @kc.jongsung = map[@kc.jongsung]
170
- end
171
-
172
- true
173
- end
174
- end
175
-
176
- # 제12항: 받침 ‘ㅎ’의 발음은 다음과 같다.
177
- # 1. ‘ㅎ(ㄶ, ㅀ)’ 뒤에 ‘ㄱ, ㄷ, ㅈ’이 결합되는 경우에는, 뒤 음절 첫소리와
178
- # 합쳐서 [ㅋ, ㅌ, ㅊ]으로 발음한다.
179
- # [붙임 1]받침 ‘ㄱ(ㄺ), ㄷ, ㅂ(ㄼ), ㅈ(ㄵ)’이 뒤 음절 첫소리 ‘ㅎ’과
180
- # 결합되는 경우에도, 역시 두 음을 합쳐서 [ㅋ, ㅌ, ㅍ, ㅊ]으로 발음한다.
181
- # [붙임 2]규정에 따라 ‘ㄷ’으로 발음되는 ‘ㅅ, ㅈ, ㅊ, ㅌ’의 경우에도 이에 준한다.
182
- #
183
- # 2. ‘ㅎ(ㄶ, ㅀ)’ 뒤에 ‘ㅅ’이 결합되는 경우에는, ‘ㅅ’을 [ㅆ]으로 발음한다.
184
- #
185
- # 3. ‘ㅎ’ 뒤에 ‘ㄴ’이 결합되는 경우에는, [ㄴ]으로 발음한다.
186
- # [붙임]‘ㄶ, ㅀ’ 뒤에 ‘ㄴ’이 결합되는 경우에는, ‘ㅎ’을 발음하지 않는다.
187
- #
188
- # 4. ‘ㅎ(ㄶ, ㅀ)’ 뒤에 모음으로 시작된 어미나 접미사가 결합되는 경우에는, ‘ㅎ’을 발음하지 않는다.
189
- def rule_12
190
- return if @next_kc.nil?
191
-
192
- map_12_1 = {
193
- 'ㄱ' => 'ㅋ',
194
- 'ㄷ' => 'ㅌ',
195
- 'ㅈ' => 'ㅊ' }
196
- if %w[ㅎ ㄶ ㅀ].include?(@kc.jongsung)
197
- # 12-1
198
- if map_12_1.keys.include?(@next_kc.chosung)
199
- @next_kc.chosung = map_12_1[@next_kc.chosung]
200
- @kc.jongsung = (dc = double_consonant_map[@kc.jongsung]) && dc.first
201
-
202
- # 12-2
203
- elsif @next_kc.chosung == 'ㅅ'
204
- @kc.jongsung = (dc = double_consonant_map[@kc.jongsung]) && dc.first
205
- @next_kc.chosung = 'ㅆ'
206
-
207
- # 12-3
208
- elsif @next_kc.chosung == 'ㄴ'
209
- if dc = double_consonant_map[@kc.jongsung]
210
- @kc.jongsung = dc.first
211
- else
212
- @kc.jongsung = 'ㄴ'
213
- end
214
-
215
- # 12-4
216
- elsif @next_kc.chosung == 'ㅇ'
217
- @kc.jongsung = (dc = double_consonant_map[@kc.jongsung]) && dc.first
218
- end
219
-
220
- true
221
- end
222
-
223
- # 12-1 붙임
224
- if @next_kc.chosung == 'ㅎ'
225
- map_jongsung = {
226
- # 붙임 1
227
- 'ㄱ' => [nil, 'ㅋ'],
228
- 'ㄺ' => ['ㄹ', 'ㅋ'],
229
- 'ㄷ' => [nil, 'ㅌ'],
230
- 'ㅂ' => [nil, 'ㅍ'],
231
- 'ㄼ' => ['ㄹ', 'ㅍ'],
232
- 'ㅈ' => [nil, 'ㅊ'],
233
- 'ㄵ' => ['ㄴ', 'ㅊ'],
234
-
235
- # 붙임 2
236
- 'ㅅ' => [nil, 'ㅌ'],
237
- #'ㅈ' => [nil, 'ㅌ'], # FIXME: 붙임2의 모순
238
- 'ㅊ' => [nil, 'ㅌ'],
239
- 'ㅌ' => [nil, 'ㅌ'],
240
- }
241
- if trans1 = map_jongsung[@kc.jongsung]
242
- @kc.jongsung = trans1.first
243
- @next_kc.chosung = trans1.last
244
-
245
- true
246
- end
247
- end
248
- end
249
-
250
- # 제13항: 홑받침이나 쌍받침이 모음으로 시작된 조사나 어미, 접미사와
251
- # 결합되는 경우에는, 제 음가대로 뒤 음절 첫소리로 옮겨 발음한다.
252
- def rule_13
253
- return if @kc.jongsung.nil? || @kc.jongsung == 'ㅇ' || @next_kc.nil? || @next_kc.chosung != 'ㅇ'
254
- @next_kc.chosung = @kc.jongsung
255
- @kc.jongsung = nil
256
-
257
- true
258
- end
259
-
260
- # 제14항: 겹받침이 모음으로 시작된 조사나 어미, 접미사와 결합되는 경우에는,
261
- # 뒤엣것만을 뒤 음절 첫소리로 옮겨 발음한다.(이 경우, ‘ㅅ’은 된소리로 발음함.)
262
- #
263
- def rule_14
264
- return if @kc.jongsung.nil? || @kc.jongsung == 'ㅇ' || @next_kc.nil? || @next_kc.chosung != 'ㅇ'
265
- if consonants = double_consonant_map[@kc.jongsung]
266
- consonants[1] = 'ㅆ' if consonants[1] == 'ㅅ'
267
- @kc.jongsung, @next_kc.chosung = consonants
268
-
269
- true
270
- end
271
- end
272
-
273
- # 제15항: 받침 뒤에 모음 ‘ㅏ, ㅓ, ㅗ, ㅜ, ㅟ’들로 시작되는 __실질 형태소__가 연결되는
274
- # 경우에는, 대표음으로 바꾸어서 뒤 음절 첫소리로 옮겨 발음한다.
275
- def rule_15
276
- return if @kc.jongsung.nil? || @kc.jongsung == 'ㅇ' || @next_kc.nil? || @next_kc.chosung != 'ㅇ'
277
-
278
- if false && %w[ㅏ ㅓ ㅗ ㅜ ㅟ].include?(@next_kc.jungsung) &&
279
- %[ㅆ ㄲ ㅈ ㅊ ㄵ ㄻ ㄾ ㄿ ㄺ].include?(@kc.jongsung) == false # PATCH
280
- @next_kc.chosung = @pconfig['jongsung sound'][ @kc.jongsung ]
281
- @kc.jongsung = nil
282
-
283
- true
284
- end
285
- end
286
-
287
- # 제16항: 한글 자모의 이름은 그 받침소리를 연음하되, ‘ㄷ, ㅈ, ㅊ, ㅋ, ㅌ,
288
- # ㅍ, ㅎ’의 경우에는 특별히 다음과 같이 발음한다.
289
- def rule_16
290
- return if @next_kc.nil?
291
-
292
- map = {'디귿' => '디긋',
293
- '지읒' => '지읏',
294
- '치읓' => '치읏',
295
- '키읔' => '키윽',
296
- '티읕' => '티읏',
297
- '피읖' => '피읍',
298
- '히읗' => '히읏'}
299
-
300
- word = @kc.to_s + @next_kc.to_s
301
- if map.keys.include? word
302
- new_char = @korean.dissect(map[word].scan(/./mu)[1])[0]
303
- @next_kc.chosung = new_char.chosung
304
- @next_kc.jongsung = new_char.jongsung
305
-
306
- true
307
- end
308
- end
309
-
310
- # 제17항: 받침 ‘ㄷ, ㅌ(ㄾ)’이 조사나 접미사의 모음 ‘ㅣ’와 결합되는 경우에는,
311
- # [ㅈ, ㅊ]으로 바꾸어서 뒤 음절 첫소리로 옮겨 발음한다.
312
- #
313
- # [붙임] ‘ㄷ’ 뒤에 접미사 ‘히’가 결합되어 ‘티’를 이루는 것은 [치]로 발음한다.
314
- def rule_17
315
- return if @next_kc.nil? || %w[ㄷ ㅌ ㄾ].include?(@kc.jongsung) == false
316
-
317
- if @next_kc.to_s == '이'
318
- @next_kc.chosung = @kc.jongsung == 'ㄷ' ? 'ㅈ' : 'ㅊ'
319
- @kc.jongsung = (dc = double_consonant_map[@kc.jongsung]) && dc.first
320
-
321
- true
322
- elsif @next_kc.to_s == '히'
323
- @next_kc.chosung = 'ㅊ'
324
- @kc.jongsung = (dc = double_consonant_map[@kc.jongsung]) && dc.first
325
-
326
- true
327
- end
328
- end
329
-
330
- # 제18항: 받침 ‘ㄱ(ㄲ, ㅋ, ㄳ, ㄺ), ㄷ(ㅅ, ㅆ, ㅈ, ㅊ, ㅌ, ㅎ), ㅂ(ㅍ, ㄼ,
331
- # ㄿ, ㅄ)’은 ‘ㄴ, ㅁ’ 앞에서 [ㅇ, ㄴ, ㅁ]으로 발음한다.
332
- def rule_18
333
- map = {
334
- %w[ㄱ ㄲ ㅋ ㄳ ㄺ] => 'ㅇ',
335
- %w[ㄷ ㅅ ㅆ ㅈ ㅊ ㅌ ㅎ] => 'ㄴ',
336
- %w[ㅂ ㅍ ㄼ ㄿ ㅄ] => 'ㅁ'
337
- }
338
- if @next_kc && map.keys.flatten.include?(@kc.jongsung) && %w[ㄴ ㅁ].include?(@next_kc.chosung)
339
- @kc.jongsung = map[ map.keys.find { |e| e.include? @kc.jongsung } ]
340
-
341
- true
342
- end
343
- end
344
-
345
- # 제19항: 받침 ‘ㅁ, ㅇ’ 뒤에 연결되는 ‘ㄹ’은 [ㄴ]으로 발음한다.
346
- # [붙임]받침 ‘ㄱ, ㅂ’ 뒤에 연결되는 ‘ㄹ’도 [ㄴ]으로 발음한다.
347
- def rule_19
348
- if @next_kc && @next_kc.chosung == 'ㄹ' && %w[ㅁ ㅇ ㄱ ㅂ].include?(@kc.jongsung)
349
- @next_kc.chosung = 'ㄴ'
350
-
351
- case @kc.jongsung
352
- when 'ㄱ' then @kc.jongsung = 'ㅇ'
353
- when 'ㅂ' then @kc.jongsung = 'ㅁ'
354
- end
355
-
356
- true
357
- end
358
- end
359
-
360
- # 제20항: ‘ㄴ’은 ‘ㄹ’의 앞이나 뒤에서 [ㄹ]로 발음한다.
361
- def rule_20
362
- return if @next_kc.nil?
363
-
364
- to = if %w[견란 진란 산량 단력 권력 원령 견례
365
- 문로 단로 원론 원료 근류].include?(@kc_org.to_s + @next_kc_org.to_s)
366
- 'ㄴ'
367
- else
368
- 'ㄹ'
369
- end
370
-
371
- if @kc.jongsung == 'ㄹ' && @next_kc.chosung == 'ㄴ'
372
- @kc.jongsung = @next_kc.chosung = to
373
-
374
- true
375
- elsif @kc.jongsung == 'ㄴ' && @next_kc.chosung == 'ㄹ'
376
- @kc.jongsung = @next_kc.chosung = to
377
-
378
- true
379
- end
380
- end
381
-
382
- # 제23항: 받침 ‘ㄱ(ㄲ, ㅋ, ㄳ, ㄺ), ㄷ(ㅅ, ㅆ, ㅈ, ㅊ, ㅌ), ㅂ(ㅍ, ㄼ, ㄿ,ㅄ)’
383
- # 뒤에 연결되는 ‘ㄱ, ㄷ, ㅂ, ㅅ, ㅈ’은 된소리로 발음한다.
384
- def rule_23
385
- return if @next_kc.nil?
386
- if fortis_map.keys.include?(@next_kc.chosung) &&
387
- %w[ㄱ ㄲ ㅋ ㄳ ㄺ ㄷ ㅅ ㅆ ㅈ ㅊ ㅌ ㅂ ㅍ ㄼ ㄿ ㅄ].include?(@kc.jongsung)
388
- @next_kc.chosung = fortis_map[@next_kc.chosung]
389
-
390
- true
391
- end
392
- end
393
-
394
- # 제24항: 어간 받침 ‘ㄴ(ㄵ), ㅁ(ㄻ)’ 뒤에 결합되는 어미의 첫소리 ‘ㄱ, ㄷ, ㅅ, ㅈ’은 된소리로 발음한다.
395
- # 다만, 피동, 사동의 접미사 ‘-기-’는 된소리로 발음하지 않는다.
396
- # 용언 어간에만 적용.
397
- def rule_24
398
- return if @next_kc.nil? ||
399
- @next_kc.to_s == '기' # FIXME 피동/사동 여부 판단 불가. e.g. 줄넘기
400
-
401
- # FIXME 용언 여부를 판단. 정확한 판단 불가.
402
- return unless case @kc.jongsung
403
- when 'ㄵ'
404
- %w[앉 얹].include? @kc.to_s
405
- when 'ㄻ'
406
- %w[젊 닮].include? @kc.to_s
407
- else
408
- false # XXX 일반적인 경우 사전 없이 판단 불가
409
- end
410
-
411
- if %w[ㄱ ㄷ ㅅ ㅈ].include?(@next_kc.chosung) &&
412
- %w[ㄴ ㄵ ㅁ ㄻ ㄼ ㄾ].include?(@kc.jongsung)
413
- @next_kc.chosung = fortis_map[@next_kc.chosung]
414
-
415
- true
416
- end
417
- end
418
-
419
- # 제25항: 어간 받침 ‘ㄼ, ㄾ’ 뒤에 결합되는 어미의 첫소리 ‘ㄱ, ㄷ, ㅅ, ㅈ’은
420
- # 된소리로 발음한다.
421
- def rule_25
422
- return if @next_kc.nil?
423
-
424
- if %w[ㄱ ㄷ ㅅ ㅈ].include?(@next_kc.chosung) &&
425
- %w[ㄼ ㄾ].include?(@kc.jongsung)
426
- @next_kc.chosung = fortis_map[@next_kc.chosung]
427
-
428
- true
429
- end
430
- end
431
-
432
- # 제26항: 한자어에서, ‘ㄹ’ 받침 뒤에 연결되는 ‘ㄷ, ㅅ, ㅈ’은 된소리로 발음한다.
433
- def rule_26
434
- # TODO
435
- end
436
-
437
- # 제27항: __관형사형__ ‘-(으)ㄹ’ 뒤에 연결되는 ‘ㄱ, ㄷ, ㅂ, ㅅ, ㅈ’은 된소리로 발음한다.
438
- # - ‘-(으)ㄹ’로 시작되는 어미의 경우에도 이에 준한다.
439
- def rule_27
440
- # FIXME: NOT PROPERLY IMPLEMENTED
441
- return if @next_kc.nil?
442
-
443
- # 비교적 확률이 높은 경우들에 대해서만 처리. "일" 은 제외.
444
- if %w[할 갈 날 볼 을 앨 말 힐].include?(@kc.to_s) && # @kc.jongsung == 'ㄹ' &&
445
- %w[ㄱ ㄷ ㅂ ㅅ ㅈ].include?(@next_kc.chosung)
446
- @next_kc.chosung = fortis_map[@next_kc.chosung]
447
- true
448
- end
449
- end
450
-
451
- # 제26항: 한자어에서, ‘ㄹ’ 받침 뒤에 연결되는 ‘ㄷ, ㅅ, ㅈ’은 된소리로 발음한다.
452
- # 제28항: 표기상으로는 사이시옷이 없더라도, 관형격 기능을 지니는 사이시옷이
453
- # 있어야 할(휴지가 성립되는) 합성어의 경우에는, 뒤 단어의 첫소리 ‘ㄱ, ㄷ,
454
- # ㅂ, ㅅ, ㅈ’을 된소리로 발음한다.
455
- def rule_26_28
456
- # TODO
457
- end
458
-
459
- # 제29항: 합성어 및 파생어에서, 앞 단어나 접두사의 끝이 자음이고 뒤 단어나
460
- # 접미사의 첫음절이 ‘이, 야, 여, 요, 유’인 경우에는, ‘ㄴ’ 음을 첨가하여
461
- # [니, 냐, 녀, 뇨, 뉴]로 발음한다.
462
- def rule_29
463
- # TODO
464
- end
465
-
466
- # 제30항: 사이시옷이 붙은 단어는 다음과 같이 발음한다.
467
- # 1. ‘ㄱ, ㄷ, ㅂ, ㅅ, ㅈ’으로 시작하는 단어 앞에 사이시옷이 올 때는 이들
468
- # 자음만을 된소리로 발음하는 것을 원칙으로 하되, 사이시옷을 [ㄷ]으로
469
- # 발음하는 것도 허용한다.
470
- # 2. 사이시옷 뒤에 ‘ㄴ, ㅁ’이 결합되는 경우에는 [ㄴ]으로 발음한다.
471
- # 3. 사이시옷 뒤에 ‘이’ 음이 결합되는 경우에는 [ㄴㄴ]으로 발음한다.
472
- def rule_30
473
- return if @next_kc.nil? || @kc.jongsung != 'ㅅ'
474
-
475
- if %w[ㄱ ㄷ ㅂ ㅅ ㅈ].include? @next_kc.chosung
476
- @kc.jongsung = 'ㄷ' # or nil
477
- @next_kc.chosung = fortis_map[@next_kc.chosung]
478
-
479
- true
480
- elsif %w[ㄴ ㅁ].include? @next_kc.chosung
481
- @kc.jongsung = 'ㄴ'
482
-
483
- true
484
- elsif @next_kc.chosung == 'ㅇ' &&
485
- %w[ㅣ ㅒ ㅖ ㅑ ㅕ ㅛ ㅠ].include?(@next_kc.jungsung) &&
486
- @next_kc.jongsung # PATCH
487
- @kc.jongsung = @next_kc.chosung = 'ㄴ'
488
-
489
- true
490
- end
491
- end
492
- end#Pronouncer
5
+ # Private class.
6
+ # Partial implementation of Korean pronouncement pronunciation rules specified in
7
+ # http://http://www.korean.go.kr/
8
+ class Pronouncer
9
+ private
10
+ def initialize korean
11
+ @korean = korean
12
+ @pconfig = korean.config['pronouncer']
13
+ end
14
+
15
+ def pronounce! str, options = {}
16
+ @sequence = @pconfig['transformation']['sequence for ' +
17
+ (options[:pronounce_each_char] ? '1' : '2')] - options[:except]
18
+
19
+ # Dissecting
20
+ @chars = @korean.dissect str
21
+ @orig_chars = @chars.dup
22
+
23
+ # Padding
24
+ @chars.each { |c| pad c }
25
+
26
+ # Two-phase processing
27
+ # - For `slur'
28
+ applied = []
29
+ 2.times do | phase |
30
+ @chars = @chars.reject { |c| c =~ /\s/ } if phase == 1 # slur-phase
31
+
32
+ # Deep-fried...no copied backup
33
+ @initial_chars = @chars.map { |c| c.dup }
34
+
35
+ # Transform one by one
36
+ applied += (0...@chars.length).inject([]) { | arr, i | arr + transform(i); }
37
+
38
+ # Post-processing (actually just for :pronounce_each_char option)
39
+ @chars.select { |c| c.is_a?(Korean::Char) && c.jongsung }.each do | c |
40
+ c.jongsung = @pconfig['jongsung sound'][c.jongsung]
41
+ end
42
+
43
+ break unless options[:slur]
44
+ end
45
+
46
+ return @orig_chars.join, applied
47
+ end
48
+
49
+ private
50
+ def transform idx
51
+ @cursor = idx
52
+ kc = @chars[@cursor]
53
+
54
+ # Not korean
55
+ return [] unless kc.is_a? Korean::Char
56
+
57
+ # Setting up variables for fast lookup
58
+ @kc = kc
59
+ @next_kc = (nkc = @chars[@cursor + 1]).is_a?(Korean::Char) ? nkc : nil
60
+ @kc_org = @initial_chars[@cursor]
61
+ @next_kc_org = (nkco = @initial_chars[@cursor + 1]).is_a?(Korean::Char) ? nkco : nil
62
+
63
+ # Cannot properly pronounce
64
+ return [] if @kc.chosung.nil? && @kc.jungsung.nil? && @kc.jongsung.nil?
65
+
66
+ applied = []
67
+ not_todo = []
68
+ blocking_rule = @pconfig['transformation']['blocking rule']
69
+ @sequence.each do | rule |
70
+ next if not_todo.include?(rule)
71
+
72
+ if self.send(rule)
73
+ applied << rule
74
+ not_todo += blocking_rule[rule] if blocking_rule.has_key?(rule)
75
+ end
76
+ end
77
+ applied
78
+ end
79
+
80
+ def pad c
81
+ return unless c.is_a? Korean::Char
82
+
83
+ c.chosung = 'ㅇ' if c.chosung.nil?
84
+ c.jungsung = 'ㅡ' if c.jungsung.nil?
85
+ end
86
+
87
+ # shortcut
88
+ def fortis_map
89
+ @korean.config['structure']['fortis map']
90
+ end
91
+
92
+ # shortcut
93
+ def double_consonant_map
94
+ @korean.config['structure']['double consonant map']
95
+ end
96
+
97
+ # 제5항: ‘ㅑ ㅒ ㅕ ㅖ ㅘ ㅙ ㅛ ㅝ ㅞ ㅠ ㅢ’는 이중 모음으로 발음한다.
98
+ # 다만 1. 용언의 활용형에 나타나는 ‘져, 쪄, 쳐’는 [저, 쩌, 처]로 발음한다.
99
+ # 다만 3. 자음을 첫소리로 가지고 있는 음절의 ‘ㅢ’는 [ㅣ]로 발음한다.
100
+ def rule_5_1
101
+ if %w[져 쪄 쳐].include? @kc.to_s
102
+ @kc.jungsung = 'ㅓ'
103
+
104
+ true
105
+ end
106
+ end
107
+
108
+ def rule_5_3
109
+ if @kc.jungsung == 'ㅢ' && @kc_org.chosung.consonant?
110
+ @kc.jungsung = 'ㅣ'
111
+
112
+ true
113
+ end
114
+ end
115
+
116
+ # 제9항: 받침 ‘ㄲ, ㅋ’, ‘ㅅ, ㅆ, ㅈ, ㅊ, ㅌ’, ‘ㅍ’은 어말 또는 자음 앞에서
117
+ # 각각 대표음 [ㄱ, ㄷ, ㅂ]으로 발음한다.
118
+ def rule_9
119
+ map = {
120
+ %w[ㄲ ㅋ] => 'ㄱ',
121
+ %w[ㅅ ㅆ ㅈ ㅊ ㅌ] => 'ㄷ',
122
+ %w[ㅍ] => 'ㅂ'
123
+ }
124
+ if map.keys.flatten.include?(@kc.jongsung) && (@next_kc.nil? || @next_kc.chosung.consonant?)
125
+ @kc.jongsung = map[ map.keys.find { |e| e.include? @kc.jongsung } ]
126
+
127
+ true
128
+ end
129
+ end
130
+
131
+ # 제10항: 겹받침 ‘ㄳ’, ‘ㄵ’, ‘ㄼ, ㄽ, ㄾ’, ‘ㅄ’은 어말 또는 자음 앞에서
132
+ # 각각 [ㄱ, ㄴ, ㄹ, ㅂ]으로 발음한다.
133
+ def rule_10
134
+ map = {
135
+ %w[ㄳ] => 'ㄱ',
136
+ %w[ㄵ] => 'ㄴ',
137
+ %w[ㄼ ㄽ ㄾ] => 'ㄹ',
138
+ %w[ㅄ] => 'ㅂ'
139
+ }
140
+ if map.keys.flatten.include?(@kc.jongsung) && (@next_kc.nil? || @next_kc.chosung.consonant?)
141
+ # Exceptions
142
+ if @next_kc && (
143
+ (@kc.to_s == '밟' && @next_kc.chosung.consonant?) ||
144
+ (@kc.to_s == '넓' && @next_kc && %w[적 죽 둥].include?(@next_kc_org.to_s))) # PATCH
145
+ @kc.jongsung = 'ㅂ'
146
+ else
147
+ @kc.jongsung = map[ map.keys.find { |e| e.include? @kc.jongsung } ]
148
+ end
149
+
150
+ true
151
+ end
152
+ end
153
+
154
+ # 제11항: 겹받침 ‘ㄺ, ㄻ, ㄿ’은 어말 또는 자음 앞에서 각각 [ㄱ, ㅁ, ㅂ]으로 발음한다.
155
+ def rule_11
156
+ map = {
157
+ 'ㄺ' => 'ㄱ',
158
+ 'ㄻ' => 'ㅁ',
159
+ 'ㄿ' => 'ㅂ'
160
+ }
161
+ if map.keys.include?(@kc.jongsung) && (@next_kc.nil? || @next_kc.chosung.consonant?)
162
+ # 다만, 용언의 어간 말음 ‘ㄺ’은 ‘ㄱ’ 앞에서 [ㄹ]로 발음한다.
163
+ # - 용언 여부 판단은?: 중성으로 판단 (PATCH)
164
+ if @next_kc && @kc.jongsung == 'ㄺ' &&
165
+ @next_kc_org.chosung == 'ㄱ' &&
166
+ %w[맑 얽 섥 밝 늙 묽 넓].include?(@kc.to_s) # PATCH
167
+ @kc.jongsung = 'ㄹ'
168
+ else
169
+ @kc.jongsung = map[@kc.jongsung]
170
+ end
171
+
172
+ true
173
+ end
174
+ end
175
+
176
+ # 제12항: 받침 ‘ㅎ’의 발음은 다음과 같다.
177
+ # 1. ‘ㅎ(ㄶ, ㅀ)’ 뒤에 ‘ㄱ, ㄷ, ㅈ’이 결합되는 경우에는, 뒤 음절 첫소리와
178
+ # 합쳐서 [ㅋ, ㅌ, ㅊ]으로 발음한다.
179
+ # [붙임 1]받침 ‘ㄱ(ㄺ), ㄷ, ㅂ(ㄼ), ㅈ(ㄵ)’이 뒤 음절 첫소리 ‘ㅎ’과
180
+ # 결합되는 경우에도, 역시 두 음을 합쳐서 [ㅋ, ㅌ, ㅍ, ㅊ]으로 발음한다.
181
+ # [붙임 2]규정에 따라 ‘ㄷ’으로 발음되는 ‘ㅅ, ㅈ, ㅊ, ㅌ’의 경우에도 이에 준한다.
182
+ #
183
+ # 2. ‘ㅎ(ㄶ, ㅀ)’ 뒤에 ‘ㅅ’이 결합되는 경우에는, ‘ㅅ’을 [ㅆ]으로 발음한다.
184
+ #
185
+ # 3. ‘ㅎ’ 뒤에 ‘ㄴ’이 결합되는 경우에는, [ㄴ]으로 발음한다.
186
+ # [붙임]‘ㄶ, ㅀ’ 뒤에 ‘ㄴ’이 결합되는 경우에는, ‘ㅎ’을 발음하지 않는다.
187
+ #
188
+ # 4. ‘ㅎ(ㄶ, ㅀ)’ 뒤에 모음으로 시작된 어미나 접미사가 결합되는 경우에는, ‘ㅎ’을 발음하지 않는다.
189
+ def rule_12
190
+ return if @next_kc.nil?
191
+
192
+ map_12_1 = {
193
+ 'ㄱ' => 'ㅋ',
194
+ 'ㄷ' => 'ㅌ',
195
+ 'ㅈ' => 'ㅊ' }
196
+ if %w[ㅎ ㄶ ㅀ].include?(@kc.jongsung)
197
+ # 12-1
198
+ if map_12_1.keys.include?(@next_kc.chosung)
199
+ @next_kc.chosung = map_12_1[@next_kc.chosung]
200
+ @kc.jongsung = (dc = double_consonant_map[@kc.jongsung]) && dc.first
201
+
202
+ # 12-2
203
+ elsif @next_kc.chosung == 'ㅅ'
204
+ @kc.jongsung = (dc = double_consonant_map[@kc.jongsung]) && dc.first
205
+ @next_kc.chosung = 'ㅆ'
206
+
207
+ # 12-3
208
+ elsif @next_kc.chosung == 'ㄴ'
209
+ if dc = double_consonant_map[@kc.jongsung]
210
+ @kc.jongsung = dc.first
211
+ else
212
+ @kc.jongsung = 'ㄴ'
213
+ end
214
+
215
+ # 12-4
216
+ elsif @next_kc.chosung == 'ㅇ'
217
+ @kc.jongsung = (dc = double_consonant_map[@kc.jongsung]) && dc.first
218
+ end
219
+
220
+ true
221
+ end
222
+
223
+ # 12-1 붙임
224
+ if @next_kc.chosung == 'ㅎ'
225
+ map_jongsung = {
226
+ # 붙임 1
227
+ 'ㄱ' => [nil, 'ㅋ'],
228
+ 'ㄺ' => ['ㄹ', 'ㅋ'],
229
+ 'ㄷ' => [nil, 'ㅌ'],
230
+ 'ㅂ' => [nil, 'ㅍ'],
231
+ 'ㄼ' => ['ㄹ', 'ㅍ'],
232
+ 'ㅈ' => [nil, 'ㅊ'],
233
+ 'ㄵ' => ['ㄴ', 'ㅊ'],
234
+
235
+ # 붙임 2
236
+ 'ㅅ' => [nil, 'ㅌ'],
237
+ #'ㅈ' => [nil, 'ㅌ'], # FIXME: 붙임2의 모순
238
+ 'ㅊ' => [nil, 'ㅌ'],
239
+ 'ㅌ' => [nil, 'ㅌ'],
240
+ }
241
+ if trans1 = map_jongsung[@kc.jongsung]
242
+ @kc.jongsung = trans1.first
243
+ @next_kc.chosung = trans1.last
244
+
245
+ true
246
+ end
247
+ end
248
+ end
249
+
250
+ # 제13항: 홑받침이나 쌍받침이 모음으로 시작된 조사나 어미, 접미사와
251
+ # 결합되는 경우에는, 제 음가대로 뒤 음절 첫소리로 옮겨 발음한다.
252
+ def rule_13
253
+ return if @kc.jongsung.nil? || @kc.jongsung == 'ㅇ' || @next_kc.nil? || @next_kc.chosung != 'ㅇ'
254
+ @next_kc.chosung = @kc.jongsung
255
+ @kc.jongsung = nil
256
+
257
+ true
258
+ end
259
+
260
+ # 제14항: 겹받침이 모음으로 시작된 조사나 어미, 접미사와 결합되는 경우에는,
261
+ # 뒤엣것만을 뒤 음절 첫소리로 옮겨 발음한다.(이 경우, ‘ㅅ’은 된소리로 발음함.)
262
+ #
263
+ def rule_14
264
+ return if @kc.jongsung.nil? || @kc.jongsung == 'ㅇ' || @next_kc.nil? || @next_kc.chosung != 'ㅇ'
265
+ if consonants = double_consonant_map[@kc.jongsung]
266
+ consonants[1] = 'ㅆ' if consonants[1] == 'ㅅ'
267
+ @kc.jongsung, @next_kc.chosung = consonants
268
+
269
+ true
270
+ end
271
+ end
272
+
273
+ # 제15항: 받침 뒤에 모음 ‘ㅏ, ㅓ, ㅗ, ㅜ, ㅟ’들로 시작되는 __실질 형태소__가 연결되는
274
+ # 경우에는, 대표음으로 바꾸어서 뒤 음절 첫소리로 옮겨 발음한다.
275
+ def rule_15
276
+ return if @kc.jongsung.nil? || @kc.jongsung == 'ㅇ' || @next_kc.nil? || @next_kc.chosung != 'ㅇ'
277
+
278
+ if false && %w[ㅏ ㅓ ㅗ ㅜ ㅟ].include?(@next_kc.jungsung) &&
279
+ %[ㅆ ㄲ ㅈ ㅊ ㄵ ㄻ ㄾ ㄿ ㄺ].include?(@kc.jongsung) == false # PATCH
280
+ @next_kc.chosung = @pconfig['jongsung sound'][ @kc.jongsung ]
281
+ @kc.jongsung = nil
282
+
283
+ true
284
+ end
285
+ end
286
+
287
+ # 제16항: 한글 자모의 이름은 그 받침소리를 연음하되, ‘ㄷ, ㅈ, ㅊ, ㅋ, ㅌ,
288
+ # ㅍ, ㅎ’의 경우에는 특별히 다음과 같이 발음한다.
289
+ def rule_16
290
+ return if @next_kc.nil?
291
+
292
+ map = {'디귿' => '디긋',
293
+ '지읒' => '지읏',
294
+ '치읓' => '치읏',
295
+ '키읔' => '키윽',
296
+ '티읕' => '티읏',
297
+ '피읖' => '피읍',
298
+ '히읗' => '히읏'}
299
+
300
+ word = @kc.to_s + @next_kc.to_s
301
+ if map.keys.include? word
302
+ new_char = @korean.dissect(map[word].scan(/./mu)[1])[0]
303
+ @next_kc.chosung = new_char.chosung
304
+ @next_kc.jongsung = new_char.jongsung
305
+
306
+ true
307
+ end
308
+ end
309
+
310
+ # 제17항: 받침 ‘ㄷ, ㅌ(ㄾ)’이 조사나 접미사의 모음 ‘ㅣ’와 결합되는 경우에는,
311
+ # [ㅈ, ㅊ]으로 바꾸어서 뒤 음절 첫소리로 옮겨 발음한다.
312
+ #
313
+ # [붙임] ‘ㄷ’ 뒤에 접미사 ‘히’가 결합되어 ‘티’를 이루는 것은 [치]로 발음한다.
314
+ def rule_17
315
+ return if @next_kc.nil? || %w[ㄷ ㅌ ㄾ].include?(@kc.jongsung) == false
316
+
317
+ if @next_kc.to_s == '이'
318
+ @next_kc.chosung = @kc.jongsung == 'ㄷ' ? 'ㅈ' : 'ㅊ'
319
+ @kc.jongsung = (dc = double_consonant_map[@kc.jongsung]) && dc.first
320
+
321
+ true
322
+ elsif @next_kc.to_s == '히'
323
+ @next_kc.chosung = 'ㅊ'
324
+ @kc.jongsung = (dc = double_consonant_map[@kc.jongsung]) && dc.first
325
+
326
+ true
327
+ end
328
+ end
329
+
330
+ # 제18항: 받침 ‘ㄱ(ㄲ, ㅋ, ㄳ, ㄺ), ㄷ(ㅅ, ㅆ, ㅈ, ㅊ, ㅌ, ㅎ), ㅂ(ㅍ, ㄼ,
331
+ # ㄿ, ㅄ)’은 ‘ㄴ, ㅁ’ 앞에서 [ㅇ, ㄴ, ㅁ]으로 발음한다.
332
+ def rule_18
333
+ map = {
334
+ %w[ㄱ ㄲ ㅋ ㄳ ㄺ] => 'ㅇ',
335
+ %w[ㄷ ㅅ ㅆ ㅈ ㅊ ㅌ ㅎ] => 'ㄴ',
336
+ %w[ㅂ ㅍ ㄼ ㄿ ㅄ] => 'ㅁ'
337
+ }
338
+ if @next_kc && map.keys.flatten.include?(@kc.jongsung) && %w[ㄴ ㅁ].include?(@next_kc.chosung)
339
+ @kc.jongsung = map[ map.keys.find { |e| e.include? @kc.jongsung } ]
340
+
341
+ true
342
+ end
343
+ end
344
+
345
+ # 제19항: 받침 ‘ㅁ, ㅇ’ 뒤에 연결되는 ‘ㄹ’은 [ㄴ]으로 발음한다.
346
+ # [붙임]받침 ‘ㄱ, ㅂ’ 뒤에 연결되는 ‘ㄹ’도 [ㄴ]으로 발음한다.
347
+ def rule_19
348
+ if @next_kc && @next_kc.chosung == 'ㄹ' && %w[ㅁ ㅇ ㄱ ㅂ].include?(@kc.jongsung)
349
+ @next_kc.chosung = 'ㄴ'
350
+
351
+ case @kc.jongsung
352
+ when 'ㄱ' then @kc.jongsung = 'ㅇ'
353
+ when 'ㅂ' then @kc.jongsung = 'ㅁ'
354
+ end
355
+
356
+ true
357
+ end
358
+ end
359
+
360
+ # 제20항: ‘ㄴ’은 ‘ㄹ’의 앞이나 뒤에서 [ㄹ]로 발음한다.
361
+ def rule_20
362
+ return if @next_kc.nil?
363
+
364
+ to = if %w[견란 진란 산량 단력 권력 원령 견례
365
+ 문로 단로 원론 원료 근류].include?(@kc_org.to_s + @next_kc_org.to_s)
366
+ 'ㄴ'
367
+ else
368
+ 'ㄹ'
369
+ end
370
+
371
+ if @kc.jongsung == 'ㄹ' && @next_kc.chosung == 'ㄴ'
372
+ @kc.jongsung = @next_kc.chosung = to
373
+
374
+ true
375
+ elsif @kc.jongsung == 'ㄴ' && @next_kc.chosung == 'ㄹ'
376
+ @kc.jongsung = @next_kc.chosung = to
377
+
378
+ true
379
+ end
380
+ end
381
+
382
+ # 제23항: 받침 ‘ㄱ(ㄲ, ㅋ, ㄳ, ㄺ), ㄷ(ㅅ, ㅆ, ㅈ, ㅊ, ㅌ), ㅂ(ㅍ, ㄼ, ㄿ,ㅄ)’
383
+ # 뒤에 연결되는 ‘ㄱ, ㄷ, ㅂ, ㅅ, ㅈ’은 된소리로 발음한다.
384
+ def rule_23
385
+ return if @next_kc.nil?
386
+ if fortis_map.keys.include?(@next_kc.chosung) &&
387
+ %w[ㄱ ㄲ ㅋ ㄳ ㄺ ㄷ ㅅ ㅆ ㅈ ㅊ ㅌ ㅂ ㅍ ㄼ ㄿ ㅄ].include?(@kc.jongsung)
388
+ @next_kc.chosung = fortis_map[@next_kc.chosung]
389
+
390
+ true
391
+ end
392
+ end
393
+
394
+ # 제24항: 어간 받침 ‘ㄴ(ㄵ), ㅁ(ㄻ)’ 뒤에 결합되는 어미의 첫소리 ‘ㄱ, ㄷ, ㅅ, ㅈ’은 된소리로 발음한다.
395
+ # 다만, 피동, 사동의 접미사 ‘-기-’는 된소리로 발음하지 않는다.
396
+ # 용언 어간에만 적용.
397
+ def rule_24
398
+ return if @next_kc.nil? ||
399
+ @next_kc.to_s == '기' # FIXME 피동/사동 여부 판단 불가. e.g. 줄넘기
400
+
401
+ # FIXME 용언 여부를 판단. 정확한 판단 불가.
402
+ return unless case @kc.jongsung
403
+ when 'ㄵ'
404
+ %w[앉 얹].include? @kc.to_s
405
+ when 'ㄻ'
406
+ %w[젊 닮].include? @kc.to_s
407
+ else
408
+ false # XXX 일반적인 경우 사전 없이 판단 불가
409
+ end
410
+
411
+ if %w[ㄱ ㄷ ㅅ ㅈ].include?(@next_kc.chosung) &&
412
+ %w[ㄴ ㄵ ㅁ ㄻ ㄼ ㄾ].include?(@kc.jongsung)
413
+ @next_kc.chosung = fortis_map[@next_kc.chosung]
414
+
415
+ true
416
+ end
417
+ end
418
+
419
+ # 제25항: 어간 받침 ‘ㄼ, ㄾ’ 뒤에 결합되는 어미의 첫소리 ‘ㄱ, ㄷ, ㅅ, ㅈ’은
420
+ # 된소리로 발음한다.
421
+ def rule_25
422
+ return if @next_kc.nil?
423
+
424
+ if %w[ㄱ ㄷ ㅅ ㅈ].include?(@next_kc.chosung) &&
425
+ %w[ㄼ ㄾ].include?(@kc.jongsung)
426
+ @next_kc.chosung = fortis_map[@next_kc.chosung]
427
+
428
+ true
429
+ end
430
+ end
431
+
432
+ # 제26항: 한자어에서, ‘ㄹ’ 받침 뒤에 연결되는 ‘ㄷ, ㅅ, ㅈ’은 된소리로 발음한다.
433
+ def rule_26
434
+ # TODO
435
+ end
436
+
437
+ # 제27항: __관형사형__ ‘-(으)ㄹ’ 뒤에 연결되는 ‘ㄱ, ㄷ, ㅂ, ㅅ, ㅈ’은 된소리로 발음한다.
438
+ # - ‘-(으)ㄹ’로 시작되는 어미의 경우에도 이에 준한다.
439
+ def rule_27
440
+ # FIXME: NOT PROPERLY IMPLEMENTED
441
+ return if @next_kc.nil?
442
+
443
+ # 비교적 확률이 높은 경우들에 대해서만 처리. "일" 은 제외.
444
+ if %w[할 갈 날 볼 을 앨 말 힐].include?(@kc.to_s) && # @kc.jongsung == 'ㄹ' &&
445
+ %w[ㄱ ㄷ ㅂ ㅅ ㅈ].include?(@next_kc.chosung)
446
+ @next_kc.chosung = fortis_map[@next_kc.chosung]
447
+ true
448
+ end
449
+ end
450
+
451
+ # 제26항: 한자어에서, ‘ㄹ’ 받침 뒤에 연결되는 ‘ㄷ, ㅅ, ㅈ’은 된소리로 발음한다.
452
+ # 제28항: 표기상으로는 사이시옷이 없더라도, 관형격 기능을 지니는 사이시옷이
453
+ # 있어야 할(휴지가 성립되는) 합성어의 경우에는, 뒤 단어의 첫소리 ‘ㄱ, ㄷ,
454
+ # ㅂ, ㅅ, ㅈ’을 된소리로 발음한다.
455
+ def rule_26_28
456
+ # TODO
457
+ end
458
+
459
+ # 제29항: 합성어 및 파생어에서, 앞 단어나 접두사의 끝이 자음이고 뒤 단어나
460
+ # 접미사의 첫음절이 ‘이, 야, 여, 요, 유’인 경우에는, ‘ㄴ’ 음을 첨가하여
461
+ # [니, 냐, 녀, 뇨, 뉴]로 발음한다.
462
+ def rule_29
463
+ # TODO
464
+ end
465
+
466
+ # 제30항: 사이시옷이 붙은 단어는 다음과 같이 발음한다.
467
+ # 1. ‘ㄱ, ㄷ, ㅂ, ㅅ, ㅈ’으로 시작하는 단어 앞에 사이시옷이 올 때는 이들
468
+ # 자음만을 된소리로 발음하는 것을 원칙으로 하되, 사이시옷을 [ㄷ]으로
469
+ # 발음하는 것도 허용한다.
470
+ # 2. 사이시옷 뒤에 ‘ㄴ, ㅁ’이 결합되는 경우에는 [ㄴ]으로 발음한다.
471
+ # 3. 사이시옷 뒤에 ‘이’ 음이 결합되는 경우에는 [ㄴㄴ]으로 발음한다.
472
+ def rule_30
473
+ return if @next_kc.nil? || @kc.jongsung != 'ㅅ'
474
+
475
+ if %w[ㄱ ㄷ ㅂ ㅅ ㅈ].include? @next_kc.chosung
476
+ @kc.jongsung = 'ㄷ' # or nil
477
+ @next_kc.chosung = fortis_map[@next_kc.chosung]
478
+
479
+ true
480
+ elsif %w[ㄴ ㅁ].include? @next_kc.chosung
481
+ @kc.jongsung = 'ㄴ'
482
+
483
+ true
484
+ elsif @next_kc.chosung == 'ㅇ' &&
485
+ %w[ㅣ ㅒ ㅖ ㅑ ㅕ ㅛ ㅠ].include?(@next_kc.jungsung) &&
486
+ @next_kc.jongsung # PATCH
487
+ @kc.jongsung = @next_kc.chosung = 'ㄴ'
488
+
489
+ true
490
+ end
491
+ end
492
+ end#Pronouncer
493
493
  end#Korean
494
494
  end#Gimchi