Как заменить случайную строку в таблице HTML?

Вопрос или проблема

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

<tr class="noBorder"><td>string1</td><td>string2</td><td>string3</td><td>string4</td><td>random string</td></tr>

Я хочу заменить только random string на что-то другое, только в одной конкретной строке. В моей таблице ячейка, содержащая random string, является последней ячейкой.

Я пробовал это:

sed -e '28s/\(<td>\).*\(<\/td><\/tr>\)/<td>!!переменная вместо случайного!!<\/td><\/tr>/' file.html

но это заменило на следующее (поэтому я потерял все, что было до этого):

<tr class="noBorder"><td>!!переменная вместо случайного!!</td></tr>

То, что я пытаюсь достичь, это:

<tr class="noBorder"><td>string1</td><td>string2</td><td>string3</td><td>string4</td><td>!!переменная вместо случайного!!</td></tr>

Спасибо всем, кто может помочь мне решить эту проблему.

Не используйте регулярные выражения для парсинга HTML. Используйте парсер HTML.

Как указал Ferrybig в комментариях, метод с использованием xmlstarlet работает хорошо только когда целевой HTML является подмножеством XML и не сработает, например, на саморазмыкающихся тегах, таких как <br /> и других.

Немного более сложный метод будет заключаться в использовании Perl с фреймворком Mojolicious (sudo apt install libmojolicious-perl), который предоставляет класс Mojo::DOM, который может парсить HTML; его метод find() будет принимать селектора Mojo::DOM::CSS (которые практически повторяют стандартные CSS-селекторы), в отличие от путей XPath xmlstarlet; преимуществом этого метода является то, что оригинальное форматирование не будет потеряно, в отличие от метода xmlstarlet.

Учитывая следующее:

<!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>

Чтобы заменить содержимое последней ячейки 2-й строки в таблице foo, вы можете сделать следующее:

perl -mMojo::DOM -0777e '
    my $d = Mojo::DOM -> new;
    $d ->
        parse(<>) ->
        find("table[id=\"foo\"] tr:nth-child(2) td:last-child") ->
        [0] ->
        content("Замена");
    print $d -> to_string
' page.html
  • table[id=\"foo\"] tr:nth-child(2) td:last-child: находит последний td второй tr первой таблицы с id foo (которой у вас должно быть только одно, кстати)
% perl -mMojo::DOM -0777e '
    my $d = Mojo::DOM -> new;
    $d ->
        parse(<>) ->
        find("table[id=\"foo\"] tr:nth-child(2) td:last-child") ->
        [0] ->
        content("Замена");
    print $d -> to_string
' page.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>Замена</td></tr>
        <tr><td>Col1</td><td>Col2</td><td>Col3</td></tr>
    </table>
</body>
</html>

Используя xmlstarlet, вы можете сделать следующее:

xmlstarlet ed -u '//table[@id="foo"]/tr[2]/td[last()]' -v 'Замена' page.html | sed 1d
  • //table[@id="foo"]: адресует все таблицы с id foo (которой у вас должно быть только одно, кстати)
  • /tr[2]: адресует второй элемент tr
  • /td[last()]: адресует последний элемент td

Команда sed '1d' к сожалению, необходима, потому что xmlstarlet вставит тег версии XML в начале. Я не нашел способа предотвратить это.

Также обратите внимание, что форматирование документа может измениться в результате парсинга:

% xmlstarlet ed -u 'html/body/table[@id="foo"]/tr[2]/td[last()]' -v 'Замена' 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>Замена</td>
      </tr>
      <tr>
        <td>Col1</td>
        <td>Col2</td>
        <td>Col3</td>
      </tr>
    </table>
  </body>
</html>

Kos дал вам правильный способ®, используйте его. Это безопаснее, более надежно, легче поддерживать в долгосрочной перспективе и т.д. Я хочу объяснить, почему ваш sed не сработал. Вы заменяете все с первого <td>, вы не пытаетесь указать, какой <td> изменить. Выражение .* всегда будет пытаться найти самое длинное соответствие, поэтому <td>.*</td> будет соответствовать от первого <td> до последнего </td>. Вы также используете ненужное сложное выражение. Никакие \( не нужны.

Эта команда sed сделает то, что вам нужно, если у вас есть эта точная строка на 28-й строке вашего файла:

sed '28s/<td>[^<]*/<td>!!переменная вместо случайного!!/5' file

Оператор s может принимать число в конце для обозначения “заменить N-е вхождение этого шаблона”. В этом случае вы хотите заменить 5-й <td> и весь текст после него до первого < на вашу замену, поэтому мы ищем <td> и затем 0 или более не-< символов ([^<]*), и заменяем это снова на <td> и ваш текст замены. Это выглядит так:

$ sed '28s|<td>[^<]*|<td>!!переменная вместо случайного!!|5' file | awk NR==28
<tr class="noBorder"><td>string1</td><td>string2</td><td>string3</td><td>string4</td><td>!!переменная вместо случайного!!</td></tr>

Но серьезно, не делайте этого. Это сломается при малейшем изменении формата ввода, не сможет работать, если таблица правильно отформатирована на несколько строк и т.д. Просто используйте подходящий парсер как предложил Kos.

Ответ или решение

Чтобы заменить случайную строку в HTML-таблице, разумно воспользоваться специализированным парсером HTML, так как использование регулярных выражений для разбора HTML может привести к непредсказуемым результатам. В данной ситуации, вам необходимо заменить строку "random string" на другую строку в последней ячейке определенной строки таблицы. Рассмотрим эффективный способ сделать это с помощью Perl и библиотеки Mojo::DOM.

Шаги для замены строки в HTML-таблице

  1. Установка необходимых инструментов:
    Убедитесь, что в вашей системе установлен Perl и библиотека Mojo::DOM. Для установки Mojolicious выполните команду:

    sudo apt install libmojolicious-perl
  2. Создание скрипта для замены:
    Напишите скрипт на Perl, который будет загружать ваш HTML-файл, находить нужный элемент и заменять его содержимое. Вот пример кода, который выполняет данную задачу. Предположим, вы хотите заменить содержимое последней ячейки второй строки таблицы с ID "foo":

    perl -mMojo::DOM -0777e '
       my $d = Mojo::DOM->new;
       $d->parse(<>)  # Загружаем содержимое HTML
           ->find("table[id=\"foo\"] tr:nth-child(2) td:last-child")  # Ищем нужную ячейку
           ->content("!!проверяемый текст вместо случайного!!");  # Заменяем содержимое
       print $d->to_string;  # Выводим измененное HTML
    ' ваш_файл.html
  3. Объяснение кода:

    • -mMojo::DOM: Загружает модуль Mojo::DOM.
    • -0777e: Загружает весь файл в одну строку, благодаря чему можно использовать большие объёмы текста.
    • $d->parse(<>);: Загружает содержание HTML-файла.
    • find("table[id=\"foo\"] tr:nth-child(2) td:last-child"): Находит последний элемент <td> второй строки соответствующей таблицы.
    • content("!!проверяемый текст вместо случайного!!");: Производит замену содержимого найденного элемента.
    • print $d->to_string;: Печатает измененное HTML на стандартный вывод.
  4. Запуск скрипта:
    Сохраните приведённый выше код в файл или выполните его через терминал, перенаправив входные данные из вашего HTML файла.

Заключение

Использование библиотек, таких как Mojo::DOM, обеспечивает надежность и безопасность вашего кода, упрощая манипуляции с HTML-документами. Это особенно пригодится при обновлении веб-контента, где критически важно сохранять первоначальную структуру и форматирование. Отказ от regex для работы с HTML значительно снижает вероятность ошибок, улучшая долгосрочную поддерживаемость вашего решения.

Эти рекомендации помогут вам успешно заменить строку в HTML-таблице эффективно и безопасно. Оставайтесь на шаг впереди в ваших профессиональных разработках, используя доступные инструменты для решения задач.

Оцените материал
Добавить комментарий

Капча загружается...