ununiga 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +12 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +21 -0
- data/README.md +69 -0
- data/Rakefile +8 -0
- data/lib/ununiga/i18n/josa_transformer.rb +16 -0
- data/lib/ununiga/jaso_splitter.rb +69 -0
- data/lib/ununiga/josa_picker.rb +65 -0
- data/lib/ununiga/version.rb +3 -0
- data/test/test.yml +5 -0
- data/test/test_jaso_splitter.rb +63 -0
- data/test/test_josa_picker.rb +32 -0
- data/test/test_josa_transformer.rb +26 -0
- data/ununiga.gemspec +16 -0
- metadata +16 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b8ed609a7765abb9b795d537e32fb9fbbb0c311d
|
4
|
+
data.tar.gz: 1cb2c593186f7c6ef0f741198738e0ee88d16ab0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b006f84c3b58d5b05e82af55f1633385ec6cb97d7caca032585eb26b5dffe69e77cbf5a82f93f51442e4ba1da2b2af49bb31ba8bc94a200a87f15f21b4f45cf
|
7
|
+
data.tar.gz: aa05c9c954390447392d858fc7ca10104cfa7f02bc5cadde5275afca9670a0f5ba31f4d7bc766534e0b192a81b5335c4ebefa6ebfa282d2a1527ed0cceec6775
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.gem
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/README.md
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
[![Build Status](https://travis-ci.org/keepcosmos/ununiga.svg?branch=master)](https://travis-ci.org/keepcosmos/ununiga)
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/ununiga.svg)](https://badge.fury.io/rb/ununiga)
|
3
|
+
|
4
|
+
# ununiga[은는이가]
|
5
|
+
|
6
|
+
은는이가는 한글의 자소분리를 분리하고 조사를 찾아주는 역할을 합니다.
|
7
|
+
I18n의 Backend 모듈도 제공합니다.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
```
|
11
|
+
gem install ununiga
|
12
|
+
```
|
13
|
+
|
14
|
+
### 조사 찾기
|
15
|
+
```ruby
|
16
|
+
require 'ununiga'
|
17
|
+
|
18
|
+
Ununiga::JosaPicker.takewell("레일즈와(과) 쟝고은(는) 싸우지 않습니다.")
|
19
|
+
# => "레일즈와 쟝고는 싸우지 않습니다."
|
20
|
+
Ununiga::JosaPicker.takewell("트위터(으)로 로그인합니다.")
|
21
|
+
# => "페이스북로 로그인합니다."
|
22
|
+
|
23
|
+
picker = Ununiga::JosaPicker.new("레일즈은(는) 루비을(를) 사용합니다.")
|
24
|
+
picker.takewell
|
25
|
+
# => "레일즈는 루비를 사용합니다.
|
26
|
+
|
27
|
+
picker.josas
|
28
|
+
# => [[3, ["은", "는"]], [10, ["을", "를"]]]
|
29
|
+
```
|
30
|
+
|
31
|
+
### I18n에 적용하기
|
32
|
+
1. Gemfile에 ununiga를 추가합니다.
|
33
|
+
```
|
34
|
+
gem 'ununiga'
|
35
|
+
```
|
36
|
+
|
37
|
+
2. Initializer나 environment config파일에 아래 코드를 추가합니다.
|
38
|
+
```ruby
|
39
|
+
I18n::Backend::Simple.send(:include, Ununiga::I18n::JosaTransformer)
|
40
|
+
```
|
41
|
+
|
42
|
+
3. 한글 locale yml 파일에 조사를 사용하는 부분을 찾아 '은(는)|(는)은|을(를)...'등으로 조사를 변경합니다.
|
43
|
+
```yaml
|
44
|
+
links:
|
45
|
+
sign_in_with_provider: "%{provider}(으)로 로그인"
|
46
|
+
|
47
|
+
# Rails의 ActiveModel/ActiveRecord의 Validation을 사용할 경우
|
48
|
+
errors:
|
49
|
+
# 디폴트는 `%{attribute} %{message}`형식으로 띄워쓰기가 되어 있으며로 format을 붙여쓰기로 변경해줍니다.
|
50
|
+
foramt: "%{attribute}%{message}"
|
51
|
+
messages:
|
52
|
+
accepted: 을(를) 반드시 확인해야 합니다.
|
53
|
+
equal_to: 은(는) %{count}와(과) 같아야 합니다
|
54
|
+
```
|
55
|
+
|
56
|
+
### 자소 분리하기
|
57
|
+
```ruby
|
58
|
+
splitter = Ununiga::JasoSplitter.new('흯')
|
59
|
+
splitter.chosung # => 'ㅎ'
|
60
|
+
splitter.jungsung # => 'ㅢ'
|
61
|
+
splitter.jongsung # => 'ㄳ'
|
62
|
+
splitter.split # => ['ㅎ', 'ㅢ', 'ㄳ']
|
63
|
+
```
|
64
|
+
|
65
|
+
## Test
|
66
|
+
두가지 방식으로 테스트 할 수 있습니다.
|
67
|
+
* `rake test` 혹은 그냥 `rake` 커맨드를 사용합니다.
|
68
|
+
* 특정 파일을 테스트할 경우 `ruby -Ilib:test /test/{file_name}` 을 사용합니다.
|
69
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'ununiga/josa_picker'
|
2
|
+
|
3
|
+
module Ununiga::I18n
|
4
|
+
module JosaTransformer
|
5
|
+
def translate(*args)
|
6
|
+
transform(super)
|
7
|
+
end
|
8
|
+
|
9
|
+
def transform(entry)
|
10
|
+
if !entry.is_a?(Hash) && I18n.locale.to_s =~ /ko|ko_KR/i
|
11
|
+
return Ununiga::JosaPicker.new(entry).takewell
|
12
|
+
end
|
13
|
+
entry
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Ununiga
|
2
|
+
# 한글 자소분리 클래스
|
3
|
+
# 1개의 한글 문자를 초성/중성/종성으로 분리한다.
|
4
|
+
#
|
5
|
+
# Sample:
|
6
|
+
#
|
7
|
+
# splitter = Ununiga::JasoSplitter.new('흯')
|
8
|
+
# splitter.extract_chosung # => 'ㅎ'
|
9
|
+
# splitter.extract_jungsung # => 'ㅢ'
|
10
|
+
# splitter.extract_jongsung # => 'ㄳ'
|
11
|
+
# splitter.split # => ['ㅎ', 'ㅢ', 'ㄳ']
|
12
|
+
#
|
13
|
+
# # 종성이 없는 경우는 nil
|
14
|
+
# splitter2 = Ununiga::JasoSplitter.new('가')
|
15
|
+
# splitter2.extract_jongsung # => nil
|
16
|
+
# splitter2.split # => ['ㄱ', 'ㅏ', nil]
|
17
|
+
#
|
18
|
+
class JasoSplitter
|
19
|
+
CHOSUNGS = %w(ㄱ ㄲ ㄴ ㄷ ㄸ ㄹ ㅁ ㅂ ㅃ ㅅ ㅆ ㅇ ㅈ ㅉ ㅊ ㅋ ㅌ ㅍ ㅎ).freeze
|
20
|
+
JUNGSUNGS = %w(ㅏ ㅐ ㅑ ㅒ ㅓ ㅔ ㅕ ㅖ ㅗ ㅘ ㅛ ㅙ ㅚ ㅜ ㅝ ㅞ ㅟ ㅠ ㅡ ㅢ ㅣ).freeze
|
21
|
+
JONGSUNGS = %w(ㄱ ㄲ ㄳ ㄴ ㄵ ㄶ ㄷ ㄹ ㄺ ㄻ ㄼ ㄽ ㄾ ㄿ ㅀ ㅁ ㅂ ㅄ ㅅ ㅆ ㅇ ㅈ ㅊ ㅋ ㅌ ㅍ ㅎ).unshift(nil).freeze
|
22
|
+
KR_RANGE = ('가'.unpack('U')[0]..'힣'.unpack('U')[0]).freeze
|
23
|
+
KR_OFFSET = KR_RANGE.first.freeze
|
24
|
+
|
25
|
+
attr_reader :kr_char
|
26
|
+
|
27
|
+
def initialize(kr_char)
|
28
|
+
fail ArgumentError, 'Argument must be single character' unless kr_char.size == 1
|
29
|
+
@kr_char = kr_char
|
30
|
+
end
|
31
|
+
|
32
|
+
def split
|
33
|
+
[extract_chosung, extract_jungsung, extract_jongsung]
|
34
|
+
end
|
35
|
+
|
36
|
+
def extract_chosung
|
37
|
+
nil unless korean?
|
38
|
+
CHOSUNGS[kr_relative_code / (JUNGSUNGS.size * JONGSUNGS.size)]
|
39
|
+
end
|
40
|
+
|
41
|
+
def extract_jungsung
|
42
|
+
nil unless korean?
|
43
|
+
JUNGSUNGS[kr_relative_code % (JUNGSUNGS.size * JONGSUNGS.size) / JONGSUNGS.size]
|
44
|
+
end
|
45
|
+
|
46
|
+
def extract_jongsung
|
47
|
+
nil unless korean?
|
48
|
+
JONGSUNGS[kr_relative_code % JONGSUNGS.size]
|
49
|
+
end
|
50
|
+
|
51
|
+
def korean?
|
52
|
+
KR_RANGE.cover?(kr_code)
|
53
|
+
end
|
54
|
+
|
55
|
+
[:chosung, :jungsung, :jongsung].each do |m|
|
56
|
+
alias_method m, :"extract_#{m}"
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def kr_code
|
62
|
+
kr_char.unpack('U')[0]
|
63
|
+
end
|
64
|
+
|
65
|
+
def kr_relative_code
|
66
|
+
kr_code - KR_OFFSET
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'ununiga/jaso_splitter'
|
2
|
+
|
3
|
+
module Ununiga
|
4
|
+
# 한글 초성, 중성, 종성 분리기
|
5
|
+
class JosaPicker
|
6
|
+
JOSAS = [%w(은 는),
|
7
|
+
%w(이 가),
|
8
|
+
%w(을 를),
|
9
|
+
%w(과 와),
|
10
|
+
%w(으로 로)
|
11
|
+
].freeze
|
12
|
+
|
13
|
+
attr_reader :korean_str
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def takewell(str)
|
17
|
+
new(str).takewell
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(str)
|
22
|
+
@korean_str = str
|
23
|
+
end
|
24
|
+
|
25
|
+
def takewell
|
26
|
+
korean_str.gsub josa_regexp do |matched|
|
27
|
+
index = $~.offset(0)[0]
|
28
|
+
next if index == 0
|
29
|
+
josa = JOSAS.find { |josa| josa_convension(josa).include? matched }
|
30
|
+
splitter = JasoSplitter.new(korean_str[index - 1])
|
31
|
+
josa[(splitter.jongsung ? 0 : 1)]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def josas
|
36
|
+
res = []
|
37
|
+
korean_str.scan josa_regexp do |matched|
|
38
|
+
res << [$~.offset(0)[0], JOSAS.find { |josa| josa.include? matched[0] }]
|
39
|
+
end
|
40
|
+
res
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def josa_regexp
|
46
|
+
@_josa_regexp ||=
|
47
|
+
begin
|
48
|
+
josa_regexp_seq = JOSAS.map do |josa|
|
49
|
+
conv = josa_convension(josa)
|
50
|
+
conv.map { |str| str.gsub!('(', '\\(').gsub!(')', '\\)') }
|
51
|
+
end
|
52
|
+
Regexp.new(josa_regexp_seq.flatten.join('|'))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# JOSAS의 element가 온다.
|
57
|
+
def josa_convension(josa)
|
58
|
+
if josa[0].size == 1
|
59
|
+
["#{josa[0]}(#{josa[1]})", "#{josa[1]}(#{josa[0]})"]
|
60
|
+
elsif josa[0].size == 2
|
61
|
+
["(#{josa[0][0]})#{josa[1]}"]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/test/test.yml
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'ununiga/jaso_splitter'
|
3
|
+
|
4
|
+
class JamoSplitterTest < Minitest::Unit::TestCase
|
5
|
+
def test_extract_chosung
|
6
|
+
testgroup = { '가' => 'ㄱ',
|
7
|
+
'낳' => 'ㄴ',
|
8
|
+
'짷' => 'ㅉ',
|
9
|
+
'하' => 'ㅎ'
|
10
|
+
}
|
11
|
+
testgroup.each do |char, chosung|
|
12
|
+
splitter = Ununiga::JasoSplitter.new(char)
|
13
|
+
assert_equal chosung, splitter.extract_chosung
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_extract_jungsung
|
18
|
+
testgroup = { '가' => 'ㅏ',
|
19
|
+
'내' => 'ㅐ',
|
20
|
+
'찋' => 'ㅢ',
|
21
|
+
'휷' => 'ㅠ'
|
22
|
+
}
|
23
|
+
testgroup.each do |char, jungsung|
|
24
|
+
splitter = Ununiga::JasoSplitter.new(char)
|
25
|
+
assert_equal jungsung, splitter.extract_jungsung
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_extract_jongsung
|
30
|
+
testgroup = { '가' => nil,
|
31
|
+
'내' => nil,
|
32
|
+
'찋' => 'ㅎ',
|
33
|
+
'휷' => 'ㄳ'
|
34
|
+
}
|
35
|
+
testgroup.each do |char, jongsung|
|
36
|
+
splitter = Ununiga::JasoSplitter.new(char)
|
37
|
+
assert_equal jongsung, splitter.extract_jongsung
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_split
|
42
|
+
testgroup = { '신' => ['ㅅ', 'ㅣ', 'ㄴ'],
|
43
|
+
'재' => ['ㅈ', 'ㅐ', nil],
|
44
|
+
'현' => ['ㅎ', 'ㅕ', 'ㄴ']
|
45
|
+
}
|
46
|
+
testgroup.each do |char, splitted|
|
47
|
+
splitter = Ununiga::JasoSplitter.new(char)
|
48
|
+
assert_equal splitted, splitter.split
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_non_korean_exception
|
53
|
+
%w(a 中 च Қ に).each do |char|
|
54
|
+
assert !Ununiga::JasoSplitter.new(char).korean?
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_non_single_character_exception
|
59
|
+
assert_raises ArgumentError do
|
60
|
+
Ununiga::JasoSplitter.new('두글자')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'ununiga/josa_picker'
|
3
|
+
|
4
|
+
class JosaPickerTest < Minitest::Unit::TestCase
|
5
|
+
def test_takewell
|
6
|
+
assert_equal '철수가 개발을 좋아합니다.', takewell('철수이(가) 개발을(를) 좋아합니다.')
|
7
|
+
|
8
|
+
assert_equal '레일즈는 루비를 사용합니다.', takewell('레일즈은(는) 루비을(를) 사용합니다.')
|
9
|
+
assert_equal '레일즈는 루비를 사용합니다.', takewell('레일즈는(은) 루비를(을) 사용합니다.')
|
10
|
+
|
11
|
+
assert_equal '레일즈와 쟝고는 싸우지 않습니다.', takewell('레일즈와(과) 쟝고은(는) 싸우지 않습니다.')
|
12
|
+
|
13
|
+
assert_equal '페이스북으로부터 인증되었습니다.', takewell('페이스북(으)로부터 인증되었습니다.')
|
14
|
+
assert_equal '트위터로부터 인증되었습니다.', takewell('트위터(으)로부터 인증되었습니다.')
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_find_josas
|
18
|
+
str1 = '철수이(가) 개발을(를) 좋아합니다.'
|
19
|
+
assert_equal [[2, %w(이 가)], [9, %w(을 를)]], find_josas(str1)
|
20
|
+
|
21
|
+
str2 = '레일즈은(는) 루비을(를) 사용합니다.'
|
22
|
+
assert_equal [[3, %w(은 는)], [10, %w(을 를)]], find_josas(str2)
|
23
|
+
end
|
24
|
+
|
25
|
+
def find_josas(str)
|
26
|
+
Ununiga::JosaPicker.new(str).josas
|
27
|
+
end
|
28
|
+
|
29
|
+
def takewell(str)
|
30
|
+
Ununiga::JosaPicker.new(str).takewell
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'i18n'
|
3
|
+
require 'ununiga/i18n/josa_transformer'
|
4
|
+
|
5
|
+
class JosaTransformerTest < Minitest::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
super
|
8
|
+
I18n::Backend::Simple.send(:include, Ununiga::I18n::JosaTransformer)
|
9
|
+
I18n.load_path = [File.dirname(__FILE__) + '/test.yml']
|
10
|
+
I18n.available_locales = [:en, :ko, :ko_KR]
|
11
|
+
I18n.locale = :ko
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_transform_korean
|
15
|
+
assert_equal '철수가 돈을 냅니다.', I18n.t(:someone_pay, name: '철수')
|
16
|
+
assert_equal '재현이 돈을 냅니다.', I18n.t(:someone_pay, name: '재현')
|
17
|
+
|
18
|
+
assert_equal '호랑이는 사과를 먹습니다.', I18n.t(:someone_eat_something, name: '호랑이', meal: '사과')
|
19
|
+
assert_equal '곰은 마늘을 먹습니다.', I18n.t(:someone_eat_something, name: '곰', meal: '마늘')
|
20
|
+
|
21
|
+
assert_equal '재현과 진아는 개발을 합니다.', I18n.t(:do_something_with_someone, name1: '재현', name2: '진아', doing: '개발')
|
22
|
+
assert_equal '정하와 민정은 디자인을 합니다.', I18n.t(:do_something_with_someone, name1: '정하', name2: '민정', doing: '디자인')
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
end
|
data/ununiga.gemspec
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'ununiga'
|
3
|
+
s.version = '1.0.3'
|
4
|
+
s.date = '2016-01-25'
|
5
|
+
s.summary = 'Support Jaso and Josa(Korean Language specific function)'
|
6
|
+
s.description = '한글 자소 분리 및 적절한 조사를 찾아주어 번역해줍니다.'
|
7
|
+
s.authors = ['Jaehyun Shin']
|
8
|
+
s.email = 'keepcosmos@gmail.com'
|
9
|
+
s.files = ['lib/ununiga.rb']
|
10
|
+
s.homepage = 'https://github.com/keepcosmos/ununiga'
|
11
|
+
s.files = `git ls-files`.split("\n")
|
12
|
+
s.require_paths = ["lib"]
|
13
|
+
s.add_development_dependency 'i18n'
|
14
|
+
s.add_development_dependency 'minitest'
|
15
|
+
s.license = 'MIT'
|
16
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ununiga
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jaehyun Shin
|
@@ -44,7 +44,22 @@ executables: []
|
|
44
44
|
extensions: []
|
45
45
|
extra_rdoc_files: []
|
46
46
|
files:
|
47
|
+
- ".gitignore"
|
48
|
+
- ".travis.yml"
|
49
|
+
- Gemfile
|
50
|
+
- Gemfile.lock
|
51
|
+
- README.md
|
52
|
+
- Rakefile
|
47
53
|
- lib/ununiga.rb
|
54
|
+
- lib/ununiga/i18n/josa_transformer.rb
|
55
|
+
- lib/ununiga/jaso_splitter.rb
|
56
|
+
- lib/ununiga/josa_picker.rb
|
57
|
+
- lib/ununiga/version.rb
|
58
|
+
- test/test.yml
|
59
|
+
- test/test_jaso_splitter.rb
|
60
|
+
- test/test_josa_picker.rb
|
61
|
+
- test/test_josa_transformer.rb
|
62
|
+
- ununiga.gemspec
|
48
63
|
homepage: https://github.com/keepcosmos/ununiga
|
49
64
|
licenses:
|
50
65
|
- MIT
|