#html #regex #zsh #csplit
#HTML #регулярное выражение #zsh #csplit
Вопрос:
Я хотел бы разделить файл на несколько файлов на основе определенного шаблона регулярных выражений. Ниже я привожу воспроизводимый пример. Если есть более простое решение, я бы тоже приветствовал его!
У меня есть каталог со следующими файлами:
page1.html page2.html page3.html
Скажите, что мой page1.html выглядело это примерно так:
<strong>Hello world</strong>
<p>ABC, Page (1 whatever).</p>
<p>Some text</p>
<p>DEF, Page (1 ummm what).</p>
<p>Some text</p>
<p>THE<em><strong><span class="underline">GHI</span></strong></em>JK <em><strong><span class="underline">the</span></strong></em>LMNOP<em><strong><span class="underline">Q</span></strong></em>RS.<p> ABC, Page (1).</p>
Я хочу разделить page1.html чтобы:
page1_0.html
<strong>Hello world</strong>
page1_1.html
<p>ABC, Page (1 whatever).</p>
<p>Some text</p>
page1_2.html
<p>DEF, Page (1 ummm what).</p>
<p>Some text</p>
<p>THE<em><strong><span class="underline">GHI</span></strong></em>JK <em><strong><span class="underline">the</span></strong></em>LMNOP<em><strong><span class="underline">Q</span></strong></em>RS.<p> ABC, Page (1).</p>
Мне нужен код, который идентифицирует строку со следующим шаблоном:
[0 to 10 characters in the beginning] , Page (1 [0 to 10 characters here]). </p>
В настоящее время у меня есть следующий код:
for filename in *.html; gcsplit -z -f "${filename%.*}_" --suffix-format="%d.html" $filename /'Page (1'/ '{*}'
Но это создает page1_3.html содержащий следующий текст:
<p>THE<em><strong><span class="underline">GHI</span></strong></em>JK <em><strong><span class="underline">the</span></strong></em>LMNOP<em><strong><span class="underline">Q</span></strong></em>RS.<p> ABC, Page (1).</p>
Но когда я запускаю это:
for filename in *.html; gcsplit -z -f "${filename%.*}_" --suffix-format="%d.html" $filename /'^.{0,10}, Page (1.{0,10}).</p>'/ '{*}'
Это просто выводит файл page1_0.html .
В чем проблема с моим регулярным выражением? Существуют ли какие-либо альтернативные способы достижения того, что я пытаюсь сделать?
Ответ №1:
Вы могли бы сделать это с помощью этого короткого скрипта Perl.
#chunker.pl
use 5.022;
use strict;
use diagnostics;
use B "perlstring";
our $i = 0;
our $fmt = "page1_%d.html";
our $fn = sprintf $fmt, $i;
open our $fh, ">", $fn or die $!;
print "opened $fnn";
while (<<>>) {
printf "read line $.: %sn", perlstring $_;
if (m{^.{0,10}?, Page (1 [^)]{0,10}?).</p>}) {
print "break matched line $.n";
$fn = sprintf $fmt, $i;
open $fh, ">", $fn or die $!;
print "opened $fnn";
}
print $fh $_;
}
С принтами:
$ perl chunker.pl page1.html
opened page1_0.html
read line 1: "<strong>Hello world</strong>n"
read line 2: "n"
read line 3: "<p>ABC, Page (1 whatever).</p>n"
break matched line 3
opened page1_1.html
read line 4: "<p>Some text</p>n"
read line 5: "n"
read line 6: "<p>DEF, Page (1 ummm what).</p>n"
break matched line 6
opened page1_2.html
read line 7: "<p>Some text</p>n"
read line 8: "n"
read line 9: "<p>THE<em><strong><span class="underline">GHI</span></strong></em>JK <em><strong><span class="underline">the</span></strong></em>LMNOP<em><strong><span class="underline">Q</span></strong></em>RS.<p> ABC, Page (1).</p>n"
read line 10: "n"
read line 11: "n"
$ for f in page1_*.html; do echo "$f:"; cat $f; echo; done;
page1_0.html:
<strong>Hello world</strong>
page1_1.html:
<p>ABC, Page (1 whatever).</p>
<p>Some text</p>
page1_2.html:
<p>DEF, Page (1 ummm what).</p>
<p>Some text</p>
<p>THE<em><strong><span class="underline">GHI</span></strong></em>JK <em><strong><span class="underline">the</span></strong></em>LMNOP<em><strong><span class="underline">Q</span></strong></em>RS.<p> ABC, Page (1).</p>
Я думаю, что проблема с вашим регулярным выражением заключалась в том, что вам нужно было не жадное сопоставление.
.{0,10}?
минимум от нуля до десяти
, Page (1
[^)]{0,10}?
минимум от нуля до десяти не закрывающих скобок
).</p>
затем закрытие
HTH
Комментарии:
1. Я запустил сценарий perl, и результаты состояли из page1_0.html (заголовок) и page1_1.html (остальная часть страницы).
2. Я просто повторил его с моим точным кодом из ответа и вашего образца текста, и я получил тот же результат. Вы пробовали это с точным примером текста из вашего вопроса?
3. Неважно. Я попробовал еще раз, и это сработало. Не уверен, что произошло в первый раз. Извините за это.
4. Вы также можете сжать это до однострочного, чтобы сделать это в командной строке.
Ответ №2:
^.{0,10}, Page (1.{0,10}).</p>
В чем проблема с моим регулярным выражением?
Это не форматирование POSIX. Попробуйте ^.{0,10}, Page (1.{0,10}).</p>
.
Это /
/
только потому, что он должен использоваться в качестве /REGEXP/[offset]
аргумента для csplit
инструмента. Возможно, вы захотите изменить это последнее .
.
значение на, чтобы оно соответствовало вашему символу точки.
Комментарии:
1. Я использовал
^.{0,10}, Page (1.{0,10}).</p>
и получил page1_0.html файл (только с заголовком hello world) и page1_1.html (вместе с остальной частью страницы).2. Что происходит с
[^>]*[^<]*
?3. После выполнения
^.{0,50}Page (1
я был более или менее в состоянии достичь того, что я пытался сделать.