C#, как сделать транслитерацию. Перевод русской строки в latinitsu.
Думаю, что объяснять, что такое транслит, никому не нужно - это написание русских слов latinskimi bukvami, понадобилось сделать это на C#.
Первая проблема, которая возникла, это то, что четкого стандарта транслитерации нет, к сожалению, кто в лес, кто по дрова. Я находил даже стандарты с мерзкой диакритикой, т.е. всякими кракозяблями над буквами. В общем, для своего примера я выбрал какой-то довольно пожилой телеграфный стандарт (нашел в печатной книжке), благо, если кому-то что-то не нравится, всегда можно подправить в исходнике, тут меня больше интересует сам пример.
Русская буква | А | Б | В | Г | Д | Е | Ё | Ж |
Латинская буква или буквосочетание | A | B | V | G | D | E | Yo | Zh |
Русская буква | З | И | Й | К | Л | М | Н | О |
Латинская буква или буквосочетание | Z | I | J | K | L | M | N | O |
Русская буква | П | Р | С | Т | У | Ф | Х | Ц |
Латинская буква или буквосочетание | P | R | S | T | U | F | Kh | Ts |
Русская буква | Ч | Ш | Щ | Ъ | Ы | Ь | Э | Ю |
Латинская буква или буквосочетание | Ch | Sh | Shch | '' | Y | ' | E | Ju |
Русская буква | Я | |||||||
Латинская буква или буквосочетание | Ja |
Вторая проблема - этот стандарт проблематично использовать для транслитерации URL или имен файлов, надо что-то делать с пробелом (который в именах файлов и URL смотрится, как говно), так что в другом варианте таблицы, для замены
Ъ
, Ь
и пробела
, был выбран знак подчеркивания (_
).Создаем новый класс
Translit
:public class Translit
{
}
В класс
Translit
добавляем словарь (Dictionary
), который, в качестве ключа, будет использовать тип char
(русскую букву), а в качестве значения string
, содержащий ее латинский эквивалент. Думаю, ясно, почему string
- некоторые русские буквы передаются латинскими буквосочетаниями:private Dictionary<char, string> TranslitDict = new Dictionary<char,string>();
Теперь надо создать две функции, которые будут заполнять словарь нужными значениями.
Для общего случая:
private void FormDictStandart()
{
TranslitDict.Clear();
//Заглавные буквы (общий случай)
TranslitDict.Add('А', "A");
//часть кода вырезана для экономии места
TranslitDict.Add('Ъ', "''");
TranslitDict.Add('Ы', "Y");
TranslitDict.Add('Ь', "'");
TranslitDict.Add('Э', "E");
TranslitDict.Add('Ю', "Ju");
TranslitDict.Add('Я', "Ja");
//строчные буквы (общий случай)
TranslitDict.Add('а', "a");
//часть кода вырезана для экономии места
TranslitDict.Add('ъ', "''");
TranslitDict.Add('ы', "y");
TranslitDict.Add('ь', "'");
TranslitDict.Add('э', "e");
TranslitDict.Add('ю', "ju");
TranslitDict.Add('я', "ja");
}
И для "режима совместимости":
private void FormDictCompat()
{
TranslitDict.Clear();
//Заглавные буквы (режим совместимости)
TranslitDict.Add('А', "A");
//часть кода вырезана для экономии места
TranslitDict.Add('Ъ', "_");
TranslitDict.Add('Ы', "Y");
TranslitDict.Add('Ь', "_");
TranslitDict.Add('Э', "E");
TranslitDict.Add('Ю', "Ju");
TranslitDict.Add('Я', "Ja");
//строчные буквы (режим совместимости)
TranslitDict.Add('а', "a");
//часть кода вырезана для экономии места
TranslitDict.Add('ъ', "_");
TranslitDict.Add('ы', "y");
TranslitDict.Add('ь', "_");
TranslitDict.Add('э', "e");
TranslitDict.Add('ю', "ju");
TranslitDict.Add('я', "ja");
//пробел
TranslitDict.Add(' ', "_");
}
Теперь необходимо добавить в класс свойство, чтобы переключать режимы и переформировывать словарь. Классически, добавляем внутреннюю переменную
compatibility
типа bool
, для хранения текущего значения свойства, и само свойство, при изменении которого, будет вызываться одна из вышеуказанных функций:private bool compatibility = false;
public bool Compatibility
{
get
{
return compatibility;
}
set
{
if (value)
{
FormDictCompat();
compatibility = true;
}
else
{
FormDictStandart();
compatibility = false;
}
}
}
Добавим простой конструктор класса:
public Translit(bool Compat)
{
Compatibility = Compat;
}
Алгоритм простой: надо проверить, содержится ли переданный в функцию символ в словаре, если да, то выдать соответствующее значение, если нет (т.е. передана латинская буква, знак препинания, цифра, или что-то иное), выдать этот же символ, преобразованный в строку:
public string TranslitChar(char Rus)
{
if (TranslitDict.ContainsKey(Rus))
{
return TranslitDict[Rus];
}
else
{
return Rus.ToString();
}
}
Это я уже делал в маленьком примере (копия), так что просто вставлю функции оттуда:
//русские буквы
public static bool ContainsRus(string TestString)
{
return
Regex.IsMatch(TestString, @"[а-я]", RegexOptions.IgnoreCase);
}
//русские буквы и пробелы
public static bool ContainsRusOrSpace(string TestString)
{
return
Regex.IsMatch(TestString, @"[а-я]|\s", RegexOptions.IgnoreCase);
}
1. Проверяем, содержит ли строка русские буквы или русские буквы и пробел, в зависимости от режима работы.
Примечание: Сильно работу алгоритма это замедлить не должно, а вот ускорить, в случае какой-нибудь гигантской строки может, т.к.
Regex
, который используется в функции поверки, работает со строкой напрямую в памяти, средствами .NET.Если искомого нет - возвращаем оригинальную строку.
2. Проходимся по символам строки, транслитерируем их, возвращаем новую строку.
Примечание: Для формирования новой строки лучше использовать
StringBuilder
вместо простой конкатенации, опять же, на случай, если строка может оказаться гигантской. См. подробности в статье на Хабреpublic string TranslitString(string Rus)
{
string sBuf = "";
StringBuilder sb = new StringBuilder();
if (compatibility)
{
if (!ContainsRusOrSpace(Rus)) return Rus;
}
else
{
if (!ContainsRus(Rus)) return Rus;
}
for (int i = 0; i < Rus.Length; i++)
{
if (TranslitDict.ContainsKey(Rus[i]))
{
sBuf = TranslitDict[Rus[i]];
}
else
{
sBuf = Rus[i].ToString();
}
sb.Append(sBuf);
}
return sb.ToString();
}
Класс
Translit
на GitHubТестовый пример на GitHub
Это репост с сайта http://tolik-punkoff.com
Оригинал: https://tolik-punkoff.com/2021/11/08/c-k