2025, Dec 17 03:02
Как удалить комментарии из JSONC на Python, не ломая строки
Как удалить комментарии из JSONC на Python с помощью регулярных выражений: сохраняем строки в кавычках, убираем // и /*...*/, получаем валидный JSON быстро.
Удалять комментарии из JSONC, чтобы получить валидный JSON, кажется простым делом — пока не вмешиваются строковые литералы. В URL, путях и других значениях встречаются двойные слэши, поэтому наивное регулярное выражение, которое вычеркивает всё от // до конца строки, повредит данные. Ниже — надёжный подход на Python, основанный только на регулярках: он сохраняет строковые значения в кавычках и при этом убирает комментарии.
Постановка задачи
На входе — JSONC, надстройка над JSON, допускающая комментарии. Задача — удалить комментарии и получить корректный JSON, используя только регулярные выражения. Подводный камень: // может встречаться внутри строк в кавычках, и прямолинейный шаблон удалит лишнее.
Пример, показывающий проблему
Сначала — наивная попытка, которая ломается, если // встречается внутри строковых значений:
import re
bad_rule = re.compile(r'\s//[^}]*')
result = bad_rule.sub('', data)
Посмотрим на такой ввод. Это корректный JSONC, аккуратно отформатированный. Если удалить комментарии правильно, он гарантированно превратится в валидный JSON:
// пробовал это sed -r 's#\s//[^}]*##'
// пробовал и это '%^*3//s39()'
[
{
"test1" : "http://test.com",
"test2" : "http://test.com",//тест
// что угодно
"ok" : 3, // здесь 2
"//networkpath1" : true, //почему бы и нет
"//networkpath2" : true
// ок
},// конец файла
{
"statement" : "I like test cases"
}// конец файла
]
Наивное регулярное выражение неверно вырежет части значений с http://, потому что не различает // внутри строк и настоящие разделители комментариев.
Почему наивный подход ломается
Регулярка, которая без разбора хватается за // до некой границы, не учитывает грамматику строковых литералов. Если // встречается внутри кавычек, это не начало комментария, но шаблон всё равно его находит и удаляет корректное содержимое. Такая же опасность и с блочными комментариями: последовательности /* и */ тоже могут попадаться внутри строк.
Регулярка, которая сохраняет строки и удаляет комментарии
Рабочая стратегия — одновременно сопоставлять комментарии и строковые литералы: строки захватывать в группу, а при замене подставлять их обратно. Так строки остаются нетронутыми, а построчные и блочные комментарии удаляются. Подход не зависит ни от отступов, ни от конкретных переводов строк.
import re
rx_cleanup = re.compile(
r'//.*|/\*[\\s\\S]*?\\*/|("(\\\\\.|.)*?")'
)
sanitized = rx_cleanup.sub(r'\\1', data)
Шаблон чередует три части. Он находит комментарии // до конца строки. Он находит блочные фрагменты /* ... */ с помощью конструкции, охватывающей любые символы. И, что важно, он распознаёт строку в кавычках как захватывающую группу, допускающую экранированные символы внутри; при замене эта группа подставляется обратно, так что содержимое в кавычках сохраняется, а комментарии исчезают.
Почему это важно
Удаление комментариев из JSONC с помощью регулярных выражений удобно для быстрого препроцессинга, но корректность держится на том, чтобы не трогать строковые значения. В URL и подобных данных часто встречается //, и любое случайное удаление ведёт к невалидному JSON или поломанной семантике. Сохранение содержимого в кавычках при одновременном удалении комментариев решает задачу без привязки к форматированию.
Итоги
Если приходится конвертировать JSONC в JSON при помощи регулярок, защитите строки в кавычках и подставляйте их обратно при замене. Показанный шаблон обрабатывает и //, и /* ... */-комментарии (даже если нужен лишь первый вид) и не полагается на конкретные отступы или тип перевода строки. При гарантии, что после удаления комментариев получится валидный JSON, этот метод даёт краткое и практичное решение.