Стековая переменная - новая возможность в Proxomitron Naoko-4. Нормально Proxomitron поддерживает 10 переменных от \0 до \9. В большинстве случаев этого достаточно, но может случится, что вам понадобится больше.
Например, использование выражений "+" и "++" совпадения с повторяющейся последовательностью совпадений. Что если вы захотите забрать каждый встретившийся элемент в отдельную переменную? Взгляните на пример, который совпадает с каждой частью пути URL:
http://(*/)+*.html
Часть выражения (*/)+ ищет совпадение для каждого участка URL, но как сохранить каждую часть в отдельную переменную? Для этого используем cтековую переменную. Он использует специальный символ "\#", который по аналогии с \0...\9 сохраняет совпавшее значение. Однако при каждом вызове он сохраняет его в "стек", который может содержать до 100 элементов. Он может быть использован в тексте замены для извлечения элементов из стека по принципу "первый пришел - первый ушел". Используя эту переменную, мы можем переписать выражение выше так:
http://(\#/)+\#.html
... а затем использовать замещающий текст так:
"\# \# \# \# \# \# \#"
Который преобразует URL вида:
http://this/is/a/test/of/the/stack.html
в строку:
"this is a test of the stack.html"
Каждый вызов (...)+ помещает помещает новое значение в стек, затем что-нибудь еще, совпавшее с последним "\#". Также, как и другие позиционные переменные, стековая переменная может быть использована непосредственно после скобок, при этом сохраняется содержимое скобок. Например:
http://(*/)\#+\#
создаст строку:
"this/ is/ a/ test/ of/ the/ stack.html"
Текст замены также распознает другой специальный эскейп - "\@". Он просто сбрасывает все содержимое стека по порядку (подобно использованию \#\#\#\#\#...). Фактически, это вы и будете использовать в большинстве случаев.
Совершенно другой путь предполагает использование \# подобно \1 \2 \3 и т.д., за исключением того, что каждый раз при вызове переменной, новые значения добавляются в ее конец, а не заменяют ее. Далее мы рассмотрим несколько примеров.
Bounds: Matching: Replace: |
<Sometag\s*> (\#(attr1|attr2|attr3)=$AV(*))+ \# \@ |
1. Первый раз \# ловит текст до первого удаляемого атрибута.
2. Последующие проходы ловят текст между текущим и последующим атрибутом.
3. Последний \# ловит все то, что осталось после последнего атрибута или весь тег, если совпадений найдено не было.
Bounds: Matching: Replace: |
<Sometag\s*> (*((attr1|attr2|attr3)=$AV(*) )\#)+ * <Sometag \@> |
Этот пример противоположен предыдущему, но очень похож. Он отбрасывает все, за исключением атрибутов, которые вы хотите сохранить. здесь только одна переменная, сохраняющая атрибут и его значение.
Bounds: Matching: Replace: |
<Sometag\s*> (\#((attr1=)\#foo$SET(\#=bar)| (attr2=)\#black$SET(\#=white)| (attr3=)\#one$SET(\#=zero)))+ \# \@ |
Этот пример несколько сложнее. Он использует команду $SET(\#=...) совместно с нормальным выражением. Это позволяет делать интересные вещи.
Пример выше сначала смотрит, не совпадает ли один из атрибутов. Если такой будет найден, его имя помещается в стек и затем пытается найти совпадение со значением атрибута. Если оно будет найдено, то используется команда SET, которая помещает новое значение в переменную. Дополнительно, сохраняется все, что не совпало с выражением. Вы даже можете взять замену для отдельных значений из списка:
(\#$LST(AttributeReplace))+ \#
Со списком элементов:
# # Sample attribute replacement list # (attr1=)\#foo$SET(\#=bar) (attr2=)\#black$SET(\#=white) (attr3=)\#one$SET(\#=zero)
или даже:
# # Sample attribute replacement list two # attr1=foo $SET(\#=attr1=bar ) attr2=black $SET(\#=attr2=white ) attr3=one $SET(\#=attr3=zero )
для выборочной замены как атрибута, так и значения. (Кстати, это даже лучше, поскольку элементы списка индексируются и поиск происходит быстрее.)