Вопрос или проблема
У меня проблема с заменой "
на \"
и \
на \\
и исключением "
из json
Входной файл test.txt
"a" "b"
{"1":"female","2":"197312","3":"359","4":"201109","5":"mail"}
\uff08\u524d\u5bfe\u5fdc
Я хочу получить вывод в следующем виде
\"a\" \"b\"
{"1":"female","2":"197312","3":"359","4":"201109","5":"mail"}
\\uff08\\u524d\\u5bfe\\u5fdc
Чтобы быть более надежным, вы можете выполнить полный разбор json:
perl -0777 -pe '
s@(".*?"|\\)|(\{(?:"(?:\\.|[^"])*+"|(?2)|[^"{}]++)*+\})|[^{}\\"]+@
$1 ? $1 =~ s/["\\]/\\$&/gr : $&@gse'
Что на входе, аналогичном
"a" "b" "c{d"
{"1":"female","2":"197312","3":"359","4":"201109","5":"mail"}
{
"1": {"x": "y"}
"2": "}}}"
"3": ["{\"x", "}"]
}
\uff08\u524d\u5bfe\u5fdc
дает
\"a\" \"b\" \"c{d\"
{"1":"female","2":"197312","3":"359","4":"201109","5":"mail"}
{
"1": {"x": "y"}
"2": "}}}"
"3": ["{\"x", "}"]
}
\\uff08\\u524d\\u5bfe\\u5fdc
Вам может понадобиться уточнить, что вы хотите сделать, если вход содержит "foo\"bar"
или "foo\nbar"
за пределами json-объектов.
В простом примере, который вы показали, это просто. Просто экранируйте символы только на строках, которые не начинаются с {
:
$ sed -E '/^[^{]/s|(["\])|\\\1|g' file
\"a\" \"b\"
{"1":"female","2":"197312","3":"359","4":"201109","5":"mail"}
\\uff08\\u524d\\u5bfe\\u5fdc
Тем не менее, ситуация усложняется, если ваш JSON может занимать несколько строк. Для таких случаев вы можете написать небольшой скрипт, который подсчитывает количество открывающих {
и закрывающих }
, и применяет замену только тогда, когда эти числа равны (т.е. когда мы не находимся в строке JSON). Что-то вроде:
perl -F'' -ne 'for (@F){$op++ if /{/; $cl++ if /}/; if($cl==$op){s|["\\]|\\$&|g;}print}' file
Однако это также сломается, если строка JSON сама может содержать {
или }
, которые не обозначают часть JSON (например, {"1":"b-{c}"}
или что-то подобное). Для таких случаев используйте подход Стефана вместо этого.
$ sed 's/\(\\\|^"\|"$\|"[ \t]\)/\\\1/g' test.txt | sed 's/\([ \t]\)"/\1\\"/g'
- Замените
\
или"
в начале строки или в конце строки или перед пробелом/символом табуляции:
's/\(\\\|^"\|"$\|"[ \t]\)/\\\1/g'
- или
"
после пробела/символа табуляции:sed 's/\([ \t]\)"/\1\\"/g'
Таким образом, это работает только в том случае, если ваша строка JSON не содержит знаков пробела/символов табуляции и находится в одной строке.
Используя jq
:
$ jq -R -rc 'if try fromjson catch false | (type == "object") then . else tojson | ltrimstr("\"") | rtrimstr("\"") end' file
\"a\" \"b\"
{"1":"female","2":"197312","3":"359","4":"201109","5":"mail"}
\\uff08\\u524d\\u5bfe\\u5fdc
Это считывает каждую строку входных данных из file
как сырую текстовую строку и пытается разобрать ее как фрагмент JSON с помощью fromjson
. Если это удачно (с использованием try
и catch
), и если разобранный фрагмент JSON является объектом, то он сохраняется в том виде, в каком был.
Если вход не может быть разобран как JSON, или если это не объект, он кодируется как строка JSON с помощью tojson
. Поскольку вход читается как сырой текст, мы дважды кодируем строку, удаляя внешний набор двойных кавычек с помощью ltrimstr()
и rtrimstr()
, чтобы получить желаемый формат вывода для этих строк, не являющихся объектами JSON.
Ответ или решение
Как заменить символы в текстовом файле с исключением JSON-строк
Введение
В данной статье мы рассмотрим, как с помощью инструментов командной строки, таких как sed
и perl
, выполнить замену символов в текстовом файле. Основной задачей является замена "
на \"
и \
на \\
, исключая элементы, содержащие JSON. Мы предоставим несколько методов, которые помогут реализовать эту задачу, а также объясним, как правильно обрабатывать строки, содержащие JSON, избегая потенциальных ошибок.
Проблема замены символов
Ваша задача состоит в том, чтобы осуществить замену символов на каждой строке текстового файла, за исключением тех строк, которые содержат JSON. Это может включать создание различных решений в зависимости от сложности JSON и структуры файла.
Простой пример
Предположим, у вас есть файл test.txt
со следующим содержимым:
"a" "b"
{"1":"female","2":"197312","3":"359","4":"201109","5":"mail"}
\uff08\u524d\u5bfe\u5fdc
Вы хотите преобразовать его в следующий вид:
\"a\" \"b\"
{"1":"female","2":"197312","3":"359","4":"201109","5":"mail"}
\\uff08\\u524d\\u5bfe\\u5fdc
Использование sed
Одним из самых простых способов достижения этой цели является использование sed
. Однако для обработки JSON нужно учитывать различные особенности форматирования. Вот пример команды:
sed -E '/^[^{]/s|(["\\])|\\\1|g' test.txt
Данная команда заменяет кавычки и обратные слэши на экранированные только в тех строках, которые не начинаются с {
, что предполагает отсутствие JSON на этой строке.
Более сложная обработка
Если JSON может занимать несколько строк, следует применить более сложный подход. Например, использование perl
для подсчёта открывающих и закрывающих фигурных скобок:
perl -F'' -ne 'for (@F){$op++ if /{/; $cl++ if /}/; if($cl==$op){s|["\\]|\\$&|g;}print}' test.txt
В этом коде мы считываем файл построчно, подсчитываем фигурные скобки и выполняем замену символов только тогда, когда выходим за пределы секции JSON.
Обработка с помощью jq
Для более продвинутого анализа JSON вы можете использовать jq
, инструмент, специализированный для работы с JSON:
jq -R -rc 'if try fromjson catch false | (type == "object") then . else tojson | ltrimstr("\"") | rtrimstr("\"") end' test.txt
Эта команда пытается интерпретировать каждую строку как JSON. Если удается, она оставляет строку нетронутой, в противном случае выполняет экранирование.
Заключение
При решении проблемы замены символов в текстовом файле с исключением JSON-строк вам может потребоваться использовать различные подходы в зависимости от сложности данных. Использование sed
, perl
или jq
— это три эффективных способа, которые вы можете комбинировать в зависимости от ваших потребностей. Правильное решение поможет избежать ошибок и улучшить читаемость вашего текста, сохраняя при этом структуру JSON неизменной.
Рекомендации
- Тестирование: Всегда тестируйте команды на небольших образцах данных, чтобы убедиться в их корректности.
- Резервные копии: Не забудьте создать резервные копии исходных данных.
С помощью приведённых примеров и подходов вы сможете успешно решить задачу замены символов в текстовом файле, исключая при этом элементы JSON.