Сначала первое: ни это , ни это , ни это не отвечали на мой вопрос. Поэтому я открою новый.
Ладно ладно. Я знаю, что регулярные выражения не являются способом анализа общего HTML. Обратите внимание, что созданные документы записываются с использованием ограниченного контролируемого подмножества HTML. И люди, пишущие документы, знают, что они делают. Это все ИТ-специалисты!
Учитывая управляемый синтаксис, можно проанализировать документы, которые у меня есть здесь, с помощью регулярных выражений.
Я не пытаюсь загружать произвольные документы из Интернета и разбирать их!
И если разбор не выполняется , документ редактируется, поэтому он будет разбираться. Проблема, которую я здесь рассматриваю, более общая, чем эта (т. Е. Не заменять шаблоны внутри двух других шаблонов).
В нашем офисе мы должны «печатать» нашу документацию. Поэтому почему некоторые придумали все это в документы Word. До сих пор мы, к счастью, еще не совсем там. И, если я это сделаю, нам может не понадобиться.
Основная часть документов хранится в базе данных TikiWiki. Я создал плотный PHP-скрипт, который конвертирует документы из HTML (через LaTeX) в PDF. Одним из необходимых свойств выбранной Wiki-системы был редактор WYSIWYG. Что, как и ожидалось, оставляет нам документы с менее формальным DOM.
Следовательно, я транслитерирую документ, используя «простые» регулярные выражения. Пока все работает (в основном), но я столкнулся с одной проблемой, которую еще не выяснил сам.
Некоторые специальные символы необходимо заменить на разметку LaTeX. Для exaple символ \
должен быть заменен на $\backslash$
(если кто-то не знает другое решение?).
Кроме того, в то время как в verbatim
!
Я заменяю теги <code>
на verbatim
разделы. Но если этот блок code
содержит обратную косую черту (как в случае с именами папок Windows), сценарий все еще заменяет эти обратные косые черты.
Я считаю, что могу решить это, используя отрицательные LookBehinds и / или LookAheads. Но мои попытки не сработали.
Конечно, мне было бы лучше с реальным парсером. Фактически, это что-то в моей «мозговой карте», но в настоящее время она выходит за рамки. Скрипт работает достаточно хорошо для нашей ограниченной области знаний. Создание парсера потребует от меня начать с нуля.
The Hello \ World document is located in: <code>C:\documents\hello_world.txt</code>
The Hello $\backslash$ World document is located in: \begin{verbatim}C:\documents\hello_world.txt\end{verbatim}
Это лучшее, что я мог придумать до сих пор:
<?php $patterns = array( "special_chars2" => array( '/(?<!<code[^>]*>.*)\\\\[^$](?!.*<\/code>)/U', '$\\backslash$'), ); foreach( $patterns as $name => $p ){ $tex_input = preg_replace( $p[0], $p[1], $tex_input ); } ?>
Обратите внимание, что это только отрывок, а [^$]
– другое требование LaTeX.
Еще одна попытка, которая, казалось, работала:
<?php $patterns = array( "special_chars2" => array( '/\\\\[^$](?!.*<\/code>)/U', '$\\backslash$'), ); foreach( $patterns as $name => $p ){ $tex_input = preg_replace( $p[0], $p[1], $tex_input ); } ?>
… другими словами: уклонение от негативного взгляда.
Но это выглядит более подверженным ошибкам, чем с lookbehind и lookahead.
Как вы, возможно, заметили, шаблон неровный ( /.../U
). Так будет ли это соответствовать как можно меньше внутри блока <code>
? С учетом взглядов?
Если я, я попытаюсь найти HTML-парсер и сделаю с этим.
Другой вариант – попытаться вырезать строку в <code>.*?</code>
и другие части .
и будет обновлять другие части и будет рекомбинировать его.
$x="The Hello \ World document is located in:\n<br> <code>C:\documents\hello_world.txt</code>"; $r=preg_split("/(<code>.*?<\/code>)/", $x,-1,PREG_SPLIT_DELIM_CAPTURE); for($i=0;$i<count($r);$i+=2) $r[$i]=str_replace("\\","$\\backslash$",$r[$i]); $x=implode($r); echo $x;
Вот результаты.
The Hello $\backslash$ World document is located in: C:\documents\hello_world.txt
Извините, если мой подход не подходит для вас.
Я считаю, что могу решить это, используя отрицательные LookBehinds и / или LookAheads.
Вы ошибаетесь. Регулярные выражения не заменяют синтаксический анализатор .
Я бы предложил вам передать html через htmltidy, затем прочитать его с помощью dom-parser, а затем преобразовать dom в ваш целевой формат вывода. Есть ли что-то, препятствующее вам пройти этот маршрут?
Parser FTW, хорошо. Но если вы не можете использовать парсер, и можете быть уверены, что теги <code>
никогда не вложены, вы можете попробовать следующее:
<code>.*?</code>
вашего файла (возможно, вам нужно включить режим «Точечные совпадения-новые строки»). #?#?#?#
$\backslash$
<code>
на \begin{verbatim}
и все </code>
на \end{verbatim}
#?#?#?#
\
FYI, регулярные выражения в PHP не поддерживают переменную длину lookbehind. Таким образом, это затруднение условного совпадения между двумя границами.
Pandoc? Pandoc конвертирует между кучей форматов. вы также можете объединить кучу мух вместе, а затем скрывать их. Может быть, несколько сценариев оболочки в сочетании с вашими скриптами scpping php?
С вашим «ожидаемым вводом» и командой pandoc -o text.tex test.html
вывод:
The Hello \textbackslash{} World document is located in: \verb!C:\documents\hello_world.txt!
pandoc может читать из stdin, писать в stdout или напрямую в файл.
Если ваши блоки <code>
не вложены, это регулярное выражение обнаружит обратную косую черту после ^
начала строки или </code>
без <code>
между ними.
((?:^|</code>)(?:(?!<code>).)+?)\\ | | | | | \-- backslash | \-- least amount of anything not followed by <code> \-- start-of-string or </code>
И замените его на:
$1$\backslash$
Вы должны запустить это регулярное выражение в режиме «singleline», так что .
соответствует новым строкам. Вам также придется запускать его несколько раз, указав глобальную замену недостаточно. Каждая замена заменяет только первую допустимую обратную косую черту после начала строки или </code>
.
Напишите парсер на основе анализатора HTML или XML, такого как DOMDocument . Пройдите анализируемую DOM и замените \
на каждый текстовый узел, который не является потомком узла code
с $\backslash$
и каждым узлом, который является узлом code
с \begin{verbatim} … \end{verbatim}
.