Как в 1С найти и исправить слова со смешанными русскими и латинскими буквами?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При заполнении реквизитов номенклатуры (артикулов, наименований, описаний) операторы часто случайно переключают раскладку клавиатуры или копируют данные из сторонних источников. В результате в тексте появляются слова, содержащие смесь кириллических и латинских символов с одинаковым начертанием (например: «А», «В», «С», «Е», «Н», «О», «Р», «Т», «Х», «У» и соответствующие латинские A, B, C, E, H, O, P, T, X, Y). Это приводит к созданию неявных дублей, ошибкам поиска и сбоям при сканировании штрихкодов. Разберем по шагам, как программно определять и исправлять такие фрагменты в строках.

Простой алгоритм: принудительная латинизация артикула

Рассмотрим базовый сценарий, когда все символы артикула должны быть гарантированно латинскими, но часть из них была введена в русской раскладке. Если в строке встречаются русские буквы, не имеющие визуальных аналогов в латинице (например: «Б», «Г», «Д», «Ж»), артикул считается ошибочным и не корректируется автоматически.

Посмотрим на пример функции, выполняющей такую проверку и замену:


Функция ЛатинскийАртикул(Артикул) Экспорт
    
    Алфавит = "ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮЁ";
    РусскиеАналоги = "АВЕКМНОРСТХ";
    ЛатинскАналоги = "ABEKMHOPCTX";
    НовыйАртикул = "";        
    ПлохиеБуквыЕсть = Ложь;
    
    Для й = 1 По СтрДлина(Артикул) Цикл
        Буква = Сред(Артикул, й, 1);
        Если Найти(Алфавит, ВРег(Буква)) > 0 Тогда
            ИндексАналога = Найти(РусскиеАналоги, ВРег(Буква));
            Если ИндексАналога = 0 Тогда
                ПлохиеБуквыЕсть = Истина;
                Прервать;
            КонецЕсли; 
            НовыйАртикул = НовыйАртикул + Сред(ЛатинскАналоги, ИндексАналога, 1);
        Иначе
            НовыйАртикул = НовыйАртикул + Буква;
        КонецЕсли; 
    КонецЦикла;
    
    Если ПлохиеБуквыЕсть Тогда
        Возврат Артикул;
    Иначе
        Возврат НовыйАртикул;
    КонецЕсли; 
    
КонецФункции

Комплексный алгоритм: определение контекста и исправление в обе стороны

Проанализируем более сложную задачу: в произвольном тексте (наименовании или описании) встречаются слова, где алфавит нужно определить автоматически по однозначным символам (не имеющим визуальных аналогов), а затем привести всё слово к выбранному языку.

Разберем логику разделения алфавитов на группы:

  1. Однозначные русские буквы: символы, которые пишутся только по-русски ("ЙЦГШЩЗЪФЫПЛДЖЭЯЧИЬБЮ").
  2. Русские омоглифы: символы кириллицы, визуально совпадающие с латиницей ("АВЕКМНОРСТХУ").
  3. Однозначные латинские буквы: символы, характерные только для латиницы ("QWRUISDFGJLZVN").
  4. Латинские омоглифы: символы латиницы, визуально совпадающие с кириллицей ("ABEKMHOPCTXY").

Определим вспомогательные функции для доступа к наборам символов:


Функция РусБуквы() Экспорт
    Возврат "ЙЦГШЩЗЪФЫПЛДЖЭЯЧИЬБЮ";
КонецФункции

Функция РусАналоги() Экспорт
    Возврат "АВЕКМНОРСТХУ";
КонецФункции

Функция ЛатБуквы() Экспорт
    Возврат "QWRUISDFGJLZVN";
КонецФункции

Функция ЛатАналоги() Экспорт
    Возврат "ABEKMHOPCTXY";
КонецФункции

Функция ВсеБуквы() Экспорт
    Возврат РусБуквы() + РусАналоги() + ЛатБуквы() + ЛатАналоги();
КонецФункции

Рассмотрим функцию посимвольного исправления слова с сохранением регистра исходных букв:


Функция ИсправленноеРусЛатСлово(Строка, РусЛатИсправление) Экспорт
    ИсправленноеСлово = "";
    Для СчетчикСимволов = 1 По СтрДлина(Строка) Цикл
        Символ = Сред(Строка, СчетчикСимволов, 1);
        ИндексАналога = Найти(?(РусЛатИсправление, ЛатАналоги(), РусАналоги()), ВРег(Символ));
        
        Если ИндексАналога = 0 Тогда
            ИсправленноеСлово = ИсправленноеСлово + Символ;
        Иначе
            БукваЗамены = Сред(?(РусЛатИсправление, РусАналоги(), ЛатАналоги()), ИндексАналога, 1);
            ИсправленноеСлово = ИсправленноеСлово + ?(Символ = ВРег(Символ), БукваЗамены, НРег(БукваЗамены));
        КонецЕсли;
    КонецЦикла;
    Возврат ИсправленноеСлово;
КонецФункции

Теперь объединим разбор строки и логику принятия решения в единую функцию поиска ошибочных слов:


Функция НайтиРусЛатСлово(Строка, РусЛатСлово = "", ИсправленноеСлово = "") Экспорт
    ЕстьРусБуквы = Ложь; ЕстьРусАналоги = Ложь; ЕстьЛатБуквы = Ложь; ЕстьЛатАналоги = Ложь;
    
    Для СчетчикСимволов = 1 По СтрДлина(Строка) Цикл
        Символ = Сред(Строка, СчетчикСимволов, 1);
        ПредыдущийСимвол = Прав(РусЛатСлово, 1);
        
        Если (Найти(ВсеБуквы(), ВРег(ПредыдущийСимвол)) = 0) = (Найти(ВсеБуквы(), ВРег(Символ)) = 0) Тогда
            РусЛатСлово = РусЛатСлово + Символ;
            ЕстьРусБуквы   = ЕстьРусБуквы Или Не(Найти(РусБуквы(), ВРег(Символ)) = 0);
            ЕстьРусАналоги = ЕстьРусАналоги Или Не(Найти(РусАналоги(), ВРег(Символ)) = 0);
            ЕстьЛатБуквы   = ЕстьЛатБуквы Или Не(Найти(ЛатБуквы(), ВРег(Символ)) = 0);
            ЕстьЛатАналоги = ЕстьЛатАналоги Или Не(Найти(ЛатАналоги(), ВРег(Символ)) = 0);
        Иначе
            Если Не ПустаяСтрока(РусЛатСлово) Тогда
                Если ЕстьРусБуквы И ЕстьЛатБуквы Тогда
                    Возврат Истина; // Неисправляемая комбинация рус./лат. букв
                ИначеЕсли ЕстьРусБуквы И ЕстьЛатАналоги Тогда
                    ИсправленноеСлово = ИсправленноеРусЛатСлово(РусЛатСлово, Истина);
                    Возврат Истина; // Исправлено на русское
                ИначеЕсли ЕстьЛатБуквы И ЕстьРусАналоги Тогда
                    ИсправленноеСлово = ИсправленноеРусЛатСлово(РусЛатСлово, Ложь);
                    Возврат Истина; // Исправлено на латинское
                КонецЕсли;
                РусЛатСлово = "";
            КонецЕсли;
            ЕстьРусБуквы = Ложь; ЕстьРусАналоги = Ложь; ЕстьЛатБуквы = Ложь; ЕстьЛатАналоги = Ложь;
        КонецЕсли;
    КонецЦикла;
    
    Если Не ПустаяСтрока(РусЛатСлово) Тогда
        Если ЕстьРусБуквы И ЕстьЛатБуквы Тогда
            Возврат Истина;
        ИначеЕсли ЕстьРусБуквы И ЕстьЛатАналоги Тогда
            ИсправленноеСлово = ИсправленноеРусЛатСлово(РусЛатСлово, Истина);
            Возврат Истина;
        ИначеЕсли ЕстьЛатБуквы И ЕстьРусАналоги Тогда
            ИсправленноеСлово = ИсправленноеРусЛатСлово(РусЛатСлово, Ложь);
            Возврат Истина;
        КонецЕсли;
        РусЛатСлово = "";
    КонецЕсли;
    
    Возврат Ложь;
КонецФункции

Важные практические нюансы и оптимизация

Выясним ключевые особенности при работе с подобными алгоритмами в 1С:

  1. Ограничение омоглифов: если слово состоит исключительно из букв-аналогов (например, "СОРТ" или "COPT") и не содержит однозначных символов, эвристический алгоритм без внешнего словаря не сможет определить правильный язык.
  2. Производительность: для ускорения пакетной обработки больших справочников вместо функций Найти() со строками можно использовать проверку числовых кодов символов через КодСимвола() или применять регулярные выражения через COMОбъект("VBScript.RegExp").
  3. Доступность параметров в отчетах: если поиск выносится в отчет или внешнюю обработку, реквизиты формы (флаги поиска по реквизитам) не видны напрямую в модуле объекта и СКД. Их следует создавать как реквизиты самого отчета (объекта метаданных) либо передавать в процедуру формирования через структуру параметров.
← На главную