2

Задача такая. Есть слово. Например "Паранoрмальное". Одна из букв здесь написана на английской раскладке. Нужно определить раскладку слова (по наибольшему сосредоточию), выявить символы из другой раскладки (думаю, в UTF есть похожие символы не только между русской и английской раскладками) и заменить их на аналогичные по начертанию символы из раскладки, к которой принадлежит большинство символов. Не подскажете быстрый способ это сделать на языке C#?

iRumba
  • 5,946
  • 2
    Боюсь, вам придётся вручную составлять таблицы «похожих» символов. – VladD May 06 '16 at 12:47
  • Если что, у кириллицы и латиницы 18 похожих символовABEKMHOPCTXaeopcyx. – Саша Черных May 06 '16 at 14:26
  • @VladD, возможно, таблицы уже составлены кем то до меня? Я просто не знаю как их найти, что ввести в гугле? – iRumba May 06 '16 at 15:36
  • Я лично не знаю. Причём нужно учесть, что буква A есть не только в кириллице и латинице, а ещё и в греческом. А в армянском есть буква ս, которая похожа на u. А в турецком есть ı без точки сверху. И ещё есть буквы с акцентами (ÀÁÂÃÄÅĀĂǍǠǺȀȂȦȺΆ). – VladD May 06 '16 at 15:45
  • 2
    mimic - тут кое-что есть. – Alexander Petrov May 06 '16 at 15:47
  • @VladD, да, конечно, я это понимаю. Это для меня немалый труд будет, учитывая мою "внимательность" )) Поэтому призываю вас помочь мне найти в гугле готовую таблицу соответствий :) – iRumba May 06 '16 at 15:47
  • 1
    Искать следует по слову homograph, по идее. https://en.wikipedia.org/wiki/IDN_homograph_attack – VladD May 06 '16 at 15:48
  • @AlexanderPetrov, спасибо! Похоже, это то что нужно! – iRumba May 06 '16 at 15:51
  • @AlexanderPetrov, хотя тут кое чего не хватает. Вот как в таком слове "АОЕ" понять, какие символы менять? Ну. Понятно, что если 2 буквы тут из кириллицы, а одна нет, то менять нужно ее на аналог из кириллицы. Но как составить классификацию символов? – iRumba May 06 '16 at 16:11
  • @VladD, нет, это что то другое. Ничего по моему вопросу с этим поисковым запросом не найти ( – iRumba May 06 '16 at 16:25
  • @VladD, как вариант: рисовать символ и сравнивать его с русским как картинки и по степень похожести картинки определять - подходит или нет :) – Grundy May 10 '16 at 06:14
  • @Grundy: Придётся рисовать разными шрифтами и в разном начертании. Например, курсивная т похожа на латинскую m, а прямая — нет. И букву «_д_» можно писать как латинскую «_g_», а можно похоже на «_ð_». – VladD May 10 '16 at 08:17
  • @VladD, я думаю шрифт можно стандартизировать :) – Grundy May 10 '16 at 08:17
  • @Grundy: Ну, ТС-то не знает заранее, каким шрифтом будет показан текст? – VladD May 10 '16 at 08:18
  • @VladD, ну почему? :) вполне можно и захардкодить для начала :) – Grundy May 10 '16 at 08:19
  • @Grundy, интересующие меня шрифты - Arial, TNR, Colibri. – iRumba May 10 '16 at 08:27
  • @VladD, а .net framework знает что либо о классификации символов? Мне нужно по коду узнать к какому языку он принадлежит – iRumba May 10 '16 at 08:36
  • @iRumba: Не всё так просто. Вот буква «б» принадлежит русскому, украинскому, белорусскому, болгарскому, чукотскому и ещё куче других языков, в которых письменность основана на кириллице. Но вы можете по идее составить таблицу отображения кодов символов в группы (кириллица, латиница, арабский, ...), или взять например эту: http://www.ssec.wisc.edu/~tomw/java/unicode.html – VladD May 10 '16 at 08:51
  • @VladD, эмм... ну и что? Программа же не видит символ, программа видит его код. Если в русском слове напечатан символ из украинского алфавита, программа должна это обнаружить и заменить на соответствующий код из русского алфивита. Предположим, что таблица похожих символов уже есть. Но нужна классификация по языкам – iRumba May 10 '16 at 11:06
  • @iRumba: Символ «б» не принадлежит русскому или украинскому алфавиту. Он общий для всех кириллических алфавитов. Как и буква «Q» общая для английского, французского, немецкого и т. п. Поэтому по букве нельзя сказать, какому языку она принадлежит. – VladD May 10 '16 at 12:02
  • @VladD, значит такие символы меня вообще не интересуют. Но что с остальными? Что, например, с символом "j" , который встречается 5 или 6 раз? Что мне делать, если классифицировать по языкам нельзя? – iRumba May 11 '16 at 03:36

2 Answers2

1

Для поиска букв, относящихся к определённому языку, можно использовать именованные блоки регулярных выражений.

А вот таблицы перекодировки придётся составлять вручную (в примере только по две похожих буквы в словарях).

string text = "Паранoрмальное";

var basicLatinToCyrillicDictionary = new Dictionary<char, char>
{
    ['a'] = 'а',
    ['o'] = 'о'
};
var cyrillicToBasicLatinDictionary = new Dictionary<char, char>
{
    ['а'] = 'a',
    ['о'] = 'o'
};

string basicLatinPattern = @"\p{IsBasicLatin}";
string cyrillicPattern = @"\p{IsCyrillic}";

var basicLatinMatches = Regex.Matches(text, basicLatinPattern);
var cyrillicMatches = Regex.Matches(text, cyrillicPattern);

int basicLatinCount = basicLatinMatches.Count;
int cyrillicCount = cyrillicMatches.Count;

var sb = new StringBuilder(text);

if (cyrillicCount > basicLatinCount)
{
    foreach (Match m in basicLatinMatches)
    {
        char basicLatinChar = m.Value[0];
        char cyrillicChar = basicLatinToCyrillicDictionary[basicLatinChar];

        sb.Replace(basicLatinChar, cyrillicChar, m.Index, 1);
    }
}
else
{
    // обратная замена
}

text = sb.ToString();
Console.WriteLine(text);

Если языков больше двух, то количество таблиц перекодировок становится устрашающим...


Присмотрелся я к диапазонам кодовых точек: судя по BasicLatin туда не только буквы попадают. Так что способ может не подойти.

  • Конечно же языков может быть несколько. Очень много получится таких вот словарей. Возможно, лучше использовать не Dictionary тогда, а Tuple или DataTable? – iRumba May 06 '16 at 15:35
  • Да и как я буду вводить символы других языков? У меня всего 2 раскладки на клавиатуре. Тут нужны коды символов. – iRumba May 06 '16 at 15:37
  • @iRumba: Ctrl-C/Ctrl-V? – VladD May 10 '16 at 08:37
  • @VladD, это издевательство :( – iRumba May 10 '16 at 08:38
  • @iRumba: Почему издевательство? Если есть готовая таблица, почему бы не скопипастить её в код? Не по одному символу, а всю вместе. – VladD May 10 '16 at 08:46
0

Используй коды ASCII, английский символы начинаются от 65 hex до 122hex русские - hex 192-255 Вот тут можно посмотреть коды

Тебе нужно каждый символ сравнивать просто

    string value = "Паранoрмальное";

// Convert the string into a byte[].
byte[] asciiBytes = Encoding.ASCII.GetBytes(value);
  • Ну зачем сразу ASCII-то использовать? Какие преимущества у этой кодировки перед Юникодом? – Pavel Mayorov May 06 '16 at 14:39