Строка в число в 1С 8.3: функции, подготовка данных и защита от исключений

· 10 мин

Содержание

Чтобы преобразовать строку в число в 1С, вызовите встроенную функцию Число(): Сумма = Число("1250.75");. Если в строке есть что-то кроме цифр, знака минус и точки, платформа выбросит исключение, поэтому строку из внешних данных сначала чистят, а вызов оборачивают в Попытка.

Типичная ситуация: программист пишет загрузку прайса из Excel, на тестовом файле всё работает, а у бухгалтера обработка падает на сотой строке. В ячейке оказалось 1 250,75 с неразрывным пробелом или вообще слово «договорная». Ниже разобрано, как приводить строки к числу так, чтобы такие данные не роняли код.

Всё описанное относится к платформе 1С:Предприятие 8.3 и не зависит от конфигурации: код одинаково работает в БП 3.0, ЗУП 3.1, УТ 11 и в собственных разработках.

Функция Число(): базовое преобразование строки к числу

Число() — основной инструмент. Она принимает значение и возвращает его в типе Число.

Количество = Число("15");        // 15
Цена = Число("1250.75");         // 1250.75
Остаток = Число("-30.5");        // -30.5
Код = Число("007");              // 7, ведущие нули отбрасываются
Флаг = Число(Истина);            // 1, Ложь даёт 0

Что функция принимает без проблем:

  • ✅ цифры подряд, в том числе с ведущими нулями;
  • ✅ знак минус в начале;
  • ✅ точку как разделитель дробной части;
  • ✅ значения типа Булево (1 и 0).

Что приводит к исключению:

  • ❌ пустая строка "";
  • ❌ пробелы внутри числа: "1 250";
  • ❌ буквы и символы валют: "150 руб.", "12%";
  • ❌ две точки или текст вроде "н/д", "-".

Надёжный разделитель дробной части для Число() — точка. Не стройте логику на том, что запятая где-то сработала: нормализуйте строку к точке до вызова, и код будет вести себя одинаково на любой базе.

Округление после преобразования

Число() возвращает значение с той точностью, что была в строке. Если реквизит документа хранит 2 знака после запятой, округлите явно:

Цена = Окр(Число("12.3456"), 2);          // 12.35
ЦелаяЧасть = Цел(Число("12.99"));         // 12

При записи в реквизит с меньшей точностью платформа сама подрежет значение под квалификаторы типа. Явное Окр() нужно, чтобы промежуточные расчёты шли с тем же числом, которое потом окажется в базе.

Способы приведения типа строки к числу: сравнение

Кроме Число() в языке есть ещё три рабочих варианта. Они различаются тем, что происходит с «плохой» строкой.

СпособЧто вернёт на «abc»Когда братьРиск
Число(Строка)исключениеданные заведомо корректные или есть Попыткападение кода без обработки
Новый ОписаниеТипов("Число").ПривестиЗначение(Строка)0нужно «тихое» приведение без исключенийошибка данных маскируется нулём
XMLЗначение(Тип("Число"), Строка)исключениеобмены, XML, строго формализованные данныене принимает запятую и пробелы
СтроковыеФункцииКлиентСервер.СтрокаВЧисло(Строка)Неопределенотиповые конфигурации на БСПдоступна только там, где внедрена БСП

ОписаниеТипов и квалификаторы

Описание типов удобно, когда сразу нужна определённая разрядность:

ТипСумма = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2));
Сумма = ТипСумма.ПривестиЗначение("1250.756");   // 1250.76
Мусор = ТипСумма.ПривестиЗначение("abc");        // 0

Обратная сторона видна во второй строке. Ноль вместо ошибки удобен в отчёте, но опасен при загрузке: строка «договорная» молча превратится в цену 0, и документ проведётся.

Если ноль — допустимое значение реквизита, не используйте ПривестиЗначение для проверки корректности данных. Отличить «в строке был 0» от «в строке был мусор» по результату нельзя.

XMLЗначение для обменов

XMLЗначение() разбирает строку по правилам XML-схемы: только точка, без пробелов и разделителей разрядов. Это строгий режим, и для обменов он правильный. Если контрагент прислал 1 250,00, лучше узнать об этом сразу, чем записать искажённую сумму.

Функция из БСП

В конфигурациях на Библиотеке стандартных подсистем есть СтроковыеФункцииКлиентСервер.СтрокаВЧисло(). Она возвращает Неопределено, если строка не является числом. Проверка становится простой:

Значение = СтроковыеФункцииКлиентСервер.СтрокаВЧисло(ТекстЯчейки);
Если Значение = Неопределено Тогда
	// сообщить пользователю, пропустить строку
КонецЕсли;

В своей конфигурации без БСП этой функции нет. Там пишут аналог самостоятельно, пример ниже.

Ошибка «Преобразование значения к типу Число не может быть выполнено»

Именно этот текст выдаёт платформа, когда Число() получает неподходящую строку. Без обработки ошибка прерывает выполнение процедуры, а при загрузке — всю загрузку на середине.

Перехват через Попытка … Исключение

Минимальная защита:

Попытка
	Цена = Число(ТекстЦены);
Исключение
	Цена = 0;
	Сообщить("Строка " + Формат(НомерСтроки, "ЧГ=0")
		+ ": не удалось прочитать цену «" + ТекстЦены + "»");
КонецПопытки;

Обратите внимание на Формат(НомерСтроки, "ЧГ=0"): без него номер 1250 при склейке со строкой превратится в «1 250».

Для журнала регистрации берите подробности ошибки:

Исключение
	Инфо = ИнформацияОбОшибке();
	ЗаписьЖурналаРегистрации("Загрузка прайса", УровеньЖурналаРегистрации.Ошибка,,,
		ПодробноеПредставлениеОшибки(Инфо));
КонецПопытки;

Универсальная функция без исключений наружу

Чтобы не повторять Попытка в каждом месте, вынесите преобразование в общий модуль:

Функция СтрокаВЧислоБезопасно(Знач Текст, ЗначениеПоУмолчанию = 0) Экспорт

	Если ТипЗнч(Текст) = Тип("Число") Тогда
		Возврат Текст;
	КонецЕсли;

	Текст = СокрЛП(Строка(Текст));
	Текст = СтрЗаменить(Текст, Символы.НПП, "");
	Текст = СтрЗаменить(Текст, " ", "");
	Текст = СтрЗаменить(Текст, ",", ".");

	Если ПустаяСтрока(Текст) Тогда
		Возврат ЗначениеПоУмолчанию;
	КонецЕсли;

	Попытка
		Возврат Число(Текст);
	Исключение
		Возврат ЗначениеПоУмолчанию;
	КонецПопытки;

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

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

Диагностика: выберите симптом

Запятая, пробелы и разделители разрядов в строке

Большинство сбоев при приведении к числу дают не буквы, а форматирование. Человек видит «1 250,75», а для Число() это три лишних символа.

Порядок очистки строки:

  1. СокрЛП() — убрать пробелы по краям, в том числе перевод строки из ячейки.
  2. Удалить неразрывный пробел Символы.НПП. Именно его ставят Excel и сама 1С при выводе чисел с разделителем групп.
  3. Удалить обычные пробелы внутри числа.
  4. Заменить запятую на точку.
  5. При необходимости убрать валюту и проценты: СтрЗаменить(Текст, "руб.", ""), СтрЗаменить(Текст, "%", "").

Когда запятая — разделитель разрядов

В англоязычных выгрузках число выглядит как 1,250.75. Простая замена запятой на точку даст 1.250.75, и Число() выдаст ошибку. Хуже, если строка 1,250 без дробной части: после замены получится 1.25 — без всякой ошибки.

Правило простое: сначала определите формат источника, потом чистите.

ИсточникПримерЧто сделать
Русская локаль Excel, выгрузки 1С1 250,75удалить пробелы и Символы.НПП, запятую заменить на точку
Англоязычные системы, банковские API1,250.75удалить запятые, точку не трогать
XML, JSON, обмены 1С1250.75ничего, строка уже в нужном формате
Европейский формат1.250,75удалить точки, затем запятую заменить на точку

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

Отличить число от не-числа заранее

Иногда нужно не преобразовать, а проверить: в колонке «Артикул» число или код вида «А-15». Помогает проверка по символам:

Функция ЭтоЧисловаяСтрока(Знач Текст) Экспорт

	Текст = СокрЛП(Текст);
	БылаТочка = Ложь;
	БылаЦифра = Ложь;

	Для Н = 1 По СтрДлина(Текст) Цикл
		Символ = Сред(Текст, Н, 1);
		Если Символ = "-" И Н = 1 Тогда
			Продолжить;
		ИначеЕсли Символ = "." И Не БылаТочка Тогда
			БылаТочка = Истина;
		ИначеЕсли СтрНайти("0123456789", Символ) > 0 Тогда
			БылаЦифра = Истина;
		Иначе
			Возврат Ложь;
		КонецЕсли;
	КонецЦикла;

	Возврат БылаЦифра;

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

Флаг БылаЦифра отсекает строки "-" и ".", на которых Число() всё равно упадёт.

Если число нужно только для сравнения или сортировки кодов вроде «000125», подумайте, нужно ли преобразование вообще. Строки одинаковой длины с ведущими нулями сортируются как числа.

Клиент, сервер, внешнее соединение и Excel: где важно

Сама функция Число() доступна везде: на клиенте, на сервере, во внешнем соединении и в мобильном приложении. Различается не синтаксис, а то, откуда приходит строка.

Поле формы

Если реквизит формы имеет тип Число, преобразовывать ничего не нужно. Поле само не даст ввести буквы, а в обработчик ПриИзменении придёт уже число.

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

Загрузка из Excel через табличный документ

При чтении файла в ТабличныйДокумент у области есть свойство Текст. Оно отдаёт то, что видно в ячейке, с форматированием Excel: пробелами между разрядами, запятой, округлением до видимых знаков.

Отсюда две ловушки:

  • 📊 ячейка с форматом «2 знака» отдаст "12,35", хотя в файле лежит 12,3456;
  • 🔤 разделитель разрядов придёт неразрывным пробелом, который на экране не отличить от обычного.

Поэтому для Excel чистка строки по списку из предыдущего раздела обязательна. А если важна полная точность, попросите пользователя убрать форматирование колонки до загрузки.

Внешнее соединение и COM

При работе через COM (из Excel, из другой базы 1С) значения часто приходят уже числами. Перед вызовом Число() проверьте тип через ТипЗнч(), как сделано в универсальной функции выше. Лишнее преобразование числа в строку и обратно может внести ошибку из-за форматирования.

Язык запросов

В языке запросов 1С нет функции, приводящей строку к числу. Конструкция ВЫРАЗИТЬ для пары «строка → число» не работает. Решение: выбрать строку запросом, а преобразовать уже в коде, при обходе выборки или таблицы значений.

Обратная задача: число в строку через Формат()

Формат() не превращает строку в число, но без него не обойтись в обратную сторону. Ошибки преобразования часто рождаются именно здесь: код сначала выводит число в строку с разделителями, а потом пытается прочитать его обратно.

Текст1 = Строка(1250.75);                       // "1 250,75" — с НПП, зависит от локали
Текст2 = Формат(1250.75, "ЧГ=0");               // "1250,75"
Текст3 = Формат(1250.75, "ЧРД=.; ЧГ=0");        // "1250.75" — читается Число() обратно
Текст4 = Формат(0, "ЧН=0");                     // "0" вместо пустой строки

Основные параметры форматной строки для чисел:

ПараметрЧто делаетПример
ЧГ=0отключает разделение на группы разрядов"1250" вместо "1 250"
ЧРД=.задаёт разделитель дробной части"1250.75"
ЧДЦ=2число знаков после запятой"1250.70"
ЧН=0что выводить для нулябез него ноль даёт пустую строку

Для передачи числа в другую систему всегда указывайте ЧРД и ЧГ явно. Тогда строка не зависит от локали сеанса и одинаково читается на любом сервере. Для XML вместо Формат() используйте XMLСтрока().

Скорость при массовом преобразовании строк в числа

На десятке значений способ не важен. На загрузке в 100 000 строк разница становится заметной.

Что ускоряет обработку:

  • ⚡ Проверка до исключения. Обработка исключения дороже обычного ветвления. Если в колонке много пустых ячеек и текста, сначала отсекайте их ПустаяСтрока() или функцией ЭтоЧисловаяСтрока(), а Попытка оставьте для редких случаев.
  • 🖥️ Преобразование на сервере. Не вызывайте серверную функцию для каждой строки с клиента. Передайте на сервер весь массив или адрес временного хранилища и преобразуйте там одним проходом.
  • 📦 Колонка нужного типа. Создавайте колонку таблицы значений с описанием типа Число. Тогда при заполнении сразу видно, где значение не легло, а сортировка и итоги работают без повторных преобразований.
  • 🔁 Один объект ОписаниеТипов. Если используете ПривестиЗначение, создайте описание типов один раз до цикла, а не на каждой итерации.
ТипЧисло = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2));
Для Каждого СтрокаДанных Из ДанныеФайла Цикл
	СтрокаДанных.Сумма = ТипЧисло.ПривестиЗначение(СтрокаДанных.СуммаТекст);
КонецЦикла;

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

Частые вопросы о преобразовании строки к числу

Можно ли преобразовать строку в число без Попытки?
Да: через ОписаниеТипов("Число").ПривестиЗначение() (вернёт 0) или функцию БСП СтрокаВЧисло() (вернёт Неопределено). Либо заранее проверить строку посимвольно.
Почему Число(Строка(Сумма)) иногда падает?
Строка() выводит число по локали сеанса, с неразрывным пробелом между разрядами и запятой. Для обратного чтения формируйте строку через Формат(Сумма, "ЧРД=.; ЧГ=0").
Как получить из строки только цифры, например из «ИНН: 7701234567»?
Пройдите строку посимвольно и оставьте символы, которые есть в «0123456789». Для ИНН, КПП и счетов результат храните строкой: при переводе в число теряются ведущие нули.
Сколько знаков может быть в числе 1С?
Тип Число хранит до 38 значащих цифр. Строку длиннее лучше не преобразовывать: банковские счета и коды держите в строковом типе.
Как преобразовать строку в число в СКД?
Преобразование делайте до компоновки: в коде, наборе данных-объекте или вычисляемом поле, которое получает уже готовое число. В тексте запроса набора данных строку к числу привести нельзя.