Как прочитать невалидный JSON с некорректно экранированными символами в 1С?

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

При интеграции 1С со сторонними веб-сервисами, форумами или API разработчики нередко сталкиваются с ситуацией, когда входящий ответ возвращается в поврежденном формате JSON. Штатный метод ПрочитатьJSON или функция JSON.parse в JavaScript при попытке разбора такого ответа завершаются критической ошибкой синтаксиса. Разберем подробно, почему это происходит и как правильно подготовить входящие данные к обработке.

Выясним причину ошибки

Согласно спецификации RFC 8259 и стандарту ECMA-404, внутри строковых значений JSON допускается экранирование обратным слэшем строго определенного набора символов:

  1. Двойная кавычка: \"
  2. Обратный слэш: \\
  3. Прямой слэш: \/
  4. Служебные управляющие символы: \b, \f, \n, \r, \t
  5. Шестнадцатеричный код символа Unicode: \uXXXX

Если сервер при формировании ответа склеивает строки вручную или применяет избыточное экранирование спецсимволов HTML, в строке появляются конструкции вида \https, \<\/a\> или \:. Символ обратного слэша перед латинской буквой h или угловой скобкой является грубым нарушением формата. Встроенные парсеры платформы 1С (объект ЧтениеJSON) работают строго по стандарту и не имеют режима нестрогого чтения, поэтому вызывают исключение.

Простая замена всех обратных слэшей с помощью СтрЗаменить(СтрокаJSON, "\", "") не подходит, так как она уничтожает полезные и обязательные управляющие конструкции, такие как экранированные кавычки \" и переносы строк \r\n. Рассмотрим надежные варианты решения этой задачи.

Способ 1. Очистка невалидных слэшей регулярным выражением через COM-объект

Проанализируем структуру строки. Нам необходимо найти все символы \, за которыми не следуют допустимые по спецификации символы, и удалить их либо продублировать. В операционной системе 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(Чтение);
Чтение.Закрыть();

Способ 2. Кроссплатформенный посимвольный разбор строки

Если код выполняется на сервере под управлением 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

Если задача решается во внешней веб-обработке или на клиенте JavaScript, обратите внимание на разницу в поведении парсеров. Метод JSON.parse() завершается с ошибкой SyntaxError: Unexpected token при встрече таких последовательностей. Однако сам интерпретатор JavaScript при вычислении обычных строковых литералов просто игнорирует невалидные слэши (превращая \https в https). Для разбора подобных нестандартных данных в веб-среде применяют предварительную регулярную замену методом str.replace(/\\(?![/"\\bfnrt]|u[0-9a-fA-F]{4})/g, "") или специализированные библиотеки, такие как JSON5.

← На главную