Как подсчитать количество целых чисел в строке в 1С

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

При разработке алгоритмов обработки текста или загрузки данных из внешних файлов программистам 1С часто приходится анализировать текстовые строки, содержащие список чисел. Зачастую возникает специфическая задача: необходимо посчитать количество только целых чисел в исходном тексте.

Сложность заключается в том, что целое число может быть записано в строке не только в классическом виде (например, "2", "3", "4"), но и с явно указанной дробной частью, состоящей исключительно из нулей (например, "1.0" или "1,0"). При этом строки вида "5.13" содержат полноценную дробную часть и считаться целыми числами не должны.

В этой статье мы подробно разберем, как правильно реализовать алгоритм подсчета целых чисел на встроенном языке 1С:Предприятие, проанализируем подводные камни при работе с типом Число, а также рассмотрим альтернативный способ решения через регулярные выражения.

Анализ проблемы и подводные камни стандартного преобразования

Рассмотрим типичную ошибку при разборе строки с числами. Когда разработчик использует встроенную функцию Число() внутри конструкции Попытка ... Исключение, он сталкивается со следующими нюансами:

  1. Разделитель дробной части: Функция Число() в платформе 1С считает корректным разделителем дробной части только точку (например, "1.0"). Если в строке передается значение с запятой (например, "1,0"), то вызов Число("1,0") вызывает исключение («Преобразование к типу Число не может быть выполнено»). Значение попадает в блок Исключение и не учитывается.
  2. Прерывание цикла или пропуск элементов: Если конструкция Попытка ... Исключение написана некорректно или находится вне тела цикла, первая же ошибка преобразования текста (например, числа "5.13" или некорректного символа) может прервать обход массива или алгоритма.
  3. Разбиение строки по пробелам: Использование функции СтрРазделить() с неправильными параметрами может приводить к созданию пустых элементов массива, если между числами содержится несколько пробелов подряд или пробелы находятся в начале и конце строки.

Выясним, как написать устойчивый код, который корректно обработает все эти ситуации.

Способ 1. Использование функций СтрРазделить и Цел

Проанализируем базовый и наиболее наглядный алгоритм. Нам потребуется разделить исходную строку на массив подстрок по пробелу, привести каждую подстроку к числовому виду и проверить, равна ли целая часть числа самому числу.

Разберем алгоритм по шагам:

  1. Очистим исходную строку от лишних пробелов по краям с помощью СокрЛП().
  2. Заменим возможные разделители дробной части (запятые) на точки с помощью СтрЗаменить().
  3. Разобьем строку на массив элементов с помощью СтрРазделить(), передав третьим параметром значение Истина, чтобы проигнорировать пустые подстроки.
  4. В цикле попытаемся принести каждый элемент к типу Число.
  5. Сравним полученное значение с результатом работы функции Цел(). Если Цел(ТекущееЧисло) = ТекущееЧисло, значит перед нами целое число (включая записи вида 1.0).

Посмотрим на готовый пример функции в 1С:


Функция КоличествоЦелыхЧиселВСтроке(Знач ИсходнаяСтрока) Экспорт

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

КонецФункции

Протестируем данную функцию на примере строки из обращения пользователя:


ТестоваяСтрока = " 2 3 4 0.1 5.13 1,0 ";
Результат = КоличествоЦелыхЧиселВСтроке(ТестоваяСтрока);
Предупреждение("В строке " + Строка(Результат) + " целых чисел");

Данный код вернет результат 4 (будут учтены числа 2, 3, 4 и 1,0, а дробные 0.1 и 5.13 пропущены).

Способ 2. Проверка на целочисленность через оператор остатка от деления

Альтернативный способ проверки числа на целочисленность в 1С после успешного преобразования — использование математического оператора остатка от деления %.

Если число является целым, то остаток от его деления на 1 всегда равен нулю (ТекущееЧисло % 1 = 0). Это лаконичное условие заменяет вызов функции Цел().

Рассмотрим пример реализации:


Функция КоличествоЦелыхЧиселЧерезОстаток(Знач ИсходнаяСтрока) Экспорт

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

КонецФункции

Данная проверка работает одинаково корректно как для положительных чисел (10.0 % 1 = 0), так и для отрицательных целых чисел (-3.0 % 1 = 0).

Способ 3. Использование регулярных выражений (VBScript.RegExp)

Если исходный текст имеет большой объем или содержит множество разнородных символов (буквы, спецсимволы, переводы строк), постоянное провоцирование генерации исключений внутри блока Попытка ... Исключение может снижать производительность.

В таких случаях наилучшим решением является использование COM-объекта VBScript.RegExp. Регулярное выражение позволяет сразу найти все паттерны целых чисел в строке без разбивки на массив и без вызова функции Число().

Проанализируем регулярное выражение для этой задачи:

(?<=\s|^)-?\d+([.,]0+)?(?=\s|$)

Рассмотрим пример реализации на 1С:


Функция ПосчитатьЦелыеЧислаRegExp(Знач ИсходнаяСтрока) Экспорт

	Попытка
		RegExp = Новый COMОбъект("VBScript.RegExp");
	Исключение
		ЗаписьЖурналаРегистрации("Ошибка RegEx", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
		Возврат 0;
	КонецПопытки;
	
	RegExp.Global     = Истина;
	RegExp.IgnoreCase = Истина;
	RegExp.Multiline  = Истина;
	
	// Шаблон поиска целых чисел, в т.ч. с нулями в дробной части
	RegExp.Pattern = "(?<=^|\s)-?\d+([.,]0+)?(?=\s|$)";
	
	Совпадения = RegExp.Execute(ИсходнаяСтрока);
	
	Возврат Совпадения.Count;

КонецФункции

Этот подход работает мгновенно даже на очень больших текстах, игнорируя любые сторонние символы и не требуя предварительной подмены запятых на точки.

Сравнение подходов и рекомендации

Разберем, какой метод выбрать в зависимости от требований вашего проекта:

Главные правила при работе со строками чисел в 1С:

  1. Всегда выполняйте предварительную замену СтрЗаменить(Строка, ",", ".") перед передачей подстроки в функцию Число().
  2. При вызове СтрРазделить() всегда передавайте третий параметр как Истина, чтобы отсекать пустые подстроки при двойных пробелах.
  3. Помещайте блок Попытка ... Исключение строго внутри цикла обхода элементов, чтобы ошибка в одном элементе не прерывала обработку остальных данных.
← На главную