ununiga 1.0.2 → 1.0.3
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.
- 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
|
+
[](https://travis-ci.org/keepcosmos/ununiga)
|
2
|
+
[](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
|