
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(); }
C#, как присвоить char значение null или его аналог.
Пост из серии спрашивали — отвечаем.
Значение null
переменной типа char
не присвоить никак, т.к. char
относится к «простым» (в другой литературе «базовым») типам, которые не могут принимать значение null
, и обязательно должны быть проинициализированы каким-то значением.
Но иногда надо объявить переменную типа char
, с которой работать будем потом, например, в цикле. Как тогда быть? Можно инициализировать переменную символом с кодом 0
(0x00
). Проще всего сделать это так:
char Chr = '\0';
Но можно и другими способами:
char Chr = char.MinValue;
char Chr = (char)0;
Или даже с извращениями:
char Chr = "\0".ToCharArray()[0];
Или с извращениями, используя большой и тяжелый класс Convert
, который лучше избегать, если он не очень нужен:
char Chr = Convert.ToChar(0);
C#, регулярное выражение для кириллицы.
Понадобилось тут узнать, содержит ли строка кириллицу. Решение через Regexp.
[а-я]
[а-я]|\s
Подключаем System.Text.RegularExpressions
:
using System.Text.RegularExpressions;
Код:
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); }
Анализ и распаковка установщика QTInstaller вручную. С помощью HEX-редактора и такой-то матери.
Понадобилась мне одна программка, которая, почему-то не захотела ставиться на мою систему, причем не захотела без всяких ошибок и вылетаний. Инсталлятор просто висел на 1% и дальше двигаться не хотел. Зная, что поддержка винды у этой софтины зависит исключительно от бодуна разработчиков (то они винду вообще не поддерживали, потом прошлая версия прекрасно ставилась и работала, а тут вдруг опять нет), решил я в софтине поковыряться, небось, софтина-то работает, а инсталлятор кривой. Но о том, как я возился с софтиной, напишу как-нибудь позже. А тут будет такой простенький заметк про реверсинг инсталлятора.
Я уже как-то упоминал (копия), что инсталляторов и упаковщиков есть туева хуча на свете, и для начала надо определить, с каким именно инсталлером мы имеем дело. Для этого воспользуюсь программкой Detect It Easy (DiE), которая по своей базе сигнатур может определять тип экзешника, чем он упакован, чем скомпилирован, а если это инсталлятор — определить и его тип. Программка работает примерно также, как антивирусный сканер, определяя по сигнатурам, с чем мы имеем дело. Благо, почти все упаковщики, компиляторы или сборщики инсталляционных пакетов, так или иначе оставляют свою сигнатуру в файле.
Итак, скармливаю DiE исследуемый инсталлятор.

Видим тип — QT installer.
Естественно, о ней я и подумал сразу же, не изобретать же велосипед, до нас его более умные люди изобрели. А не тут-то было! Автоматического распаковщика не нашел, так что стал думать… Qt проект открытый, значит, скорее всего, они особо не заморачивались, и инсталлятор представляет из себя самораспаковывающийся архив, который по структуре выглядит как-то так, как выглядят самораспаковывающиеся архивы RAR WinZip или 7Zip — в начале файла EXE-модуль, а после него данные, которые EXE-модуль распаковывает:

В принципе, что я иду верным путем, можно было понять из главного окна DiE, тот недвусмысленно сообщал про overlay (оверлей), в котором находятся QT installer data, т.е. данные QT-установщика.
Detect It Easy (DiE):
— На Exe-Lab
— На Mega.nz
qresExtract:
— Binary for Windows x86
— Sources
WinHex 19.9: