Sed: как заменить символ nextline \ n в текстовых файлах? - PullRequest
0 голосов
/ 23 апреля 2011

Мне нужно исправить ошибку и заменить второй тег </time> на </tags> в XML-файле со следующей структурой:

<time>20260664</time>
<tags>substancesummit ss</time>
<geo>asdsadsa</geo>
<time>20260664</time>
<tags>substancesummit ss</time>
<geo>asdsadsa</geo>

Я пытаюсь сделать это с помощью sed итак как у меня есть 2 </time> закрывающий тег на элемент, моя идея состоит в том, чтобы заменить </time><geo> на </tags><geo>.

Однако между ними есть следующий символ строки, поэтому я использую \n, ноэто не работает:

sed 's/time>\n<geo>/tags>\n<geo>/g' old.xml > new.xml

Любая помощь?

Ответы [ 7 ]

1 голос
/ 23 апреля 2011

Используйте это:

$ sed -n '1h; 1!H; $ {g; s/<\/time>\n<geo>/<\/tags>\n<geo>/g; p;}' file
1 голос
/ 23 апреля 2011

Если в файле есть символ, который вы определенно не используете, попробуйте заменить его \ n, выполните работу sed и замените его обратно.tr работает очень хорошо для этого

cat old.txt | tr '\n' '#' | sed 's/time>#<geo>/tags>#<geo>/g' | tr '#' '\n' > new.txt

Я использую # как символ замены.

1 голос
/ 23 апреля 2011

Вы можете сделать это с помощью одной команды sed следующим образом:

sed '/<\/time>/I{n;:A;N;h;/<geo>/I!{H;bA};/<geo>/I{g;s/<\/time>/<\/tags>/i}}' file.txt

Тестирование

Если ваш входной файл file.txt такой:

<time>20260664</time>
<tags>substancesummit ss
</time>

<Geo>asdsadsa</geo>
<time>30260664</time>
<tags>substancesummit st</timE>
<geo>bsdsadsa</geo>

Тогда вывод вышеуказанной команды будет:

<time>20260664</time>
<tags>substancesummit ss
</tags>

<Geo>asdsadsa</geo>
<time>30260664</time>
<tags>substancesummit st</tags>
<geo>bsdsadsa</geo>

Он охватывает несколько символов новой строки (\r или \n) в любой комбинации от </time> до <geo>

PS: вышеприведенная команда sed игнорирует поиск / замену по уходу, если вы этого не хотите, просто удалите флаг I из команды sed или просто дайте мне знать.

0 голосов
/ 23 апреля 2011
sed -e 's,<\([^>]*\)>\([^<]*\)</[^>]*>,<\1>\2</\1>,g' tags.xml

Это заменяет в той же строке

(opening tag)(content)(closing tag) 

с

(opening tag)(content)(closing tag) 

но закрывающий тег всегда совпадает с открывающим тегом.

Может произойти сбой, если в файле найдено более одной пары тегов.

Подробно, он ищет что-то, начиная с «<», затем следует имя тега, не закрывая его «>», за которым следует содержимое, то есть все до «<». </p>

0 голосов
/ 23 апреля 2011

Почему бы вам не обойти проблему, пытаясь сопоставить разрывы строк, и вместо этого попытаться сопоставить строку с открывающим тегом <tags> и содержимым после него до (не) совпадающего тега </time>? Нравится

# untested, written from scratch
sed 's/<tags>(.*)<\/time>/<tags>\1<\/tags>/g' infile > outfile
0 голосов
/ 23 апреля 2011

вы можете использовать awk вместо

$ awk -vRS="</geo>" '{gsub(/<\/time>.<geo>/,"</tags>\n<geo>")}1' ORS="</geo>" file
<time>20260664</time>
<tags>substancesummit ss</tags>
<geo>asdsadsa</geo>
<time>20260664</time>
<tags>substancesummit ss</tags>
<geo>asdsadsa</geo>

Во-первых, я вижу, что </geo> заканчивает каждый блок, поэтому сделайте это разделителем записей. После этого подставьте то, что требуется. Наконец, поместите </geo> обратно в качестве разделителя выходных записей (ORS).

0 голосов
/ 23 апреля 2011

sed обычно редактирует строки, и немного сложнее заставить его понимать несколько строк одновременно, как и вы. Вместо этого, как насчет более точного исправления ломаных линий, например:

/<tags>/ s@</time>@</tags>@

Это заменит </time> на </tags> только в строках, которые также содержат <tags>. Обратите внимание, что я использовал @ вместо / в качестве разделителя для команды подстановки, чтобы избежать необходимости избегать косых черт в XML, который мы пытаемся заменить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...