Подтвердить что ты не робот

Невозможно проанализировать TAB в файлах JSON

Я запускаю проблему синтаксического анализа при загрузке JSON файлов, которые, как представляется, имеют символ TAB.

Когда я перехожу на http://jsonlint.com/, и я ввожу часть с символом TAB:

{
    "My_String": "Foo bar.  Bar foo."
}

Валидатор жалуется на:

Parse error on line 2:
{    "My_String": "Foo bar. Bar foo."
------------------^
Expecting 'STRING', 'NUMBER', 'NULL', 'TRUE', 'FALSE', '{', '['

Это буквально копия/вставка оскорбительного текста JSON.

Я попытался загрузить этот файл с json и simplejson без успеха. Как я могу загрузить это правильно? Должен ли я просто предварительно обработать файл и заменить TAB на \t или пробелом? Или есть что-то, что мне здесь не хватает?

Обновление:

Здесь также есть проблемный пример в simplejson:

foo = '{"My_string": "Foo bar.\t Bar foo."}'
simplejson.loads(foo)

JSONDecodeError: Invalid control character '\t' at: line 1 column 24 (char 23)
4b9b3361

Ответ 1

Из стандарта JSON:

Незначительные пробелы разрешены до или после любого токена. пробельные символы: табличная таблица символов (U + 0009), строка (U + 000A), возврат каретки (U + 000D) и пробел (U + 0020). Пробел не допускается в пределах любого токена, за исключением того, что в строки.

Это означает, что символ буквальной вкладки не допускается внутри строки JSON. Вам нужно избегать его как \t (в .json файле):

{"My_string": "Foo bar.\t Bar foo."}

Кроме того, если текст json предоставляется внутри строкового литерала Python, вам нужно дважды выйти на вкладку:

foo = '{"My_string": "Foo bar.\\t Bar foo."}' # in a Python source

Или используйте строковый литерал Python:

foo = r'{"My_string": "Foo bar.\t Bar foo."}' # in a Python source

Ответ 2

Вкладки являются законными как ограничение пробелов вне значений, но не внутри строк. Вместо этого используйте \t.

РЕДАКТИРОВАТЬ: Основываясь на ваших комментариях, я вижу некоторую путаницу в том, что такое вкладка. символ табуляции - это обычный символ, например "a" или "5" или ".". или любой другой символ, который вы вводите, нажав клавишу на клавиатуре. Он занимает один байт, числовое значение которого равно 9. Отсутствуют обратные косые черты или нижний регистр.

Что помещает вкладку в другую категорию из 'a' или '5' или '.' это тот факт, что вы, как человек, использующий ваши глазные яблоки, вообще не можете смотреть на отображение текста и идентифицировать или подсчитывать символы табуляции. Визуально последовательность вкладок идентична последовательности (обычно большего, но все еще визуально неопределенного числа) пробелов.

Чтобы однозначно представить вкладки внутри текста, предназначенные для компьютерной обработки, у нас есть различные синтаксические методы, чтобы сказать "Эй, какое-то программное обеспечение! Замените этот мусор символом табуляции позже, ОК?".

В истории языков программирования были два основных подхода; если вы вернетесь в 1950-е годы, вы получите оба подхода, существующие бок о бок, по одному на каждом из двух самых старых языков высокого уровня. Lisp назвал символьные литералы типа #\Tab; они были преобразованы, как только они были прочитаны из источника программы. У Fortran была только функция CHAR, которая вызывалась во время выполнения и возвращала символ, номер которого соответствовал аргументу: CHAR(9) вернул вкладку. (Конечно, если бы это было действительно CHAR(9), а не CHAR( некоторое выражение, которое работает до 9 ), оптимизирующий компилятор может заметить это и заменить вызов функции на вкладку во время компиляции, возвращая нас обратно в другом лагере.)

В общем, с обоими типами решений, если вы хотите придерживаться специального символа внутри большей строки, вам нужно было сделать конкатенацию самостоятельно; например, хакерский хакинг BASIC в 80 может написать что-то вроде этого:

10 PRINT "This is a tab ->"; CHR$(9); "<- That was a tab"

Но некоторые языки, в первую очередь семья, начавшаяся с языка B, ввели возможность включать эти символы непосредственно в строковый литерал:

printf("This is a tab -> *t <- That was a tab");

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

В любом случае, целый ряд языков, включая как Python, так и Javascript, заимствовал или унаследовал соглашения C здесь. Таким образом, на обоих языках два выражения "\t" и '\t' приводят к односимвольной строке, где этот один символ является вкладкой.

JSON основан на синтаксисе Javascript, но он допускает только ограниченное подмножество. Например, строки должны быть заключены в двойные кавычки (") вместо одиночных ('), а внутри нее не допускаются литеральные вкладки.

Это означает, что эта строка Python из вашего обновления:

foo = '{"My_string": "Foo bar.\t Bar foo."}'

недействителен JSON. Интерпретатор Python превращает последовательность \t в фактический символ табуляции, как только он читает строку - задолго до того, как процессор JSON когда-либо ее увидит.

Вы можете сказать Python поставить литерал \t в строке вместо символа табуляции, удвоив обратную косую черту:

foo = '{"My_string": "Foo bar.\\t Bar foo."}'

Или вы можете использовать синтаксис "сырой" строки, который вообще не интерпретирует специальные последовательности обратной косой черты:

foo = r'{"My_string": "Foo bar.\t Bar foo."}'

В любом случае процессор JSON увидит строку, содержащую обратную косую черту, за которой следует "t", а не строка, содержащая вкладку.

Ответ 3

Вы можете включить вкладки в значениях (а не в виде пробелов) в файлах JSON, экранируя их. Вот рабочий пример с модулем json в Python2.7:

>>> import json
>>> obj = json.loads('{"MY_STRING": "Foo\\tBar"}')
>>> obj['MY_STRING']
u'Foo\tBar'
>>> print obj['MY_STRING']
Foo    Bar

Не ускользая от '\t' вызывает ошибку:

>>> json.loads('{"MY_STRING": "Foo\tBar"}')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 338, in loads
    return _default_decoder.decode(s)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py", line 365, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py", line 381, in raw_decode
    obj, end = self.scan_once(s, idx)
ValueError: Invalid control character at: line 1 column 19 (char 18)

Ответ 4

Просто чтобы поделиться своим опытом:

Я использую snakemake и конфигурационный файл, написанный в Json. В json файле есть вкладки для отступов. TAB являются законными для этой цели. Но я получаю сообщение об ошибке: snakemake.exceptions.WorkflowError: файл Config недействителен JSON или YAML. Я считаю, что это ошибка snakemake; но я мог ошибаться. Прокомментируйте, пожалуйста. После замены всех TAB на пробелы сообщение об ошибке исчезло.

Ответ 5

В node -red поток i, стоящий перед тем же типом проблемы:

flow.set("delimiter",'"\t"');

ошибка:

{ "status": "ERROR", "result": "Cannot parse config: String: 1: in value for key 'delimiter': JSON does not allow unescaped tab in quoted strings, use a backslash escape" }  

Решение:

i добавлен только в \\t в коде.

 flow.set("delimiter",'"\\t"');