gimchi 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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