В практике программирования на 1С часто возникает задача очистки данных. Например, при загрузке информации из Excel, распознавании сканов документов или интеграции со сторонними системами нам могут приходить строки вида "Вес: 120 кг", "Артикул № 123-45/А" или "Суплата: 10 500.00 руб.". Чтобы работать с этими данными как с числами, необходимо отделить цифры от текста.
В этой статье мы подробно разберем несколько способов решения этой задачи: от классического перебора символов до использования регулярных выражений и элегантных однострочных решений на современных версиях платформы.
Самый надежный и универсальный способ, который работает на любой версии платформы (7.7, 8.1, 8.2, 8.3) и в любой операционной системе (Windows, Linux, MacOS) — это посимвольный обход строки. Алгоритм прост: мы смотрим на каждый символ и проверяем, является ли он цифрой.
Рассмотрим функцию, которая собирает все найденные цифры в одну строку и возвращает массив чисел. Это полезно, если в строке может быть несколько чисел (например, "Код 123, кол-во 5").
Для проверки, является ли символ цифрой, можно использовать сравнение диапазонов кодов символов или просто сравнение строк.
Функция НайтиЧислаВСтроке(Знач ИсходнаяСтрока) Экспорт
МассивЧисел = Новый Массив;
СтрокаЧисла = "";
// Проходим по всей длине строки
Для Индекс = 1 По СтрДлина(ИсходнаяСтрока) Цикл
Символ = Сред(ИсходнаяСтрока, Индекс, 1);
КодСимвола = КодСимвола(Символ);
// Проверяем, является ли символ цифрой (коды ASCII от 48 до 57 соответствуют '0'-'9')
// Также можно добавить проверку на разделители дроби, например "." или ","
Если КодСимвола >= 48 И КодСимвола <= 57 Тогда
СтрокаЧисла = СтрокаЧисла + Символ;
Иначе
// Если цепочка цифр прервалась, и мы уже что-то накопили — сохраняем число
Если Не ПустаяСтрока(СтрокаЧисла) Тогда
МассивЧисел.Добавить(Число(СтрокаЧисла));
СтрокаЧисла = "";
КонецЕсли;
КонецЕсли;
КонецЦикла;
// Не забываем добавить последнее число, если строка заканчивалась цифрой
Если Не ПустаяСтрока(СтрокаЧисла) Тогда
МассивЧисел.Добавить(Число(СтрокаЧисла));
КонецЕсли;
Возврат МассивЧисел;
КонецФункции
Преимущества: Полная кроссплатформенность, предсказуемость, возможность тонкой настройки (например, можно легко добавить обработку точки или запятой).
Недостатки: Код получается громоздким. На очень длинных строках конкатенация (сложение строк) может работать медленно.
Если ваша база работает на сервере Windows или вы выполняете код на клиенте под Windows, мощным инструментом являются регулярные выражения. Они позволяют описать шаблон поиска (паттерн) и извлечь данные одной командой.
Для этого мы используем системный COM-объект VBScript.RegExp. Разберем пример, который умеет извлекать не только целые, но и дробные числа (с точкой или запятой).
Функция ДостатьЧислаRegExp(ИсходнаяСтрока) Экспорт
МассивРезультат = Новый Массив;
// Создаем COM-объект
Попытка
RegExp = Новый COMОбъект("VBScript.RegExp");
Исключение
// Скорее всего, это не Windows или закрыт доступ к COM
Возврат МассивРезультат;
КонецПопытки;
RegExp.IgnoreCase = Истина; // Игнорировать регистр (не важно для цифр, но полезно знать)
RegExp.Global = Истина; // Искать все вхождения, а не только первое
RegExp.MultiLine = Ложь;
// Паттерн:
// \d+ - одна или более цифр
// [.,]? - необязательный разделитель (точка или запятая)
// \d* - ноль или более цифр после разделителя
RegExp.Pattern = "\d+[.,]?\d*";
Matches = RegExp.Execute(ИсходнаяСтрока);
Для Каждого Match Из Matches Цикл
Попытка
// Заменяем запятую на точку или наоборот, чтобы Число() корректно сработало
// в зависимости от настроек системы, но чаще всего 1С понимает оба варианта,
// если это стандартная функция Число()
МассивРезультат.Добавить(Число(Match.Value));
Исключение
// Обработка ошибок преобразования
КонецПопытки;
КонецЦикла;
Возврат МассивРезультат;
КонецФункции
Важное примечание: Этот код не будет работать на серверах под управлением Linux, в веб-клиенте (браузере) и на мобильных устройствах, так как там нет библиотеки VBScript.
Начиная с версии платформы 8.3.6, появились функции СтрРазделить и СтрСоединить. С их помощью можно реализовать "гениальный" метод очистки строки от мусора в две строчки кода без использования циклов 1С. Этот метод работает очень быстро, так как функции реализованы внутри платформы на C++.
Суть метода заключается в двойной инверсии:
Разберем это по шагам на примере строки "Артикул123Склад":
Функция ОставитьТолькоЦифры(Знач ИсходнаяСтрока) Экспорт
// 1. Получаем строку, содержащую ВСЕ символы, кроме цифр.
// Мы "дробим" строку цифрами.
// "Артикул123Склад" -> Разделитель "0123456789" -> Массив ["Артикул", "Склад"]
// Затем соединяем обратно -> "АртикулСклад"
ЛишниеСимволы = СтрСоединить(СтрРазделить(ИсходнаяСтрока, "0123456789", Ложь), "");
// 2. Теперь используем полученные "ЛишниеСимволы" как разделитель для исходной строки.
// "Артикул123Склад" -> Разделитель "АртикулСклад" -> Массив ["", "123", ""] (пустые строки отсекаются параметром Ложь)
// В итоге получаем чистое число в виде строки.
ЧистаяСтрокаСЧислом = СтрСоединить(СтрРазделить(ИсходнаяСтрока, ЛишниеСимволы, Ложь), "");
// Преобразуем в число (если строка пустая, вернется 0)
Возврат Число(ЧистаяСтрокаСЧислом);
КонецФункции
Или вариант в одну строку ("One-liner"), который можно встретить в коде опытных разработчиков:
Результат = СтрСоединить(СтрРазделить(Строка, СтрСоединить(СтрРазделить(Строка, "0123456789"), "")), "");
Особенность метода: Этот способ склеит все цифры в одно число. Если у вас строка "Вес 10 Цена 20", то результатом будет число 1020. Если вам нужно получить массив чисел [10, 20], этот метод нужно модифицировать (не делать последний СтрСоединить, а перебирать массив).
Если нам нужно из строки "15; 24; 42" получить массив чисел, используя современные функции, можно сделать так:
Функция ПолучитьМассивЧиселИзСтроки(Знач СтрокаСЧислами)
// 1. Определяем все, что НЕ цифры
Мусор = СтрСоединить(СтрРазделить(СтрокаСЧислами, "0123456789"), "");
// 2. Разделяем исходную строку, используя "Мусор" как разделители.
// Параметр Ложь (третий) означает, что пустые строки будут игнорироваться.
МассивСтрок = СтрРазделить(СтрокаСЧислами, Мусор, Ложь);
МассивЧисел = Новый Массив;
Для Каждого ТекСтрока Из МассивСтрок Цикл
МассивЧисел.Добавить(Число(ТекСтрока));
КонецЦикла;
Возврат МассивЧисел;
КонецФункции
Сложнее всего, когда нужно сохранить дробную часть, например, из строки "Сумма 123.50 руб".
Если использовать метод "удаления лишнего" (Метод 3), точка может попасть в "мусор" и удалиться, превратив 123.50 в 12350. Чтобы этого избежать, нужно добавить точку (или запятую) в список "разрешенных" символов при первом разделении.
Давайте адаптируем однострочное решение для дробных чисел:
// Добавляем точку и запятую в строку цифр
ЛишниеСимволы = СтрСоединить(СтрРазделить(ИсходнаяСтрока, "0123456789.,"), "");
// Теперь при удалении лишнего, точки и запятые останутся
ЧистаяСтрока = СтрСоединить(СтрРазделить(ИсходнаяСтрока, ЛишниеСимволы, Ложь), "");
Однако здесь есть риск. Если строка вида "1.2.3.4", то такой метод оставит "1.2.3.4", что вызовет ошибку при преобразовании в число. Поэтому для сложных случаев с грязными данными надежнее использовать Метод 1 (Цикл) или Метод 2 (RegExp) с четким паттерном.