На практике программисты 1С часто сталкиваются с задачей парсинга произвольных строк. Рассмотрим классическую ситуацию: в реквизитах справочника хранятся наименования в формате многоязычного текста, например, «машина // car» или «яблоко // apple». Возникает необходимость вывести или сохранить раздельно строку на русском языке и строку на латинице. Длина наименований у всех элементов разная, поэтому банальное отсечение по фиксированному количеству символов нам не подойдет.
Давайте подробно разберем несколько вариантов решения этой задачи, начиная от самых простых подходов с перебором и заканчивая оптимизированными алгоритмами и использованием регулярных выражений.
Самый очевидный и наглядный способ — это проверить каждый символ исходной строки на вхождение в строку, содержащую все буквы нужного алфавита. Посмотрим на пример кода, реализующий эту логику:
КириллическиеСимволы = "АаБбВвГгДдЕеЁёЖжЗзИиЙйКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЬьЫыЪъЭэЮюЯя";
ЛатинскиеСимволы = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz";
КириллическийТекст = "";
ЛатинскийТекст = "";
Для НомерСимвола = 1 По СтрДлина(ИсходныйТекст) Цикл
ТекущийСимвол = Сред(ИсходныйТекст, НомерСимвола, 1);
Если СтрНайти(КириллическиеСимволы, ТекущийСимвол) > 0 Тогда
КириллическийТекст = КириллическийТекст + ТекущийСимвол;
ИначеЕсли СтрНайти(ЛатинскиеСимволы, ТекущийСимвол) > 0 Тогда
ЛатинскийТекст = ЛатинскийТекст + ТекущийСимвол;
КонецЕсли;
КонецЦикла;
Важное замечание по оптимизации: В коде выше символы собираются через оператор сложения (конкатенацию). В 1С сложение строк в цикле — это ресурсоемкая операция. Значительно более быстрый и правильный подход — добавлять отфильтрованные символы в объект Массив, а после завершения цикла объединить элементы массива в готовый текст с помощью функции СтрСоединить.
Если нам нужно проанализировать огромные массивы данных, функция СтрНайти внутри цикла может замедлить работу. Выясним причину: поиск подстроки — операция не самая дешевая. Гораздо быстрее работает математическое сравнение кодов символов ASCII. Метод КодСимвола позволяет нам проверить попадание буквы в нужный числовой диапазон.
Латинские (английские) буквы всегда находятся в строгих диапазонах таблицы символов: от 65 до 90 для заглавных (A-Z) и от 97 до 122 для строчных (a-z). Посмотрим, как выглядит оптимизированный цикл проверки на латиницу:
Для Сч = 1 По СтрДлина(ИсходныйТекст) Цикл
Код = КодСимвола(Сред(ИсходныйТекст, Сч, 1));
ЭтоЛатиница = ((Код >= 65 И Код <= 90) Или (Код >= 97 И Код <= 122));
Если ЭтоЛатиница Тогда
// Обработка латинского символа
КонецЕсли;
КонецЦикла;
Математическое сравнение чисел (кодов) выполняется на уровне процессора значительно быстрее, чем строковые функции. Этот способ отлично подходит для нагруженных участков кода.
Регулярные выражения — мощнейший инструмент работы со строками, который решает задачу извлечения нужных букв в несколько строк кода. Разберем по шагам, как это можно реализовать. Долгое время разработчикам 1С приходилось использовать COM-объект операционной системы Windows:
RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.MultiLine = Истина;
RegExp.Global = Истина;
RegExp.IgnoreCase = Истина;
RegExp.Pattern = "[a-zA-Z]+"; // Шаблон поиска английских слов
// Далее перебор совпадений...
Однако, COM-объект VBScript.RegExp имеет существенный недостаток: он не будет работать на серверах Linux. К счастью, платформа 1С активно развивается. Начиная с версии платформы 1С:Предприятие 8.3.23, в языке появились встроенные, нативные (кроссплатформенные) регулярные выражения.
Теперь для таких задач можно использовать встроенный объект РегулярноеВыражение и функции СтрНайтиПоРегулярномуВыражению. Применяя паттерн [a-zA-Z]+, мы можем извлечь сразу целые английские слова из текста без циклов перебора символов.
Если в вашей конфигурации внедрена Библиотека стандартных подсистем (БСП), нет необходимости «изобретать велосипед». Проанализируем возможности стандартных общих модулей. В модуле СтроковыеФункцииКлиентСервер существуют готовые удобные функции:
ТолькоЛатиницаВСтроке() — проверяет, состоит ли строка только из символов латинского алфавита.ТолькоКириллицаВСтроке() — аналогично для русского языка.Для нашей исходной задачи с явными разделителями («машина // car») можно сначала разбить строку в массив функцией СтрРазделить, используя "//" в качестве разделителя, а затем прогнать получившиеся части через эти проверки БСП.
В завершение разберем еще один нестандартный, но лаконичный вариант от участников форума, использующий функции разделения строк и подстановки алфавитов:
КириллическиеСимволы = "АаБбВвГгДдЕеЁёЖжЗзИиЙйКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЬьЫыЪъЭэЮюЯя";
ЛатинскиеСимволы = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz";
// Удаляем кириллицу (останется латиница и прочие символы)
ЛатинскийТекст = СтрСоединить(СтрРазделить(ИсходныйТекст, КириллическиеСимволы, Ложь), "");
// Удаляем латиницу (останется кириллица)
КириллическийТекст = СтрСоединить(СтрРазделить(ИсходныйТекст, ЛатинскиеСимволы, Ложь), "");
В этом примере строка с алфавитом выступает как гигантский набор разделителей. Функция разделяет исходный текст везде, где встречается русская (или английская) буква, а затем мы склеиваем остатки. Это отличный пример гибкости встроенного языка 1С!