From bb444c8cebb40b9677cdb3f11b950414f7115584 Mon Sep 17 00:00:00 2001 From: ymw0407 Date: Sat, 6 Apr 2024 22:47:55 +0900 Subject: [PATCH] Feat : decomposing hangeul into syllables feature added - 2 decompose option added - jamo option - qwerty option - test code added - gitignore added Signed-off-by: ymw0407 --- .gitignore | 0 README.md | 0 examples/ex.go | 12 +++ go.mod | 11 +++ go.sum | 10 +++ internal/data/data.go | 143 +++++++++++++++++++++++++++++++ pkg/jamo/jamo.go | 63 ++++++++++++++ pkg/jamo/jamo_test.go | 47 ++++++++++ pkg/options/interface.go | 23 +++++ pkg/options/jamoOption.go | 84 ++++++++++++++++++ pkg/options/jamoOption_test.go | 99 +++++++++++++++++++++ pkg/options/qwertyOption.go | 89 +++++++++++++++++++ pkg/options/qwertyOption_test.go | 59 +++++++++++++ 13 files changed, 640 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 examples/ex.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/data/data.go create mode 100644 pkg/jamo/jamo.go create mode 100644 pkg/jamo/jamo_test.go create mode 100644 pkg/options/interface.go create mode 100644 pkg/options/jamoOption.go create mode 100644 pkg/options/jamoOption_test.go create mode 100644 pkg/options/qwertyOption.go create mode 100644 pkg/options/qwertyOption_test.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/examples/ex.go b/examples/ex.go new file mode 100644 index 0000000..95c717b --- /dev/null +++ b/examples/ex.go @@ -0,0 +1,12 @@ +package main + +import ( + "fmt" + + "github.com/ymw0407/golang-jamo/pkg/jamo" + "github.com/ymw0407/golang-jamo/pkg/options" +) + +func main() { + fmt.Println(jamo.DecomposeHangeul("얘를롦놈", options.Jamo())) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..4f1bee1 --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module github.com/ymw0407/golang-jamo + +go 1.21.6 + +require github.com/stretchr/testify v1.9.0 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..60ce688 --- /dev/null +++ b/go.sum @@ -0,0 +1,10 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/data/data.go b/internal/data/data.go new file mode 100644 index 0000000..68a8a20 --- /dev/null +++ b/internal/data/data.go @@ -0,0 +1,143 @@ +/* +Copyright 2024 Yun Minwoo. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package data + +const ( + StartHangeul = rune(0xAC00) // '가' + EndHangeul = rune(0xD7A3) // '힣' +) + +var ( + ChoSung = []rune{ + 'ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ', + } + JungSung = []rune{ + 'ㅏ', 'ㅐ', 'ㅑ', 'ㅒ', 'ㅓ', 'ㅔ', 'ㅕ', 'ㅖ', 'ㅗ', 'ㅘ', 'ㅙ', 'ㅚ', 'ㅛ', 'ㅜ', 'ㅝ', 'ㅞ', 'ㅟ', 'ㅠ', 'ㅡ', 'ㅢ', 'ㅣ', + } + JongSung = []rune{ + 0, 'ㄱ', 'ㄲ', 'ㄳ', 'ㄴ', 'ㄵ', 'ㄶ', 'ㄷ', 'ㄹ', 'ㄺ', 'ㄻ', 'ㄼ', 'ㄽ', 'ㄾ', 'ㄿ', 'ㅀ', 'ㅁ', 'ㅂ', 'ㅄ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ', + } +) + +var ( // QWERTY Keyboard + // Qwerty keyboard form without shift + Qwerty = []string{"ㅘ", "ㅙ", "ㅚ", "ㅝ", "ㅞ", "ㅟ", "ㅢ", "ㄳ", "ㄵ", "ㄶ", "ㄺ", "ㄻ", "ㄼ", "ㄽ", "ㄾ", "ㄿ", "ㅀ", "ㅄ"} + // Qwerty keyboard form without shift + /* + fmt.Println(QwertyDecomposer["ㅘ"]) // "ㅗㅏ" + fmt.Println(QwertyDecomposer["ㄳ"]) // "ㄱㅅ" + fmt.Println(QwertyDecomposer["ㄲ"]) // "ㄲ" + // to make "ㄱㄱ" use QwertyOnlyShiftDecomposer1 or QwertyOnlyShiftDecomposer2 + */ + QwertyDecomposer = map[string]string{ + "ㅘ": "ㅗㅏ", + "ㅙ": "ㅗㅐ", + "ㅚ": "ㅗㅣ", + "ㅝ": "ㅜㅓ", + "ㅞ": "ㅜㅔ", + "ㅟ": "ㅜㅣ", + "ㅢ": "ㅡㅣ", + "ㄳ": "ㄱㅅ", + "ㄵ": "ㄴㅈ", + "ㄶ": "ㄴㅎ", + "ㄺ": "ㄹㄱ", + "ㄻ": "ㄹㅁ", + "ㄼ": "ㄹㅂ", + "ㄽ": "ㄹㅅ", + "ㄾ": "ㄹㅌ", + "ㄿ": "ㄹㅍ", + "ㅀ": "ㄹㅎ", + "ㅄ": "ㅂㅅ", + } + // Qwerty keyboard form only with shift + QwertyOnlyShift = []string{"ㄲ", "ㄸ", "ㅃ", "ㅆ", "ㅉ", "ㅒ", "ㅖ"} + // Qwerty keyboard form only with shift + /* + fmt.Println(QwertyOnlyShiftDecomposer1["ㄲ"]) // "ㄱㄱ" + fmt.Println(QwertyOnlyShiftDecomposer1["ㅒ"]) // "ㅑㅣ" + fmt.Println(QwertyOnlyShiftDecomposer1["ㅖ"]) // "ㅕㅣ" + */ + QwertyOnlyShiftDecomposer1 = map[string]string{ + "ㄲ": "ㄱㄱ", + "ㄸ": "ㄷㄷ", + "ㅃ": "ㅂㅂ", + "ㅆ": "ㅅㅅ", + "ㅉ": "ㅈㅈ", + "ㅒ": "ㅑㅣ", + "ㅖ": "ㅕㅣ", + } + // Qwerty keyboard form only with shift + /* + fmt.Println(QwertyOnlyShiftDecomposer2["ㄲ"]) // "ㄱㄱ" + fmt.Println(QwertyOnlyShiftDecomposer2["ㅒ"]) // "ㅐㅐ" + fmt.Println(QwertyOnlyShiftDecomposer2["ㅖ"]) // "ㅔㅔ" + */ + QwertyOnlyShiftDecomposer2 = map[string]string{ + "ㄲ": "ㄱㄱ", + "ㄸ": "ㄷㄷ", + "ㅃ": "ㅂㅂ", + "ㅆ": "ㅅㅅ", + "ㅉ": "ㅈㅈ", + "ㅒ": "ㅐㅐ", + "ㅖ": "ㅔㅔ", + } +) + +var ( + // tense consonants(된소리 자음) + TenseConsonants = []string{"ㄲ", "ㄸ", "ㅃ", "ㅆ", "ㅉ"} + // tense consonants(된소리 자음) decomposer + TenseConsonantsDecomposer = map[string]string{ + "ㄲ": "ㄱㄱ", + "ㄸ": "ㄷㄷ", + "ㅃ": "ㅂㅂ", + "ㅆ": "ㅅㅅ", + "ㅉ": "ㅈㅈ", + } + // complex consonants(복합 자음) + ComplexConsonants = []string{"ㄳ", "ㄵ", "ㄶ", "ㄺ", "ㄻ", "ㄼ", "ㄽ", "ㄾ", "ㄿ", "ㅀ", "ㅄ"} + // complex consonants(복합 자음) decomposer + ComplexConsonantsDecomposer = map[string]string{ + "ㄳ": "ㄱㅅ", + "ㄵ": "ㄴㅈ", + "ㄶ": "ㄴㅎ", + "ㄺ": "ㄹㄱ", + "ㄻ": "ㄹㅁ", + "ㄼ": "ㄹㅂ", + "ㄽ": "ㄹㅅ", + "ㄾ": "ㄹㅌ", + "ㄿ": "ㄹㅍ", + "ㅀ": "ㄹㅎ", + "ㅄ": "ㅂㅅ", + } + // Dipthong(이중 모음) + Diphthong = []string{"ㅐ", "ㅒ", "ㅔ", "ㅖ", "ㅘ", "ㅙ", "ㅚ", "ㅝ", "ㅞ", "ㅢ"} + // Dipthong(이중 모음) decomposer + DiphthongDecomposer = map[string]string{ + "ㅐ": "ㅏㅣ", + "ㅒ": "ㅑㅣ", + "ㅔ": "ㅓㅣ", + "ㅖ": "ㅕㅣ", + "ㅘ": "ㅗㅏ", + "ㅙ": "ㅗㅏㅣ", + "ㅚ": "ㅗㅣ", + "ㅝ": "ㅜㅓ", + "ㅞ": "ㅜㅓㅣ", + "ㅟ": "ㅜㅣ", + "ㅢ": "ㅡㅣ", + } +) diff --git a/pkg/jamo/jamo.go b/pkg/jamo/jamo.go new file mode 100644 index 0000000..65943e1 --- /dev/null +++ b/pkg/jamo/jamo.go @@ -0,0 +1,63 @@ +/* +Copyright 2024 Yun Minwoo. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package jamo + +import ( + "github.com/ymw0407/golang-jamo/internal/data" + "github.com/ymw0407/golang-jamo/pkg/options" +) + +// Decompose Hangeul words into Syllables +/* + // example + fmt.Println(DecomposeHangeul("한글 is hangeul!")) // "ㅎㅏㄴㄱㅡㄹ is hangeul!" +*/ +//* TODO: Allow to apply serveral option (now only first option can apply) +func DecomposeHangeul(hangeuls string, opts ...options.Options) (decomposedHangeul string) { + filterFunc := func(syllable string) string { + return syllable + } + + if len(opts) > 0 { + option := opts[0] + filterFunc = option.GetFilterFunc() + } + + for _, hangeul := range hangeuls { + if hangeul < data.StartHangeul || hangeul > data.EndHangeul { // non-hangeul character + decomposedHangeul += string(hangeul) + continue + } + + diff := hangeul - data.StartHangeul + + choIdx := diff / (21 * 28) + jungIdx := (diff % (21 * 28)) / 28 + jongIdx := diff % 28 + + chosung := string(data.ChoSung[choIdx]) + jungsung := string(data.JungSung[jungIdx]) + jongsung := "" + if jongIdx > 0 { + jongsung = string(data.JongSung[jongIdx]) + } + + decomposedHangeul += filterFunc(chosung) + filterFunc(jungsung) + filterFunc(jongsung) + } + + return decomposedHangeul +} diff --git a/pkg/jamo/jamo_test.go b/pkg/jamo/jamo_test.go new file mode 100644 index 0000000..b1cb9d6 --- /dev/null +++ b/pkg/jamo/jamo_test.go @@ -0,0 +1,47 @@ +/* +Copyright 2024 Yun Minwoo. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package jamo_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/ymw0407/golang-jamo/pkg/jamo" +) + +func TestDecomposeHangeul(t *testing.T) { + t.Run("한글 is hangeul!", func(t *testing.T) { + expected := "ㅎㅏㄴㄱㅡㄹ is hangeul!" + res := jamo.DecomposeHangeul("한글 is hangeul!") + + assert.Equal(t, expected, res, res+" : `"+expected+"` is expected!") + }) + + t.Run("ㄱ is giyeok!", func(t *testing.T) { + expected := "ㄱ is giyeok!" + res := jamo.DecomposeHangeul("ㄱ is giyeok!") + + assert.Equal(t, expected, res, res+" : `"+expected+"` is expected!") + }) + + t.Run("윤민우", func(t *testing.T) { + expected := "ㅇㅠㄴㅁㅣㄴㅇㅜ" + res := jamo.DecomposeHangeul("윤민우") + + assert.Equal(t, expected, res, res+" : `"+expected+"` is expected!") + }) +} diff --git a/pkg/options/interface.go b/pkg/options/interface.go new file mode 100644 index 0000000..056c335 --- /dev/null +++ b/pkg/options/interface.go @@ -0,0 +1,23 @@ +/* +Copyright 2024 Yun Minwoo. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package options + +type Options interface { + GetFilterFunc() func(syllable string) string +} + +//* TODO: Add Cheonjiin(천지인) Keyboard form diff --git a/pkg/options/jamoOption.go b/pkg/options/jamoOption.go new file mode 100644 index 0000000..dc941fe --- /dev/null +++ b/pkg/options/jamoOption.go @@ -0,0 +1,84 @@ +/* +Copyright 2024 Yun Minwoo. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package options + +import ( + "slices" + + "github.com/ymw0407/golang-jamo/internal/data" +) + +// option for decompose tense constants(된소리 자음, ㄲㄸㅃㅆㅉ), complex consonants(복합 자음, ㄳㄵㄶㄺㄻㄼㄽㄾㄿㅀㅄ), dipthongs(이중 모음, ㅐㅔㅘㅙㅚㅝㅞㅢ) +type JamoOption struct { + tenseConsonants bool + complexConsonants bool + diphthong bool +} + +// get JamoOption that option for decompose tense constants(된소리 자음, ㄲㄸㅃㅆㅉ), complex consonants(복합 자음, ㄳㄵㄶㄺㄻㄼㄽㄾㄿㅀㅄ), dipthongs(이중 모음, ㅐㅔㅘㅙㅚㅝㅞㅢ) +func Jamo() *JamoOption { + return &JamoOption{ + tenseConsonants: true, + complexConsonants: true, + diphthong: true, + } +} + +// Option to also decompose tense consonants(된소리 자음, ㄲㄸㅃㅆㅉ) // default is true +/* + // example + opts := options.Jamo().SetTenseConsonants(true) // ㄲ -> ㄱㄱ +*/ +func (j *JamoOption) SetTenseConsonants(b bool) *JamoOption { + j.tenseConsonants = b + return j +} + +// Option to also decompose complex consonants(복합 자음, ㄳㄵㄶㄺㄻㄼㄽㄾㄿㅀㅄ) // default is true +/* + // example + opts := options.Jamo().SetComplexConsonants(true) // ㄳ -> ㄳ +*/ +func (j *JamoOption) SetComplexConsonants(b bool) *JamoOption { + j.complexConsonants = b + return j +} + +// Option to also decompose dipthongs(이중 모음, ㅐㅒㅔㅖㅘㅙㅚㅝㅞㅢ) // default is true +/* + // example + opts := options.Jamo().SetDiphthong(true) // ㅞ -> ㅜㅓㅣ +*/ +func (j *JamoOption) SetDiphthong(b bool) *JamoOption { + j.diphthong = b + return j +} + +// GetDecomposeFilter method +func (j JamoOption) GetFilterFunc() func(syllable string) string { + return func(syllable string) string { + if j.tenseConsonants && slices.Contains(data.TenseConsonants, syllable) { // ㄲㄸㅃㅆㅉ + return data.TenseConsonantsDecomposer[syllable] + } else if j.complexConsonants && slices.Contains(data.ComplexConsonants, syllable) { // ㄳㄵㄶㄺㄻㄼㄽㄾㄿㅀㅄ + return data.ComplexConsonantsDecomposer[syllable] + } else if j.diphthong && slices.Contains(data.Diphthong, syllable) { // ㅐㅒㅔㅖㅘㅙㅚㅝㅞㅢ + return data.DiphthongDecomposer[syllable] + } + + return syllable + } +} diff --git a/pkg/options/jamoOption_test.go b/pkg/options/jamoOption_test.go new file mode 100644 index 0000000..a470c34 --- /dev/null +++ b/pkg/options/jamoOption_test.go @@ -0,0 +1,99 @@ +/* +Copyright 2024 Yun Minwoo. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package options_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/ymw0407/golang-jamo/pkg/jamo" + "github.com/ymw0407/golang-jamo/pkg/options" +) + +func TestJamoOption(t *testing.T) { + t.Run("꿳테스트 with jamo options(all false)", func(t *testing.T) { + expected := "ㄲㅞㄳㅌㅔㅅㅡㅌㅡ" + opts := options.Jamo().SetComplexConsonants(false).SetTenseConsonants(false).SetDiphthong(false) + res := jamo.DecomposeHangeul("꿳테스트", *opts) + + assert.Equal(t, expected, res, res+" : `"+expected+"` is expected!") + }) + + t.Run("꿳테스트 with jamo options(complex consonants)", func(t *testing.T) { + expected := "ㄲㅞㄱㅅㅌㅔㅅㅡㅌㅡ" + opts := options.Jamo().SetComplexConsonants(true).SetTenseConsonants(false).SetDiphthong(false) + res := jamo.DecomposeHangeul("꿳테스트", *opts) + + assert.Equal(t, expected, res, res+" : `"+expected+"` is expected!") + }) + + t.Run("꿳테스트 with jamo options(tense consonants)", func(t *testing.T) { + expected := "ㄱㄱㅞㄳㅌㅔㅅㅡㅌㅡ" + opts := options.Jamo().SetComplexConsonants(false).SetTenseConsonants(true).SetDiphthong(false) + res := jamo.DecomposeHangeul("꿳테스트", *opts) + + assert.Equal(t, expected, res, res+" : `"+expected+"` is expected!") + }) + + t.Run("꿳테스트 with jamo options(diphthong)", func(t *testing.T) { + expected := "ㄲㅜㅓㅣㄳㅌㅓㅣㅅㅡㅌㅡ" + opts := options.Jamo().SetComplexConsonants(false).SetTenseConsonants(false).SetDiphthong(true) + res := jamo.DecomposeHangeul("꿳테스트", *opts) + + assert.Equal(t, expected, res, res+" : `"+expected+"` is expected!") + }) + + t.Run("꿳테스트 with jamo options(complex consonants, tense consonants)", func(t *testing.T) { + expected := "ㄱㄱㅞㄱㅅㅌㅔㅅㅡㅌㅡ" + opts := options.Jamo().SetComplexConsonants(true).SetTenseConsonants(true).SetDiphthong(false) + res := jamo.DecomposeHangeul("꿳테스트", *opts) + + assert.Equal(t, expected, res, res+" : `"+expected+"` is expected!") + }) + + t.Run("꿳테스트 with jamo options(complex consonants, tense consonants)", func(t *testing.T) { + expected := "ㄱㄱㅞㄱㅅㅌㅔㅅㅡㅌㅡ" + opts := options.Jamo().SetComplexConsonants(true).SetTenseConsonants(true).SetDiphthong(false) + res := jamo.DecomposeHangeul("꿳테스트", *opts) + + assert.Equal(t, expected, res, res+" : `"+expected+"` is expected!") + }) + + t.Run("꿳테스트 with jamo options(complex consonants, diphthong)", func(t *testing.T) { + expected := "ㄲㅜㅓㅣㄱㅅㅌㅓㅣㅅㅡㅌㅡ" + opts := options.Jamo().SetComplexConsonants(true).SetTenseConsonants(false).SetDiphthong(true) + res := jamo.DecomposeHangeul("꿳테스트", *opts) + + assert.Equal(t, expected, res, res+" : `"+expected+"` is expected!") + }) + + t.Run("꿳테스트 with jamo options(tense consonants, diphthong)", func(t *testing.T) { + expected := "ㄱㄱㅜㅓㅣㄳㅌㅓㅣㅅㅡㅌㅡ" + opts := options.Jamo().SetComplexConsonants(false).SetTenseConsonants(true).SetDiphthong(true) + res := jamo.DecomposeHangeul("꿳테스트", *opts) + + assert.Equal(t, expected, res, res+" : `"+expected+"` is expected!") + }) + + t.Run("꿳테스트 with jamo options(complex consonants, tense consonants, diphthong)", func(t *testing.T) { + expected := "ㄱㄱㅜㅓㅣㄱㅅㅌㅓㅣㅅㅡㅌㅡ" + opts := options.Jamo().SetComplexConsonants(true).SetTenseConsonants(true).SetDiphthong(true) + res := jamo.DecomposeHangeul("꿳테스트", *opts) + + assert.Equal(t, expected, res, res+" : `"+expected+"` is expected!") + }) +} diff --git a/pkg/options/qwertyOption.go b/pkg/options/qwertyOption.go new file mode 100644 index 0000000..62f25ff --- /dev/null +++ b/pkg/options/qwertyOption.go @@ -0,0 +1,89 @@ +/* +Copyright 2024 Yun Minwoo. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package options + +import ( + "slices" + + "github.com/ymw0407/golang-jamo/internal/data" +) + +// option for decompose Qwerty Keyboard form +type QwertyOption struct { + shiftOption ShiftOption +} + +type ShiftOption int + +const ( + // default option // none shift option + /* + "ㄳ" -> "ㄱㅅ" + "ㄲ" -> "ㄲ" + "ㅒ" -> "ㅒ" + */ + None ShiftOption = iota + // option1 // first shift option for qwerty + /* + "ㄳ" -> "ㄱㅅ" + "ㄲ" -> "ㄱㄱ" + "ㅒ" -> "ㅑㅣ" + */ + QwertyShiftOption1 + // option2 // second shift option for qwerty + /* + "ㄳ" -> "ㄱㅅ" + "ㄲ" -> "ㄱㄱ" + "ㅒ" -> "ㅐㅐ" + */ + QwertyShiftOption2 +) + +// get QwertyOption that option for decompose qwerty keyboard form // option1 is default option +func Qwerty() *QwertyOption { + return &QwertyOption{ + shiftOption: QwertyShiftOption1, + } +} + +// Option to also decompose tense consonants(된소리 자음, ㄲㄸㅃㅆㅉ) // default is true +/* + // example + opts := options.Qwerty().SetTenseConsonants(true) // ㄲ -> ㄱㄱ +*/ +func (q *QwertyOption) SetShiftOption(s ShiftOption) *QwertyOption { + q.shiftOption = s + return q +} + +// GetDecomposeFilter method +func (q QwertyOption) GetFilterFunc() func(syllable string) string { + return func(syllable string) string { + if slices.Contains(data.Qwerty, syllable) { + return data.QwertyDecomposer[syllable] + } else if slices.Contains(data.QwertyOnlyShift, syllable) { + switch q.shiftOption { + case QwertyShiftOption1: + return data.QwertyOnlyShiftDecomposer1[syllable] + case QwertyShiftOption2: + return data.QwertyOnlyShiftDecomposer2[syllable] + } + } + + return syllable + } +} diff --git a/pkg/options/qwertyOption_test.go b/pkg/options/qwertyOption_test.go new file mode 100644 index 0000000..01b8ffd --- /dev/null +++ b/pkg/options/qwertyOption_test.go @@ -0,0 +1,59 @@ +/* +Copyright 2024 Yun Minwoo. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package options_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/ymw0407/golang-jamo/pkg/jamo" + "github.com/ymw0407/golang-jamo/pkg/options" +) + +func TestQwertyOption(t *testing.T) { + t.Run("꺣 테스트! with qwerty options(none shiftOption)", func(t *testing.T) { + expected := "ㄲㅒㄱㅅ ㅌㅔㅅㅡㅌㅡ!" + opts := options.Qwerty().SetShiftOption(options.None) + res := jamo.DecomposeHangeul("꺣 테스트!", *opts) + + assert.Equal(t, expected, res, res+" : `"+expected+"` is expected!") + }) + + t.Run("꺣 테스트! with qwerty options(shiftOption1)", func(t *testing.T) { + expected := "ㄱㄱㅑㅣㄱㅅ ㅌㅔㅅㅡㅌㅡ!" + opts := options.Qwerty().SetShiftOption(options.QwertyShiftOption1) + res := jamo.DecomposeHangeul("꺣 테스트!", *opts) + + assert.Equal(t, expected, res, res+" : `"+expected+"` is expected!") + }) + + t.Run("꺣 테스트! with qwerty default options(shiftOption1)", func(t *testing.T) { + expected := "ㄱㄱㅑㅣㄱㅅ ㅌㅔㅅㅡㅌㅡ!" + opts := options.Qwerty().SetShiftOption(options.QwertyShiftOption1) + res := jamo.DecomposeHangeul("꺣 테스트!", *opts) + + assert.Equal(t, expected, res, res+" : `"+expected+"` is expected!") + }) + + t.Run("꺣 테스트! with qwerty options(shiftOption2)", func(t *testing.T) { + expected := "ㄱㄱㅐㅐㄱㅅ ㅌㅔㅅㅡㅌㅡ!" + opts := options.Qwerty().SetShiftOption(options.QwertyShiftOption2) + res := jamo.DecomposeHangeul("꺣 테스트!", *opts) + + assert.Equal(t, expected, res, res+" : `"+expected+"` is expected!") + }) +}