При интеграции 1С со сторонними веб-сервисами, форумами или API разработчики нередко сталкиваются с ситуацией, когда входящий ответ возвращается в поврежденном формате JSON. Штатный метод ПрочитатьJSON или функция JSON.parse в JavaScript при попытке разбора такого ответа завершаются критической ошибкой синтаксиса. Разберем подробно, почему это происходит и как правильно подготовить входящие данные к обработке.
Согласно спецификации RFC 8259 и стандарту ECMA-404, внутри строковых значений JSON допускается экранирование обратным слэшем строго определенного набора символов:
\"\\\/\b, \f, \n, \r, \t\uXXXXЕсли сервер при формировании ответа склеивает строки вручную или применяет избыточное экранирование спецсимволов HTML, в строке появляются конструкции вида \https, \<\/a\> или \:. Символ обратного слэша перед латинской буквой h или угловой скобкой является грубым нарушением формата. Встроенные парсеры платформы 1С (объект ЧтениеJSON) работают строго по стандарту и не имеют режима нестрогого чтения, поэтому вызывают исключение.
Простая замена всех обратных слэшей с помощью СтрЗаменить(СтрокаJSON, "\", "") не подходит, так как она уничтожает полезные и обязательные управляющие конструкции, такие как экранированные кавычки \" и переносы строк \r\n. Рассмотрим надежные варианты решения этой задачи.
Проанализируем структуру строки. Нам необходимо найти все символы \, за которыми не следуют допустимые по спецификации символы, и удалить их либо продублировать. В операционной системе Windows для этого удобно использовать системный объект VBScript.RegExp.
Посмотрим на пример функции, которая находит ошибочные слэши с помощью регулярного выражения с отрицательным опережающим просмотром:
Функция ИсправитьСтрокуJSON(Знач ИсходныйJSON) Экспорт
РегЭксп = Новый COMОбъект("VBScript.RegExp");
РегЭксп.Global = Истина;
РегЭксп.IgnoreCase = Истина;
РегЭксп.Multiline = Истина;
// Ищем обратный слэш, после которого нет кавычки, слэша, управляющих букв b,f,n,r,t или uXXXX
РегЭксп.Pattern = "\\(?![/""\\bfnrt]|u[0-9a-fA-F]{4})";
// Удаляем ошибочные слэши из строки
ИсправленныйJSON = РегЭксп.Replace(ИсходныйJSON, "");
Возврат ИсправленныйJSON;
КонецФункции
После предварительной очистки нормализованный текст передается в стандартный механизм чтения платформы:
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(ИсправленныйJSON);
Результат = ПрочитатьJSON(Чтение);
Чтение.Закрыть();
Если код выполняется на сервере под управлением Linux, использование COM-объектов невозможно. В таком случае разберем по шагам алгоритм собственного парсера-нормализатора на встроенном языке 1С без сторонних зависимостей.
Алгоритм отслеживает нахождение указателя внутри кавычек и проверяет следующий символ после каждого слэша:
Функция НормализоватьJSON(Знач ТекстJSON) Экспорт
РазрешенныеСимволы = """/\bfnrtu";
Результат = "";
ВнутриСтроки = Ложь;
Длина = СтрДлина(ТекстJSON);
Индекс = 1;
Пока Индекс <= Длина Цикл
Символ = Сред(ТекстJSON, Индекс, 1);
Если Символ = """" Тогда
// Проверяем, не экранирована ли кавычка
КоличествоСлэшейПеред = 0;
ПозицияПроверки = Индекс - 1;
Пока ПозицияПроверки >= 1 И Сред(ТекстJSON, ПозицияПроверки, 1) = "\" Цикл
КоличествоСлэшейПеред = КоличествоСлэшейПеред + 1;
ПозицияПроверки = ПозицияПроверки - 1;
КонецЦикла;
// Если перед кавычкой четное число слэшей — это граница строки
Если (КоличествоСлэшейПеред % 2) = 0 Тогда
ВнутриСтроки = Не ВнутриСтроки;
КонецЕсли;
Результат = Результат + Символ;
Индекс = Индекс + 1;
ИначеЕсли Символ = "\" И ВнутриСтроки Тогда
Если Индекс < Длина Тогда
СледующийСимвол = НРег(Сред(ТекстJSON, Индекс + 1, 1));
Если Найти(РазрешенныеСимволы, СледующийСимвол) > 0 Тогда
// Валидная escape-последовательность — оставляем слэш
Результат = Результат + Символ;
Иначе
// Ошибочный слэш — пропускаем его
КонецЕсли;
КонецЕсли;
Индекс = Индекс + 1;
Иначе
Результат = Результат + Символ;
Индекс = Индекс + 1;
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
Если задача решается во внешней веб-обработке или на клиенте JavaScript, обратите внимание на разницу в поведении парсеров. Метод JSON.parse() завершается с ошибкой SyntaxError: Unexpected token при встрече таких последовательностей. Однако сам интерпретатор JavaScript при вычислении обычных строковых литералов просто игнорирует невалидные слэши (превращая \https в https). Для разбора подобных нестандартных данных в веб-среде применяют предварительную регулярную замену методом str.replace(/\\(?![/"\\bfnrt]|u[0-9a-fA-F]{4})/g, "") или специализированные библиотеки, такие как JSON5.