-
Notifications
You must be signed in to change notification settings - Fork 2
/
translit.go
92 lines (84 loc) · 4.92 KB
/
translit.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// Данная библиотека обеспечивает простую транслитерацию. Для этого достаточно только описать
// соответствующую таблицу подстановки символов, в которой буква проассоциирована с какой-либо
// строкой. В частности, такая ассоциация для транслитерации русского языка уже определена.
//
// Текущая реализация подразумевает только одностороннюю транслитерацию: обратное преобразование
// будет уже не так очевидно.
//
// Хоть кода в этой библиотеке и не очень много, но время на нее все-таки было потрачено, т.к.
// раньше я просто не задумывался о некоторых аспектах работы с транслитерацией.
//
// В общем, как и большинство других аналогичных библиотек, она перебирает все символы в строке
// и заменяет их по предложенному ей словарю. Отличие только в том, что, с моей точки зрения, она
// более корректно отрабатывает случаи с чередованием заглавных букв. Например:
//
// "ЧАЩА" -> "CHASCHA"
// "ЧаЩа" -> "ChaScha"
// "Чаща" -> "Chascha"
// "чаЩА" -> "chaSCHA"
//
// Для транслитерации русских букв в ней уже предусмотрен встроенный словарь. Для других языков
// вы можете задать свой. Все достаточно просто:
//
// import "github.com/mdigger/translit"
//
// tests := []string{
// "Проверочная СТРОКА для транслитерации",
// "ЧАЩА",
// "ЧаЩа",
// "Чаща",
// "чаЩА",
// }
// for _, text := range tests {
// fmt.Println(translit.Ru(text))
// }
package translit
import (
"strings"
"unicode"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
// Map определяет таблицу подстановки символов при транслитерации.
type Map map[rune]string
// Translate выполняет транслитерацию в строке по указанной таблице и возвращает новую строку с
// результатом такого преобразования. Все символы, которые не указаны в таблице транслитерации,
// останутся без изменения.
//
// При транслитерации учитывается, что замена буквы может быть произведена на строку
// произвольной длины и корректно обрабатываются чередования заглавных и строчных букв. В частности,
// производится корректная транслитерация следующих случаев:
//
// "ЧАЩА" -> "CHASCHA"
// "ЧаЩа" -> "ChaScha"
// "Чаща" -> "Chascha"
// "чаЩА" -> "chaSCHA"
//
// При желании, вы можете указать любую таблицу в качестве второго параметра при вызове функции,
// по которой и будет выполнено данное преобразование.
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(r): // заглавная буква
if (i > 0 && unicode.IsUpper(src[i-1])) ||
(i < len(src)-1 && unicode.IsUpper(src[i+1])) {
str = strings.ToUpper(str) // преобразуем все буквы в заглавные
} else {
str = toTitle.String(str) // преобразуем в заглавную только первый символ замены
}
fallthrough // выполняем подмену
default:
result.WriteString(str) // подменяем символ на транслитерированный
}
}
return result.String()
}
// toTitle преобразует первую букву в заглавную.
var toTitle = cases.Title(language.Und)