From 93f647e1c7951ec9eb4450c8079a67d5e4f44707 Mon Sep 17 00:00:00 2001 From: Dmitry Sedykh Date: Sun, 11 Jun 2023 12:12:54 +0300 Subject: [PATCH] update library --- LICENSE | 22 ++++++++ go.mod | 5 ++ go.sum | 2 + ru.go | 45 ++++++++++++++++ translit.go | 132 +++++++++++++++++------------------------------ translit_test.go | 1 + 6 files changed, 123 insertions(+), 84 deletions(-) create mode 100644 LICENSE create mode 100644 go.mod create mode 100644 go.sum create mode 100644 ru.go diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..acf57aa --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2023 Dmitry Sedykh + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..1e2b811 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/mdigger/translit + +go 1.20 + +require golang.org/x/text v0.9.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..20cf523 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= diff --git a/ru.go b/ru.go new file mode 100644 index 0000000..5054202 --- /dev/null +++ b/ru.go @@ -0,0 +1,45 @@ +package translit + +// RuMap описывает замены русских букв на английские при транслитерации. Некоторые буквы +// заменяются ни на одну, а на две или три буквы латинского алфавита. А мягкий знак вообще исчезает. +// Но такова обычная распространенная схема транслитерации. +var RuMap = Map{ + 'а': "a", + 'б': "b", + 'в': "v", + 'г': "g", + 'д': "d", + 'е': "e", + 'ё': "yo", + 'ж': "zh", + 'з': "z", + 'и': "i", + 'й': "j", + 'к': "k", + 'л': "l", + 'м': "m", + 'н': "n", + 'о': "o", + 'п': "p", + 'р': "r", + 'с': "s", + 'т': "t", + 'у': "u", + 'ф': "f", + 'х': "h", + 'ц': "c", + 'ч': "ch", + 'ш': "sh", + 'щ': "sch", + 'ъ': "'", + 'ы': "y", + 'ь': "", + 'э': "e", + 'ю': "ju", + 'я': "ja", +} + +// Ru выполняет транслитерацию строки с учетом словаря для русской транслитерации. +func Ru(text string) string { + return RuMap.Translate(text) +} diff --git a/translit.go b/translit.go index d26b6a0..be05131 100644 --- a/translit.go +++ b/translit.go @@ -12,117 +12,81 @@ // и заменяет их по предложенному ей словарю. Отличие только в том, что, с моей точки зрения, она // более корректно отрабатывает случаи с чередованием заглавных букв. Например: // -// "ЧАЩА" -> "CHASCHA" -// "ЧаЩа" -> "ChaScha" -// "Чаща" -> "Chascha" -// "чаЩА" -> "chaSCHA" +// "ЧАЩА" -> "CHASCHA" +// "ЧаЩа" -> "ChaScha" +// "Чаща" -> "Chascha" +// "чаЩА" -> "chaSCHA" // // Для транслитерации русских букв в ней уже предусмотрен встроенный словарь. Для других языков // вы можете задать свой. Все достаточно просто: // -// import "github.com/mdigger/translit" +// import "github.com/mdigger/translit" // -// tests := []string{ -// "Проверочная СТРОКА для транслитерации", -// "ЧАЩА", -// "ЧаЩа", -// "Чаща", -// "чаЩА", -// } -// for _, text := range tests { -// fmt.Println(translit.Ru(text)) -// } +// tests := []string{ +// "Проверочная СТРОКА для транслитерации", +// "ЧАЩА", +// "ЧаЩа", +// "Чаща", +// "чаЩА", +// } +// for _, text := range tests { +// fmt.Println(translit.Ru(text)) +// } package translit import ( - "bytes" - "golang.org/x/exp/utf8string" "strings" "unicode" + + "golang.org/x/text/cases" + "golang.org/x/text/language" ) -// RuTransiltMap описывает замены русских букв на английские при транслитерации. Некоторые буквы -// заменяются ни на одну, а на две или три буквы латинского алфавита. А мягкий знак вообще исчезает. -// Но такова обычная распространенная схема транслитерации. -var RuTransiltMap = map[rune]string{ - 'а': "a", - 'б': "b", - 'в': "v", - 'г': "g", - 'д': "d", - 'е': "e", - 'ё': "yo", - 'ж': "zh", - 'з': "z", - 'и': "i", - 'й': "j", - 'к': "k", - 'л': "l", - 'м': "m", - 'н': "n", - 'о': "o", - 'п': "p", - 'р': "r", - 'с': "s", - 'т': "t", - 'у': "u", - 'ф': "f", - 'х': "h", - 'ц': "c", - 'ч': "ch", - 'ш': "sh", - 'щ': "sch", - 'ъ': "'", - 'ы': "y", - 'ь': "", - 'э': "e", - 'ю': "ju", - 'я': "ja", -} +// Map определяет таблицу подстановки символов при транслитерации. +type Map map[rune]string -// Transliterate выполняет транслитерацию в строке по указанной таблице и возвращает новую строку с +// Translate выполняет транслитерацию в строке по указанной таблице и возвращает новую строку с // результатом такого преобразования. Все символы, которые не указаны в таблице транслитерации, // останутся без изменения. // -// При транслитерировании учитывается, что замена буквы может быть произведена на строку +// При транслитерации учитывается, что замена буквы может быть произведена на строку // произвольной длины и корректно обрабатываются чередования заглавных и строчных букв. В частности, // производится корректная транслитерация следующих случаев: -// "ЧАЩА" -> "CHASCHA" -// "ЧаЩа" -> "ChaScha" -// "Чаща" -> "Chascha" -// "чаЩА" -> "chaSCHA" +// +// "ЧАЩА" -> "CHASCHA" +// "ЧаЩа" -> "ChaScha" +// "Чаща" -> "Chascha" +// "чаЩА" -> "chaSCHA" // // При желании, вы можете указать любую таблицу в качестве второго параметра при вызове функции, // по которой и будет выполнено данное преобразование. -func Transliterate(text string, translitMap map[rune]string) string { - var result bytes.Buffer - utf8text := utf8string.NewString(text) - length := utf8text.RuneCount() - for index := 0; index < length; index++ { - runeValue := utf8text.At(index) - switch str, ok := translitMap[unicode.ToLower(runeValue)]; { - case !ok: - result.WriteRune(runeValue) - case str == "": +func (m Map) Translate(text string) string { + src := []rune(text) // преобразуем текст в набор символов + + var result strings.Builder + result.Grow(len(src) * 3) // выделяем память под построение результирующего текста + + for i, r := range src { + switch str, ok := m[unicode.ToLower(r)]; { + case !ok: // не входит в список символов для транслитерации + result.WriteRune(r) + case str == "": // игнорируется при транслитерации continue - case unicode.IsUpper(runeValue): - // Если следующий или предыдущий символ тоже заглавная буква, то все буквы строки - // заглавные. Иначе, заглавная только первая буква. - if (length > index+1 && unicode.IsUpper(utf8text.At(index+1))) || - (index > 0 && unicode.IsUpper(utf8text.At(index-1))) { - str = strings.ToUpper(str) + case unicode.IsUpper(r): // заглавная буква + if (i > 0 && unicode.IsUpper(src[i-1])) || + (i < len(src)-1 && unicode.IsUpper(src[i+1])) { + str = strings.ToUpper(str) // преобразуем все буквы в заглавные } else { - str = strings.Title(str) + str = toTitle.String(str) // преобразуем в заглавную только первый символ замены } - fallthrough + fallthrough // выполняем подмену default: - result.WriteString(str) + result.WriteString(str) // подменяем символ на транслитерированный } } + return result.String() } -// Ru выполняет транслитерацию строки с учетом словаря для русской транслитерации. -func Ru(text string) string { - return Transliterate(text, RuTransiltMap) -} +// toTitle преобразует первую букву в заглавную. +var toTitle = cases.Title(language.Und) diff --git a/translit_test.go b/translit_test.go index a20f98b..26a940f 100644 --- a/translit_test.go +++ b/translit_test.go @@ -2,6 +2,7 @@ package translit_test import ( "fmt" + "github.com/mdigger/translit" )