Mazmunga o'tish
Tez Base

Число в строку в 1С: неразрывный пробел в ключах и как его вычистить

· Chop etilgan:

Интеграции и обмены

Загрузка отрабатывает, в журнале пусто, а сопоставленных записей ноль или заметно меньше, чем должно быть. Если ключ сопоставления собирается из числа через Строка(), первым делом смотрите на символ с кодом 160. Это неразрывный пробел, и 1С вставляет его сама, когда показывает число человеку: Строка(123456) возвращает 123 456, семь символов вместо шести.

Ниже справочник по тому, как платформа превращает число в строку, запросы и код для поиска испорченных значений, правильная замена Строка() с одной неочевидной ловушкой и порядок правки. Все фрагменты встроенного языка прогнаны 27.09.2026 на платформе 8.3.27.1606.

Что делает платформа с числом

Прогон на пяти значениях. В колонке кодов видно, где появляется символ 160:

ЧислоСтрока(Ч)ДлинаКоды символовФормат(Ч, "ЧГ=0")Формат(Ч, "ЧН=0; ЧГ=0")
00148пустая строка0
999999357 57 57999999
10001 000549 160 48 48 4810001000
123456123 456749 50 51 160 52 53 54123456123456
12345671 234 567949 160 50 51 52 160 53 54 5512345671234567

Из таблицы читаются три вещи, на которых дальше строится всё остальное.

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

Прирост длины зависит от разрядности. У шестизначного числа разделитель один, у семизначного два. Проверка “длина больше ожидаемой на единицу” найдёт одни и пропустит другие.

Формат с одним ЧГ=0 превращает ноль в пустую строку. Это вторая ловушка, и она поджидает ровно тех, кто взялся чинить первую. Если в поле может оказаться 0, нужен ЧН=0 в той же форматной строке, иначе ключ “0” молча станет пустым и совпадёт со всеми незаполненными значениями сразу.

Для строк Формат безопасен: Формат("АБ 12", "ЧГ=0") вернул АБ 12 без изменений. Поэтому замена работает и на смешанных полях, где рядом лежат числовые коды и буквенные артикулы.

Почему символ не находится обычным поиском

Отладчик показывает пробел. Редактор показывает пробел. А условие с обычным пробелом ничего не находит:

Строка1000 = Строка(1000);
СтрНайти(Строка1000, " ");              // 0, обычного пробела (код 32) там нет
СтрНайти(Строка1000, Символы.НПП);      // 2, неразрывный на второй позиции
Строка(123456) = "123 456";             // Ложь, в литерале набран обычный пробел

Символы.НПП возвращает символ с кодом 160, этим им удобно пользоваться в коде и в параметрах запроса. СокрЛП() неразрывный пробел по краям строки убирает, мы проверили: из строки “НПП + 12 + НПП” остались два символа. Но разделитель разрядов стоит в середине, и туда СокрЛП() не дотягивается.

Как найти испорченные ключи у себя

Шаг 1. Распределение длин

Начинать стоит с данных. Запрос раскладывает значения по длине и сразу считает, сколько в каждой группе содержат символ 160:

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|	ДЛИНАСТРОКИ(Т.Артикул) КАК Длина,
|	КОЛИЧЕСТВО(*) КАК Всего,
|	СУММА(ВЫБОР
|			КОГДА Т.Артикул ПОДОБНО &Шаблон
|				ТОГДА 1
|			ИНАЧЕ 0
|		КОНЕЦ) КАК СНеразрывнымПробелом
|ИЗ
|	Справочник.Номенклатура КАК Т
|
|СГРУППИРОВАТЬ ПО
|	ДЛИНАСТРОКИ(Т.Артикул)
|
|УПОРЯДОЧИТЬ ПО
|	Длина";
Запрос.УстановитьПараметр("Шаблон", "%" + Символы.НПП + "%");
Результат = Запрос.Выполнить().Выгрузить();

Справочник и реквизит здесь для примера, подставьте свою таблицу сопоставления. Ожидаемая длина видна сразу, рядом окажется группа длиннее, и в ней ненулевой счётчик в последней колонке.

Шаг 2. Проверка по кодам символов

Для точечной проверки значения, которое должно состоять только из цифр:

Функция ТолькоЦифры(Значение)

	Если СтрДлина(Значение) = 0 Тогда
		Возврат Ложь;
	КонецЕсли;

	Для Позиция = 1 По СтрДлина(Значение) Цикл
		Код = КодСимвола(Значение, Позиция);
		Если Код < 48 Или Код > 57 Тогда
			Возврат Ложь;
		КонецЕсли;
	КонецЦикла;

	Возврат Истина;

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

На прогоне функция вернула Ложь для Строка(123456) и для AB 12, Истина для Формат(123456, "ЧН=0; ЧГ=0"). Проверка по кодам дороже поиска подстроки, зато не зависит ни от шрифта, ни от редактора, и не путает символ 160 с обычным пробелом.

Отбор “содержит пробел” врёт в обе стороны: не находит символ 160 там, где он есть, и находит законный пробел внутри буквенного артикула. Поэтому проверяем по кодам, а поиск пробела оставляем для глаз.

Шаг 3. Места в коде

Глобальный поиск по конфигурации: Строка( рядом со словами ключ, код, артикул, идентификатор. Интересуют все места, где из числа собирается значение для сравнения, имени файла, параметра запроса к внешней системе. Обычно их несколько: загрузка, выгрузка, отчёт сверки, ручное заполнение. Если ключи собирают внешние обработки загрузки, их код можно разобрать анализатором кода внешних обработок, он работает без отправки кода наружу.

Шаги 1 и 2 отвечают на вопрос “есть ли у меня такое” без отладчика и без чтения модулей. Шаг 3 нужен, когда ответ “да”.

Чем заменить Строка()

Для любого значения, которое уйдёт в ключ, сравнение, имя файла или внешнюю систему:

// Было: форматирование для человека, с разделителем разрядов
Ключ = Строка(Код);

// Стало: без разделителя, ноль остаётся нулём
Ключ = Формат(Код, "ЧН=0; ЧГ=0");

Для дробных чисел тот же вопрос встаёт с десятичным разделителем: Строка(1234.5) на прогоне дала 1 234,5, с запятой. Если число с дробной частью уходит во внешнюю систему, разделитель дробной части тоже задаётся в форматной строке явно, под то, что ждёт приёмник.

Две правки, которые напрашиваются и вредят:

  • Вычистить из значений все пробелы. В артикулах поставщиков пробел бывает значимым. Массовая зачистка даст новые несовпадения, редкие и потому незаметные. К тому же ключ из числа можно пересобрать заново, а стёртый пробел внутри чужого артикула восстановить неоткуда. Если чистить накопленные данные, то одним символом: СтрЗаменить(Значение, Символы.НПП, ""), и только в полях, которые по смыслу числовые.
  • Проверять результат по длине. У семизначных разделителей два, проверка “на единицу длиннее” пропустит их и отчитается, что всё исправлено.

Почему это годами не всплывает

Самое неприятное свойство дефекта: он может жить с первого дня внедрения и не давать никаких последствий. Если обе стороны сопоставления собирают ключ одним и тем же кодом, слева получается 123 456 и справа 123 456. Строки равны, связь находится, платформа ведёт себя совершенно корректно. На прогоне Строка(123456) = Строка(123456) вернуло Истина, а Строка(123456) = Формат(123456, "ЧГ=0") вернуло Ложь.

Совпадение ломается в тот день, когда одна сторона начинает формироваться иначе. Подключили новый источник, загрузили данные из файла, кто-то переписал один из двух модулей и сделал ключ правильно. Для дежурного это выглядит как “сломалось после новой интеграции”, хотя новая интеграция единственная, кто собрал ключ как надо.

Отсюда практическое следствие для проверок: сверка “наши ключи против их ключей” такую порчу не видит по построению, обе половины испорчены одинаково. Ловит её только проверка каждого значения против ожидаемого формата, то есть функция из шага 2 или запрос из шага 1.

Порядок правки, чтобы не порвать работающее

Из симметричной порчи вытекает неприятное: там, где обе стороны сейчас испорчены одинаково, сопоставление работает. Починив одну сторону, вы эти связи разорвёте.

  1. Посчитать обе стороны. Сколько значений с символом 160 в источнике, сколько в таблице сопоставления.
  2. Посчитать пересечение. Сколько связей сейчас держится на совпадении двух испорченных значений. Ровно это количество сломается при односторонней правке.
  3. Найти все места сборки ключа по шагу 3. Наполовину исправленная система хуже исходной: часть связей рвётся, и объяснение неочевидно.
  4. Править код и приводить накопленные данные одним заходом, обе стороны сразу, с заменой Строка() на Формат(..., "ЧН=0; ЧГ=0") и разовой заменой Символы.НПП в числовых полях.
  5. Повторить запрос из шага 1. В группе ожидаемой длины должны оказаться все числовые значения, счётчик символа 160 должен стать нулём.

Пересечение из пункта 2 считайте до выкатки: узнавать его размер от пользователей дороже.

Как это выглядело в живой таблице

В разборе, с которого началась эта статья, в таблице сопоставления лежало 1 449 ключей. Испорченными оказались 1 370, это 94,55 процента: ключ ожидался шестью цифрами подряд, а в базе лежали семь символов с разделителем между третьей и четвёртой цифрой. Сопоставление при этом отрабатывало без ошибок и возвращало пустоту.

Уцелели 79 ключей, 5,45 процента. По механизму это должны быть числа меньше тысячи или буквенно-цифровые значения, которые Строка() не трогает. Запросом по длинам это в том разборе не проверяли, так что считайте это предсказанием: найдётся среди уцелевших четырёхзначное число, и механизм описан неполно. Замера “после правки” там тоже нет, риск разрыва связей выведен из механизма. Замера под ним нет.

Короткая версия этой истории, с акцентом на то, почему порча жила годами, вышла на Инфостарте.

Этот же символ при переезде на PostgreSQL

У символа 160 есть и обратная сторона. Здесь он делает одинаковые на вид строки разными. При переносе базы на PostgreSQL он делает разные строки одинаковыми: сравнение через библиотеку ICU считает неразрывный пробел равным обычному, и уникальный индекс перестаёт строиться. Этот случай целиком разобран в статье о миграции 1С на PostgreSQL, а значения, которые схлопнутся при переезде, заранее показывает проверка базы перед миграцией на PostgreSQL. Сколько подобного мусора накопилось в справочниках вообще, отвечает чек-ап чистоты базы.

Если сопоставление в загрузке или обмене теряет записи и непонятно почему, разберём ключи и правила сопоставления в рамках настройки обмена данными 1С: найдём все места сборки, посчитаем, что сломается при правке, и выкатим исправление обеими сторонами сразу.

Buni siz uchun hal qila olaman

1C ni istalgan tizim bilan bogʻlaymiz: boshqa 1C bazalari, saytlar, CRM, banklar, davlat tizimlari. "Uzilib qoladigan" va navbat toʻplaydigan almashinuvlarni tuzatamiz.

Narxi
450 000 ₸ danalmashinuv quyi tizimini toʻliq joriy etish; soliqlarsiz, alohida vazifalar - arzonroq

Yozishga erta? O'zingiz o'lchang

Двадцать чужих обработок в справочнике дополнительных

Ishlov berishni ochish

INFOSTART TECH EVENT 2026: конференция для 1с-специалистов. если собираетесь, регистрируйтесь по нашей ссылке. Регистрация →

Buni ham o'qing

Регламентное задание 1С обрабатывает не все записи и не выдаёт ошибок: проверка и исправление цикла

Задание прошло, журнал чистый, счётчик обработанных сходится, а утром часть записей по-прежнему ждёт обработки. Частая причина: постраничный обход со смещением по набору, который сам сжимается от обработки. Как подтвердить это холостым прогоном, сколько теряется при разных размерах страницы, как переписать цикл и чем платить за исправление.

Проверка параметров HTTP-сервиса 1С: белый список, ошибка 400 и явные умолчания

Платформа не отвергает параметры, которых обработчик не ждёт, и опечатка в имени превращается в другой запрос с кодом 200. Разбираем четыре правила строгого входа для HTTP-сервиса на встроенном языке: белый список имён, 400 с понятным текстом, видимое умолчание и возраст данных в ответе. Код на BSL и проверка за минуту.

Расхождение остатков 1С и WMS: как устроить сверку, которой можно верить

Когда сверка 1С и WMS регулярно находит расхождения, а склад их не подтверждает, первым делом проверяют саму сверку. Шесть требований к ней таблицей, порядок проверки по шагам и цифры из разбора робота, который за 60 дней сам создал 62,7% оборота технического склада.