Правила сравнения текста - наиболее сложная часть Proxomitron. Их понимание может быть поначалу затруднительным, особенно если вы никогда прежде не использовали языки сравнения текста. Однако, не отчаивайтесь, даже очень простые правила могут делать достаточно много. Преодолейте эту ступеньку - и скоро это станет вашей второй натурой. Для начала, здесь даны несколько советов, охватывающих некоторые основы HTML, соответствующие нашим задачам.
Обратите внимание: Этот раздел предполагает, что вы знаете немного о HTML. Если нет, то есть много превосходных обучающих программ, доступных в сети. Если же вы не намереваетесь писать свои собственные правила, то можете проигнорировать эту информацию полностью.
Сложные правила соответствия часто бывают весьма трудночитабельны. Чтобы сделать их немного понятнее, выражения соответствия и текст замены могут быть разбиты на несколько строк. Разрывы строк игнорируются в выводе. Чтобы явно включить разрыв в текст замены или выражение соответствия, используйте "\n".
Поскольку пробелы всегда соответствуют истине, вы можете использовать их свободно для разделения элементов выражения соответствия. Только учитывайте, что они поглощают все последовательно идущие пробелы, которые находят.
При разработке нового правила руководствуйтесь тем, что лучше "не соответствовать вообще" чем "соответствовать слишком многому". Всегда начинйте с простого, а затем усложняйте по мере необходимости. И в случае, когда правило внезапно не работает так, как вы ожидали, вы будете представлять, в какой части возникли проблемы.
Журнал поможет узнать, когда фильтр рабтает, а опция "HTML debug info" в меню журнала (можно также набрать "dbug.." перед именем хоста) покажет исходный код страницы и результат работы фильтров. Это два очень полезных инструментальных средства для разработки правил. Еще более полезное - тестовое окно, которое позволяет вам точно увидеть, как фильтр изменит текст HTML.
Часто хороший способ начать новый фильт состоит в том, чтобы скопировать и вставить интересующий вас HTML непосредственно в верхнее окно для исходного текста. Здесь важно не упустить одну вещь - поскольку тестовое окно игнорирует разрывы строк, то строка HTML, подобная этой:
<br>
<p>
кажется точно такой же, как "<br><p>". Это может создать проблемы, так как фактический HTML также имеет символ новой строки, который должен быть учтен в правиле. Это решается простым размещением пробела в начале или конце каждой строки (если она уже не имеет одного), это будет соответствовать всем "белым пространствам", включая любые новые строки.
Так как браузеры игнорируют любые тэги и их элементы, которые не понимают, то "быстрый и грубый", но эффективный способ отключить тэг или один из его элементов состоит в том, чтобы переименовать его. Это становится особенно полезно, когда тот же самый элемент может использоваться несколькими различными тэгами. Возьмите, например, "onload", этот элемент автоматически запускает JavaScript. Хотя его нормальное местоположение в тэге "<body ... >", он может находится также в другом месте. Чтобы отключить его, вы можете использовать:
Соответствие: | onload = |
Замена: | LoadOff = |
Это правило будет заменять тэг подобный такому:
<body background="bak.gif" onload="window.open(myadd);">
на такой:.
<body background="bak.gif" LoadOff="window.open(myadd);">
Заметьте, какое простое это правило! Однако оно становится немного рискованным, когда появляется шанс, что фраза "оnload = " может появиться вне тэга в тексте web-страницы. Практически однако это редко случается (включение знака равенства частично защищает от этого). Но даже если это произошло, до тех пор, пока вы понимаете что случилось, это не так страшно.
Вот простая уловка для изменения начала и конца тэга в одном правиле. Эта уловка используется в правиле "Blink to Bold" (преобразование мигающего текста в полужирный). В этом правиле мы хотим преобразовать <blink> в <b> и </blink> to </b>. Давайте посмотрим, как это сделано:
Соответствие: | <\1blink> |
Замена: | <\1b> |
Используя мета-символ "\1", правило будет соответствовать обоим тэгам: "<blink>" и "</blink>". Дополнительно, "\1" сохраняет "\" конечного тэга для использования в тексте замены. Более безопасная, но и более сложная версия правила могла бы быть:
Соответствие: | < ( / | )\1 blink> |
Замена: | <\1b> |
Вы можете сказать почему? Если нет, прочтите абзац "Проверка на что-то или на ничто".
Рано или поздно, вы вероятно захотите изменить только один элемент тэга при сохранении всего остального. Это как раз тот случай, когда числовая переменная " \#" очень полезна. Следующий пример - правило, уничтожающее фоны web-страницы.
Соответствие: | <body \1 background=\w \2 > |
Замена: | <body \1 \2> |
Когда они непосредственно не следуют за круглыми скобками (...), переменные \# действуют точно так же, как звездочка "*". Здесь, "\1" сохраняет всё перед элементом фона, в то время, как "\2" сохраняет всё последующее. В тексте замены фоновый элемент просто не учтен, но вы можете включить здесь ваш собственный фон.
А это быстрая уловка, как добавить элемент к тэгу. Хотя "надлежащий" метод состоял бы в том, чтобы заменить элемент, если он уже существует и добавить его, только если он не существует, это может иногда быть затруднительно. Часто проще добавить элемент независимо. Мы только должны удостовериться, что браузер будет использовать наш тэг вместо любого существовавшего ранее. Например, чтобы добавить границу ко всем "<img ... > " тэгам, вы можете использовать:
Соответствие: | <img \1 > |
Замена: | <img border=1 \1 border=1> |
Зачем добавлять границу дважды? Было бы идеально, если бы браузер находил повторяющийся элемент, использовал первый и игнорировал остальное. Фактически, это то, что делает Netscape , но как оборачивается, Internet Explorer делает все наоборот! (удивлены?). Помещая элемент в начале и конце тэга, мы можем быть уверены, что это сработает в любом случае. Обратите внимание, что независимость от браузера не столь важна здесь, как для разработки web-страниц. Вы, вероятно, будете знать, какой браузер будете использовать, так что достаточно только расположить всё в порядке, ожидаемом вашим броузером.
Значения атрибутов тэга часто могут создавать сложности для сравнения. Возьмите "<href = ... >", например. "href" указывает URL, но значение URL может быть окружено одиночными кавычками, двойными кавычками или даже не иметь кавычек вообще. В этом случае может пригодиться специальная команда $AVQ(...). Она будет соответствовать всему значению, включая любые кавычки, которые будут найдены. Например, если вы хотите сохранить URL в переменную \1, вы можете использовать:
<a * href=$AVQ(\1) * >
Помните, что когда переменная следует сразу за круглой скобкой, то в ней сохраняется любой текст соответствующий выражению в круглых скобках. Скажем, вы хотите сохранить только то значение, что содержит определенную фразу. Сделать это можно при помощи скобок (...) и команды $AV(...):
<a * href=( $AV(*(banner|advert|cgi)*) )\1 * >
Выражение будет соответствовать только URL, содержащим слова "banner", "advert", или "cgi". Мы теперь имеем основу правила типа "banner blaster".
Вероятно, вы захотите, чтобы выражение соответствовало в зависимости от наличия специфического значения. Это делается при использовании следующего правила:
"(что-нибудь|)"
Сначала будет проверено слово "что-нибудь", но если оно не найдено, выражение останется истинным. Почему? Заметьте, что здесь есть символ ИЛИ (вертикальная полоса) ни с чем между ним и заключительной круглой скобкой. Это создает пустое выражение, а пустое выражение всегда истинно и не поглощает никаких символов. Читайте это так - соответствие "чему-нибудь" ИЛИ ничему.
Обратите внимание, что, если бы выражение было написано "(|что-нибудь)", слово "что-нибудь" никогда не участвовало бы в сравнении! Поскольку символы ИЛИ обрабатываются слева направо, пустое выражение всегда соответствовало бы перед словом "что-нибудь".
Практический пример - (" |) * (" |), который проверяет на что-нибудь, что может или не может быть окружено кавычками. Вот более сложный пример, который захватывает значение "border" из "<img ... >" тэга, если оно существует и размещает его в переменной \1
<img ( * (border=\w)\1 | ) * >
Будьте осторожны в размещении звездочек, например "<img*(border=\w|)\1*>" не сможет сделать то, что вы ожидаете. Если то, что идёт после просмотра первого символа после "<img" не "border", то подвыражение всё еще будет соответствовать! Затем, когда "border" появился бы позже в строке, он был бы согласован вместо этого со второй звездочкой, так как начальное испытание уже прошло.
Используя "&" вы можете сохранять некоторые признаки тэга независимо от порядка, в котором они найдены. Например, скажем вы хотите перезаписать "< img ... >" тэг, чтобы он содержал ваше собственное изображение, но хотели сохранить первоначальные значения "width" and "height". Вы можете использовать:
Соответствие: |
<img ( (*(height=\w)\1*| ) & (*(width=\w)\2*| ) ) > |
Обратите внимание, что высота сохранена в переменную \1, а ширина в \2. Также, используя синтаксис "что-нибудь или ничто", описанный выше, выражение все еще будет соответствовать, даже если значения ширины или значение высоты отсутствуют в тэге. В этом случае соответствующие переменные \# останутся пустыми.
Чаще всего, "\w" хорошо работаетдля сохранения атрибутов тэгов. Однако может оказаться, что вам потребуется нечто большее. "alt" элемент тэга "<img ... >" часто содержит пробелы как в ... alt = "некоторый текст" или alt ='также некоторый текст'. Для сохранения такого рода вещей используют двойные кавычки:
Соответствие: alt=( " * " )\1
Еще более сложные ситуации часто возникают с JavaScript. Здесь обычно имеются "кавычки в кавычках":
onmouseover="javascript:window.open( ' mywindow.html ' ); "
Сохранение этого выражения может быть затруднительным, поскольку оно может быть также записано:
onmouseover= ' javascript:window.open( " mywindow.html " ); '
В этом случае удобно использовать одиночную кавычку, которая ищет правильную заключительную кавычку для предыдущей стартовой кавычки. Возьмем следующее правило, которое может использоваться практически для любого значения:
Соответствие: onmouseover=( " * ' | \w )\1
Это соответствие определяет одиночные кавычки, двойные кавычки, вложенные кавычки или даже отсутствие кавычек вообще! Тем не менее, есть еще лучший путь - помните команду $AVQ( )? Она также поддерживает все типы кавычек (и их отсутствие), и особенно удобна для сохранения значений.
Matching: onmouseover=$AVQ(\1)
"Файловым URL" является URL, который указывает на файл на вашем жестком диске, а не на местоположение в Internet. Броузеры используют файловые URL для автономного просмотра web-страниц, сохраненных в кэше, но это также очень удобный способ вставить ваши собственные изображения, web-страницы и даже JavaScript в просматриваемые страницы.
Proxomitron теперь делает вставку файловых URL в текст замены очень простым делом. Сначала установите курсор на место, куда вы желаете вставить URL, щелкните правой кнопкой мыши и выберите "Insert file URL" из контекстного меню. Далее просто выберите нужный файл в открывшемся диалоге.
Далее показан пример правила "background replacer", которое использует файловый URL:
Соответствие: |
<body ( \1 background=\w | ) \2 > |
Обратите внимание, что выражение соответствия имеет пробел между ")" и "\2", это общая ошибка, забыть про этот пробел! Без пробела в \2 будет содержаться то, что соответствует содержимому скобок "(...)", вместо того, что следует за атрибутом фона.
Это уловка позволит вам полностью взять web-страницы под свой контроль. JavaScript может быть очень мощным инструментом - в правильных руках... Теперь эти руки могут быть вашими собственными! Чтобы вставить JavaScript или что-нибудь еще в каждую web-страницу, найдите тэг, который будет всегда там - "<html>", "<head>" или "<body>" часто являются хорошим выбором. Возьмите, например, правило, блокирующие основанные на JavaScript сообщения об ошибках. Для Netscape мы должны выполнить следующий участок кода JavaScript на каждой странице "<script> this.onerror=null; </script>" Правило должно выглядеть примерно так:
Соответствие: |
<html> |
Обычно скрипт вставляется непосредственно после <html> тэга. Обратите внимание на мета-символ "\n", который вставляет разрыв строки между <html> тэгом и началом скрипта. В этом нет особой необходимости, однако текст web-страницы становится более легким для чтения при проверке результатов. Также, при использовании этой уловки лучше установить переключатель "Allow for multiple matches". Это позволяет другим правилам, которые могут использовать ту же самую уловку, вставить также и их текст.
Также обратите внимание на использование команды $STOP( ). Она выключает фильтр до конца страницы, и дает уверенность, что скрипт будет вставлен только один раз (особенно важно, если вы также используете "multi-match").
Маленькие сценарии, подобные вышеописанному, могут быть легко быть включены непосредственно в тексте замены, но для больших сценариев это может быть неудобно. Пожалуй лучшее решение - иметь "<script ...>" тэг, содержщий "файловый URL", указывающий на файл с фактическим сценарием. Например:
<html>\n<script src= "file://c|/scripts/myscript.js" >
Я сперва описал вышеупомянутый метод, потому что это - полезная уловка, когда вам нужно вставить что-нибудь в произвольную область страницы (например после тэга <body ... >). Однако, если всё, что вы хотите вставить, размещается в начале или конце страницы, есть более легкий путь...
Выражение соответствия может иметь два специальных значения <start> и <end> - они просто вставляют текст замены в начало или конец web-страницы. Они удобны и очень эффективны, так как не требуется никакого поиска. При использовании <start> вышеупомянутое правило можно записать:
Соответствие: |
<start> |
Это прекрасно работает с JavaScript (и отключает функции JavaScript - см. ниже). Также нет никакой необходимости волноваться об учете многократных соответствий!
В Netscape и Internet Explorer 4.0+ есть очень эффективная уловка для преобразования JavaScript. Любые функции JavaScript - даже встроенные - могут переопределяться и делать то, что мы хотим. Скажем, мы хотим избавиться от сообщений типа "alert( ... )" и "confirm( ... )". Мы можем сделать это, просто вставляя следующий скрипт в начале web-страницы (используя <start>):
<script>
function alert( ){ return(1); }
function confirm( ){ return(1); }
</start>
Теперь всякий раз, когда любой другой скрипт на странице попытается вызывать предупреждение или окно подтверждения, вместо них будут вызываться наши функции. Возвращая "1" мы даже заставляем ни о чем не подозревающий скрипт думать, что мы ответили "да" на запрос окна подтверждения!
Это действительно очень мощная концепция. И хотя функции в этом примере не делают ничего, более сложные функции замены могут фильтровать только определенные предупреждающие окна или что-нибудь еще. Нет действительно никакого предела.
Это настолько эффективно, что заданные по умолчанию правила Proxomitron'a широко используют эту уловку. Единственный недостаток - всё это работает с большинством версий Netscape и IE 4.0 или выше, но не будет работать с JScript в IE 3.x. Proxomitron предусматривает дополнительный набор правил для пользователей IE 3.0, который использует нормальные методы поиска и замены, чтобы сделать эти вещи.
Рекурсивное соответствие - это когда правило может искать соответствие в своих собственных результатах. Обычно этого следует избегать, особенно если это ведет к бесконечной рекурсии, когда правило работает бесконечно. Однако, при использовании этой методики должным образом, можно достичь неплохих результатов. Возьмите этот сценарий - скажем, вы хотите устранить любые всплывающие окна, встретившиеся между "<script ..." и "</script>" тэгами. Поскольку JavaScript использует команду "open(...)", чтобы открыть всплывающее окно, правило могло бы иметь вид:
Соответствие: |
<script \1 open \( * \) \2 </script> |
(В действительности, вы также захотите использовать здесь пределы, но мы обсудим это позже. Обратите также внимание на использование "\", для отмены специального значения круглой скобки). Это правило могло бы работать, если была бы только одна команда "open" в JavaScript, но если их больше, то только первая была бы устранена. Решение? Сначала включите опцию "Allow for multiple matches", что позволит правилу использовать его собственные результаты. Во-вторых, мы должны изменить текст замены таким образом:
Замена: \n<script \1 \2 </script>
Почему? Чтобы избежать случайной бесконечной рекурсии, механизм сравнения текста Proxomitron'a всегда продвигает один символ вперед после того, как все правила были проверены. Это означает, что в следующий раз наше правило увидит только"script ..." в отличие от "<script ...". Чтобы обойти это, мы просто вставляем символ новой строки перед текстом замены. В финальном выводе это создаст пустую строку перед тэгом "<script ...", которую броузер благополучно проигнорирует. Однако это позволит в следующий раз правилу опять видеть "<script ...". Также может быть использован пробел, фактически это может быть что угодно, не затрагивающее функционирование web-броузера. Идея в том, чтобы просто поместить по крайней мере один символ перед полным результатом.
Как только все команды "open(...)" будут удалены, правило больше ничего не найдет, так что никакой опасности бесконечной рекурсии нет.
Proxomitron имеет возможность, называемую "стековая переменная". Она использует переменную \# для сбора нескольких значений. Переменная \# работает аналогично переменным \0 ... \9 и может помещаться в те же места. Различие в том, что она вызывается многократно - в циклах или используя ее несколько раз - значение помещается в конец переменной, не замещая предыдущих значений. Используя эту переменную, вы можете использовать соответствие нескольким элементам, не опасаясь рекурсии:
Соответствие: |
<script (\#.open \( * \))+ \# </script> |
Здесь мы создаем цикл, используя плюс после скобок: "(...)+". Цикл будет повторяться до тех пор, пока может находить совпадения с содержимым скобок. Данный цикл ищет команды ".open()". Все, что перед "open" помещается в первую \# и с повторением цикла, все что находится перед следующим "open" добавляется в \#. Это продолжается до тех пор, пока закончатся все "open". Затем, все что останется после, также помещается в \#.
Таким образом, мы сохранили все между двумя скриптовыми тегами за исключением команд "open". В тексте замены мы просто вызываем \@, которая сбросит все сохраненное содержимое \#. Эффект аналогичен рекурсивному соответствию, но более надежен и менее опасен (поскольку исключена возможность бесконечного цикла).
Для простоты, приведенные здесь примеры не используют установки "scope bounds" web-фильтров. Границы могут использоваться для управления глубиной поиска соответствия при просмотре Proxomitron'ом web-страницы (подробнее см. в разделе редактор фильтров web-страниц).
В случае с границами вы обычно даете правилу фиксированные стартовые и конечные точки, между которыми будет производиться поиск. Используя вышеприведенный пример, возьмем следующее правило:
Соответствие: |
<script \1 open \( * \) \2 </script> |
При записи с границами это может выглядеть так:
Границы: |
<script\s*</script> |
Заметьте, что мы только перемещаем фиксированный начальный и оконечный текст в проверку границ поиска. Byte Limit - максимальное число символов, которое будет просмотрено перед отказом от поиска. Также мы использовали \1 и \2 в выражении соответствия для сохранения начала и конца того, что находится в границах - включая <script и </script>. Так что нам больше не требуется помещать их в текст замены.
Это все советы, которые я могу придумать на данный момент. Если у вас есть собственные идеи, пожалуйста сообщите мне. Также помните, что вы можете посмотреть правила, которые идут с Proxomitron'ом! Используйте их как отправную точку при написании новых правил - весьма вероятно, что подобное правило уже существует.