Skip to content

Commit

Permalink
update library
Browse files Browse the repository at this point in the history
  • Loading branch information
mdigger committed Jun 11, 2023
1 parent 8422236 commit 93f647e
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 84 deletions.
22 changes: 22 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
The MIT License (MIT)

Copyright (c) 2023 Dmitry Sedykh <[email protected]>

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.

5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/mdigger/translit

go 1.20

require golang.org/x/text v0.9.0
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -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=
45 changes: 45 additions & 0 deletions ru.go
Original file line number Diff line number Diff line change
@@ -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)
}
132 changes: 48 additions & 84 deletions translit.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
1 change: 1 addition & 0 deletions translit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package translit_test

import (
"fmt"

"github.com/mdigger/translit"
)

Expand Down

0 comments on commit 93f647e

Please sign in to comment.