#regex #bash #macos #sed #grep
Вопрос:
Как я могу удалить весь <a href="file://???">
этот текст </a>
, но не другой <a></a>
, или </a>
использовать sed или perl?
Является:
<p><a class="a" href="file://any" id="b">keep this text</a>, <a href="http://example.com/abc">example.com/abc</a>, more text</p>
Должно быть:
<p>keep this text, <a href="http://example.com/abc">example.com/abc</a>, more text</p>
У меня есть такое регулярное выражение, но оно слишком жадное и удаляет все </a>
gsed -E -i 's/<a*href="file:[^>]*>(. ?)</a>/1>/g' file.xhtml
Комментарии:
1.рассмотрите возможность обновления вопроса более репрезентативным набором данных, в частности … вы упомянули
remove all
, что подразумевает, что вы, возможно, захотите удалить несколько записей, поэтому пример, показывающий несколько записей, был бы полезен; кроме того, вы хотите удалить всеfile:
записи или только определенные?
Ответ №1:
Допущения:
- OP не имеет доступа к инструменту, ориентированному на HTML
- удалите
<a href="file:...">
…some_text…</a>
обертки, оставив только...some_text...
- применяется только к
file:
записям - входные данные не имеют разрыва строки/подачи в середине
file:
записи
Примеры данных, показывающие несколько file:
записей, чередующихся с некоторыми другими (бессмысленными) записями:
$ cat sample.html
<p><a href="https:/google.com">some text</a><a href="file://any" >keep this text</a>, <a href="http://example.com/abc">example.com/abc</a>, more text</p><a href="file://anyother" >keep this text,too</a>, last test</p>
Одна sed
идея-удалить обертки для всех file:
записей:
sed -E 's|<a[^<>] file:[^>] >([^<] )</a>|1|g' "${infile}"
ПРИМЕЧАНИЕ: возможно, немного перебор с некоторыми [^..]
записями, но ключевая цель состоит в том, чтобы замкнуть sed's
жадное соответствие по умолчанию …
Это оставляет:
<p><a href="https:/google.com">some text</a>keep this text, <a href="http://example.com/abc">example.com/abc</a>, more text</p>keep this text,too, last test</p>
Комментарии:
1. твой код работает на меня. Спасибо! Он работает с macOS sed и GNU sed, и на данный момент он самый короткий.
Ответ №2:
В одну сторону:
sed -E 's,<a[^>]*?href="file://[^>]*>([^<]*)</a>,1,g'
<a[^>]*?href="file://[^>]*>
совпадение<a
любое количество не->
(не-жадных), за которыми следуетhref="file://
любое количество не —>
символов, за которыми следует>
([^<]*)
сопоставьте и захватите любое количество несимвольных<
символов- матч на
</a>
Все совпадающее заменяется захватом, 1
и окончание g
заставляет его выполнять замену в каждом случае в каждой строке.
Примеры:
$ cat data
<p><a class="a" href="file://any" id="b">keep this text</a>, <a id="file:ex" href="http://example.com/abc">example.com/abc</a>, more text</p>
<p><a href="file://any" class="f">keep this text</a>, <a href="http://example.com/abc">example.com/abc</a>, more text</p>
$ sed -E 's,<a[^>]*?href="file://[^>]*>([^<]*)</a>,1,g' < data
<p>keep this text, <a id="file:ex" href="http://example.com/abc">example.com/abc</a>, more text</p>
<p>keep this text, <a href="http://example.com/abc">example.com/abc</a>, more text</p>
Комментарии:
1. Спасибо, этот тоже работает, однако он работает только с GNU sed, но он выполняет свою работу.
2. @user3464412 Пожалуйста, но это должно работать с любым Posix
sed
, если я не ошибаюсь. Я попробовалsed -E --posix
, и это дает тот же результат.
Ответ №3:
Учитывая тот случай <a>
, когда тег состоит из содержимого в нескольких строках, как насчет perl
решения:
perl -0777 -i -pe 's#<a. ?href="?file. ?>(. ?)</a>#$1#gs' file.xhtml
-0777
Опция указывает perl проглотить весь файл целиком.- Эта
-i
опция позволяет редактировать на месте. s
Переключатель в концеs
оператора заставляет точку совпадать с любыми символами, включая символ новой строки.- Регулярное выражение
. ?
-это не жадная версия.
, позволяющая обеспечить кратчайшее совпадение.