Вопрос или проблема
У меня есть HTML-файл, и я хочу заменить строку, включенную между двумя тегами HTML-таблицы. Вот пример того, что у меня есть:
<tr class="noBorder"><td>string1</td><td>string2</td><td>string3</td><td>string4</td><td>random string</td></tr>
Итак, я хочу заменить только случайную строку на что-то другое только в одной конкретной строке. В моей таблице это последняя ячейка.
Я пробую это;
sed -e '28s/\(<td>\).*\(<\/td><\/tr>\)/<td>!!variable instead of random!!<\/td><\/tr>/' file.html
Но это заменяется на следующее (так что я теряю все перед этим);
<tr class="noBorder"><td>!!variable вместо random!!</td></tr>
Я хочу это;
<tr class="noBorder"><td>string1</td><td>string2</td><td>string3</td><td>string4</td><td>!!variable вместо random!!</td></tr>
Спасибо всем, кто может это решить
Не используйте регулярные выражения для парсинга HTML. Используйте парсер HTML.
Учитывая следующее:
<!DOCTYPE html>
<html>
<head>
<title>Foo</title>
</head>
<body>
<!-- Таблица "foo" -->
<table id="foo">
<tr><td>Col1</td><td>Col2</td><td>Col3</td></tr>
<tr><td>Col1</td><td>Col2</td><td>Col3</td></tr>
<tr><td>Col1</td><td>Col2</td><td>Col3</td></tr>
</table>
</body>
</html>
Чтобы заменить содержимое последней ячейки второй строки в таблице foo
, используя xmlstarlet
, вы должны сделать:
xmlstarlet ed -u '//table[@id="foo"]/tr[2]/td[last()]' -v 'Replacement' page.html | sed 1d
//table[@id="foo"]
: адресует все таблицы с idfoo
(которых у вас, кстати, должно быть только одна)/tr[2]
: адресует второй элементtr
/td[last()]
: адресует последний элементtd
Команда sed '1d'
, к сожалению, необходима, потому что xmlstarlet
вставит тег версии XML в начало. Я не нашел способа предотвратить это.
Также имейте в виду, что форматирование документа может измениться как побочный эффект парсинга:
% xmlstarlet ed -u 'html/body/table[@id="foo"]/tr[2]/td[last()]' -v 'Replacement' page.html | sed 1d
<!DOCTYPE html>
<html>
<head>
<title>Foo</title>
</head>
<body>
<!-- Таблица "foo" -->
<table id="foo">
<tr>
<td>Col1</td>
<td>Col2</td>
<td>Col3</td>
</tr>
<tr>
<td>Col1</td>
<td>Col2</td>
<td>Replacement</td>
</tr>
<tr>
<td>Col1</td>
<td>Col2</td>
<td>Col3</td>
</tr>
</table>
</body>
</html>
Ответ или решение
Замена строки в HTML-файле с помощью sed
При работе с HTML-файлами и необходимости замены строки, особенно в контексте таблиц, важно помнить, что sed
не лучший выбор для манипуляций с HTML-структурой. В этой статье мы подробно обсудим, как использовать sed
для замены строки в конкретной ячейке таблицы. Тем не менее, рекомендуется воспользоваться специализированными инструментами для работы с XML или HTML, такими как xmlstarlet
, для более надежных и чистых решений.
Пример исходной HTML-структуры
Предположим, у вас есть следующая HTML-структура, и вам нужно заменить текст "random string" в последней ячейке второго ряда таблицы:
<tr class="noBorder">
<td>string1</td>
<td>string2</td>
<td>string3</td>
<td>string4</td>
<td>random string</td>
</tr>
Замена строки с помощью sed
Вы пытаетесь выполнить следующую команду sed
:
sed -e '28s/\(<td>\).*\(<\/td><\/tr>\)/<td>!!variable instead of random!!<\/td><\/tr>/' file.html
К сожалению, эта команда упускает часть строки и приводит к потере содержимого предыдущих ячеек. Вместо этого вы можете попробовать более детальный и точный подход:
sed -i '28s/\(.*<td>\)[^<]*\(.*<\/td>\)/\1!!variable instead of random!!\2/' file.html
Объяснение команды:
-i
— Этот параметр позволяет редактировать файл на месте.28s/
— Выбор 28-й строки для замены. Убедитесь, что в вашем файле есть достаточное количество строк, чтобы эта команда не выдавала ошибку.\(.*<td>\)
— Указывает на любой текст перед необходимой ячейкой.[^<]*
— Захватывает текст внутри ячейки, не включая символы<
.\(.*<\/td>\)
— Указывает на любой текст после ячейки вплоть до</td>
.
Таким образом, команда сохраняет все содержимое перед и после целевой ячейки, заменяя только нужное значение.
Альтернатива — Использование xmlstarlet
Если структура документа более сложная или если вам нужно обрабатывать файлы HTML и XML более надежно, рассмотрите использование xmlstarlet
. Например, для замены содержимого последней ячейки второго ряда таблицы можете использовать следующую команду:
xmlstarlet ed -u '//table[@id="foo"]/tr[2]/td[last()]' -v '!!variable instead of random!!' file.html | sed '1d'
Объяснение команды:
//table[@id="foo"]
— Выбор таблицы с указанным идентификатором./tr[2]
— Обращение ко второму ряду таблицы./td[last()]
— Выбор последней ячейки текущего ряда.sed '1d'
— Удаление первой строки вывода, которую добавляетxmlstarlet
.
Заключение
При работе с HTML-структурами целесообразно использовать более специализированные инструменты, чем sed
, для предотвращения ошибок при парсинге. Несмотря на возможность замены через sed
, использование xmlstarlet
дает большую уверенность в корректности манипуляций с разметкой и сохранением других данных. Помните, что изменение HTML и XML документации требует осторожности и внимательности к структуре данных.