Я хотел бы удалить некоторые гиперссылки, которые содержат «устаревшие/» в URL-адресе во многих файлах HTML. Однако некоторые из них находятся в одной строке
<a href = ".../legacy/..."> ... </a>\n
в то время как другие нет. Как я могу использовать sed для замены их всех одновременно?
До сих пор я пробовал
sed -ri 's/(.+legacy/[[:print:]]+</a>.*$)/<!--\1-->/g' wave-on-a-string.html
который заменяет гиперссылку только в одной строке. Затем я понял, что sed читает только одну строку за раз. Однако я не мог узнать, как сопоставить блок гиперссылок из нескольких (неопределенного числа) строк.
Файлы HTML имеют примерно такое содержимое:
<a class = "other-sim-page" href = "legacy/wave-on-a-string.html" dir = "ltr">
<table>
<tr>
<td>
<img style = "display: block;" src = "../../images/icons/sim-badges/flash-badge.png" alt = "Flash Logo" width = "44" height = "44">
</td>
<td>
<span class = "other-sim-link">原始模擬教學與翻譯</span>
</td>
</tr>
</table>
</a>
...
<p>瀏覽<a href = "legacy/wave-on-a-string.html#for-teachers-header">更多活動</a>。</p>
...
<a href = "legacy/radiating-charge.html" class = "simulation-link">
<img class = "simulation-list-thumbnail" src = "../../sims/radiating-charge/radiating-charge-128.png" id = "simulation-display-thumbnail-radiating-charge" alt = "Screenshot of the simulation 電荷輻射" width = "128" height = "84"/><br/>
<strong><span class = "simulation-list-title">電荷輻射</span></strong><br/>
<span class = "sim-display-badge sim-badge-flash"></span>
</a>
...
и он соответствует и заменяет только вторую гиперссылку, поскольку она находится в одной строке.
Я бы хотел заменить все блоки гиперссылок (<a href = "..."> ... </a>
), даже если они растягиваются на несколько строк.
Вы не используете надлежащий инструмент для этой задачи.
sed
— отличный инструмент для поиска и замены с использованием регулярных выражений, однако регулярные выражения (на основе DFA) не могут анализировать вложенные структуры, такие как деревья JSON или XML (поскольку нет ограничений на глубину вложенности). Поэтому я бы рекомендовал использовать синтаксический анализатор XML/HTML.
Например, вы можете использовать XSLT
:
Вход:
$ cat webpage.html
<!DOCTYPE html>
<html>
<body>
<h1>My First Heading</h1>
<p>My first paragraph.</p>
<a href = "https://www.w3schools.com">Visit W3Schools</a>
<p>My second paragraph.</p>
<a href = "legacy/radiating-charge.html" class = "simulation-link">
<img class = "simulation-list-thumbnail" src = "../../sims/radiating-charge/radiating-charge-128.png" id = "simulation-display-thumbnail-radiating-charge" alt = "Screenshot of the simulation 電荷輻射" width = "128" height = "84"/><br/>
<strong><span class = "simulation-list-title">電荷輻射</span></strong><br/>
<span class = "sim-display-badge sim-badge-flash"></span>
</a>
</body>
</html>
Таблица стилей:
$ cat remove_legacy.xslt
<?xml version = "1.0"?>
<xsl:stylesheet version = "1.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
<xsl:output method = "html" encoding = "UTF-8" omit-xml-declaration = "yes"/>
<!-- copy the whole structure recursively -->
<xsl:template match = "@*|node()">
<xsl:copy>
<xsl:apply-templates select = "@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- when you meet a tag a that contains href -->
<xsl:template match = "//a[contains(@href,'legacy')]">
<!-- add comment starting tag -->
<xsl:text disable-output-escaping = "yes">
<!--
</xsl:text>
<xsl:copy>
<xsl:apply-templates select = "@*|node()"/>
</xsl:copy>
<!-- add comment ending tag -->
<xsl:text disable-output-escaping = "yes">
-->
</xsl:text>
</xsl:template>
</xsl:stylesheet>
Выход:
$ xsltproc --html remove_legacy.xslt webpage.html
<html>
<body>
<h1>My First Heading</h1>
<p>My first paragraph.</p>
<a href = "https://www.w3schools.com">Visit W3Schools</a>
<p>My second paragraph.</p>
<!--
<a href = "legacy/radiating-charge.html" class = "simulation-link">
<img class = "simulation-list-thumbnail" src = "../../sims/radiating-charge/radiating-charge-128.png" id = "simulation-display-thumbnail-radiating-charge" alt = "Screenshot of the simulation 電荷輻射" width = "128" height = "84"><br>
<strong><span class = "simulation-list-title">電荷輻射</span></strong><br>
<span class = "sim-display-badge sim-badge-flash"></span>
</a>
-->
</body>
</html>
Как видите, href
, не содержащее legacy
, не комментируется.
Спасибо за этот ответ. Я пробовал, но получил много ошибок. Я предполагаю, что, возможно, исходные файлы HTML не имеют строгой структуры.
@Franklin: не могли бы вы запустить команду xsltproc --html remove_legacy.xslt webpage.html
с помощью --html
?
@Franklin: если и это не работает, то это потому, что ваши html-файлы повреждены ...
Правильно, это должно быть проблемой исходного HTML-файла. pastebin.com/AqjxmDJT Первая ошибка в строке 7 содержит только <head>. Строка 138 — это строка кода javascript, вызывающая много ошибок. Также у него есть <g:sharetoclassroom>, который, я думаю, должен работать для класса Google. Спасибо, что поделились инструментом в любом случае.
С GNU sed for -z
и использованием всех 3 блоков ввода, которые вы предоставили вместе в одном файле, в качестве ввода:
$ sed -z '
s:@:@A:g; s:}:@B:g; s:</a>:}:g;
s:<a[^<>]* href = "legacy/[^}]*}:<!--&-->:g;
s:}:</a>:g; s:@B:}:g; s:@A:@:g
' file
<!--<a class = "other-sim-page" href = "legacy/wave-on-a-string.html" dir = "ltr">
<table>
<tr>
<td>
<img style = "display: block;" src = "../../images/icons/sim-badges/flash-badge.png" alt = "Flash Logo" width = "44" height = "44">
</td>
<td>
<span class = "other-sim-link">原始模擬教學與翻譯</span>
</td>
</tr>
</table>
</a>-->
...
<p>瀏覽<!--<a href = "legacy/wave-on-a-string.html#for-teachers-header">更多活動</a>-->。</p>
...
<!--<a href = "legacy/radiating-charge.html" class = "simulation-link">
<img class = "simulation-list-thumbnail" src = "../../sims/radiating-charge/radiating-charge-128.png" id = "simulation-display-thumbnail-radiating-charge" alt = "Screenshot of the simulation 電荷輻射" width = "128" height = "84"/><br/>
<strong><span class = "simulation-list-title">電荷輻射</span></strong><br/>
<span class = "sim-display-badge sim-badge-flash"></span>
</a>-->
Первая строка превращает }
в символ, который впоследствии не может присутствовать во входных данных, путем преобразования всех }s
в @B
, а затем превращает все </a>
в }
, так что char можно инвертировать в выражении в квадратных скобках, как [^}]
в регулярном выражении для строку, которую вы хотите заменить, вторая строка выполняет фактическую замену, которую вы хотите, а третья строка восстанавливает все }
s в </a>
s, а затем @B
s в }
s.
Манипулирование входными данными для создания символа, который не может существовать во входных данных, является довольно распространенной идиомой sed для обхода невозможности инвертировать строки в регулярных выражениях. См. https://stackoverflow.com/a/35708616/1745001 для другого примера с дополнительным пояснением.
Это, конечно, потерпит неудачу, если у вас есть строки на входе, которые напоминают строки, которые вы пытаетесь сопоставить, но на самом деле этого, вероятно, достаточно для вашего конкретного ввода - вам просто нужно подумать о том, что он делает, и проверить его вывод на проверять.
попробуй гну сед
sed -E '/<a\s+.*href=.*legacy/.*</a>/d; /<a\s+.*href=.*legacy//,/</a>/d' wave-on-a-string.html
Найдите
-z
на справочной странице sed.