替换堆栈
Previous Back to contents Next

"替换堆栈" 是在 Proxomitron Naoko4 里引入的新功能。Proxomitron 支持十个匹配变量 \0\9,一般来说是够用的。不过仍然不能完全满足需求。

例如,使用 "+" 或 "++" 表达式循环匹配时,如果你想要把搜索到的每项都存入不同的变量的话怎么办?以下面这个匹配 URL 路径的规则为例...

http://(*/)+*.html

(*/)+ 部分会匹配 URL 的每个部分,但怎么才能把这些捕获到的部分存入不同的变量?这就是替换堆栈出场的时候了。它像 "\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: <Sometag\s*>
Matching: (\#(attr1|attr2|attr3)=$AV(*))+ \#
Replace: \@

  1. 第一个 "\#" 会捕获第一个需要移除的属性之前的所有文本(如果有的话)
  2. 然后下面的循环会匹配所有需要移除的属性和属性值。
  3. 最后的 \# 会循环匹配完后的剩下的文本;如果循环没有任何匹配,这个 \# 则会匹配整个标签。

只保留需要的属性 (移除其他任何东西):

Bounds: <Sometag\s*>
Matching: (*((attr1|attr2|attr3)=$AV(*) )\#)+ *
Replace: <Sometag \@>

这和刚才的例子用途相反,但语法上非常接近。它会去掉除了需要的属性和属性值以外的所有东西。这里我们只用一个 \# 就捕获了全部。

替换属性值:

Bounds: <Sometag\s*>
Matching: (\#((attr1=)\#foo$SET(\#=bar)|
(attr2=)\#black$SET(\#=white)|
(attr3=)\#one$SET(\#=zero)))+ \#
Replace: \@

这个规则有一点点复杂。注意它在普通匹配中使用了 $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 ) 

来有选择性地同时替换属性和属性值(事实上因为名单可以被索引,这种方法会匹配更快,效果更好)。


返回目录