ZSubSelector 的 interface,用来封装 Optional, Concatational 等 Rules 的接口
public interface ZSubSelector{
String parseNext(String s, int index);
String parseCurrent(String s, int index);
String getCurrentPattern();
boolean needEatBack();
boolean hasNext() ;
void reset();
int getOperator() ;
} |
public class ZMalFormedBNFException extends Exception{
public ZMalFormedBNFException(String s){
System.out.println("[ZMalFormedBNFException] " + s);
}
public ZMalFormedBNFException(int type){
System.out.println("[ZMalFormedBNFException] " + String.valueOf((char)type));
}
} |
增强性的 ZEnhancedSelector 的接口,给外面调用提供的
import java.util.*;
public interface ZEnhancedSelector extends ZSubSelector{
List parseNext2(String s, int index);
List parseCurrent2(String s, int index);
void next();
} |
import java.util.*;
static String namel;
public class HttpSession{
public static void main(String[] args)throws Exception{
String templ = "\"name=\" 1*16(OCTET) \" \" 1*32(OCTET) " +
"\"type=\" 1*16(OCTET) (\" \" / \">\")";
System.out.println(templ);
ZBNFSelector selector = new ZBNFSelector(templ);
String s = "<input name=pass size=12 type=password " +
"maxlength=\"8\" class=\"form1\">";
System.out.println(s);
Iterator it = selector.select2(s);
while(it.hasNext()){
List lst = (List)it.next();
System.out.println("$" + (String)lst.get(1) + "$" +
(String)lst.get(5) + "$");
}
}
|
ABNF 是 RFC2234 里面定义的一个字符串模式匹配的文法定义 (syntax),这个 syntax 在 RFC 的文档里面被广泛的引用,由此可见重要性,另外在实际的工作中间我们时常需要对表达式进行分析和模式匹配,所以我编了一个 ABNF 字符串匹配的程序 ..;)
我实现的 ABNF 和真正的 RFC2234 的 ABNF 模式不太一样,RFC2234 里面:字符串的顺序模式 (Concatational Rules,在正则表达式里面叫 Sequential Pattern 吧 ) 定义为 :element1 element2 element3 这样的形式,中间用 LWS(Linear White Space,就是 Tab 与空格的组合 ) 隔开 , 我的定义多了一个分组符号 (Gruping Rules):(element1 element2 element3) 一个字符串只有按顺序匹配了 element1 element2 element3 才是匹配了这个顺序模式
备选模式 (Optional Rules): element1 / element2 / element3
我也加了分组符号: (element1 / element2 / element3)
不过在 RFC2234 里面虽然备选模式没有分组符号,但是它强力推荐使用,这样使文法更加清晰而没有二义性一个字符串只要匹配了 element1, element2 或 element3 中间的任何一个就算匹配了这个备选模式
字符串 (Strings):"element"这个和我的一样,也适用双引号"来标志一个完整的字符串
重复模式 (Repetition):<m>*<n>element
为了清晰起见我改成了:m*n(element) 原来 RFC2234 里面还有省略形式的重复模式的,我把他们去掉了
范围选择模式 (Value range):m-n
省略号 (Comment):; element 这个我没有,不过要加应该也不难
在程序里面我定义了 ZConcatSelector 对应顺序模式,ZAlterSelector 对应备选模式,ZQuoteSelector 对应字符串模式,ZRepetSelector 对应重复模式,ZRangeSelector 对应范围选择模式
它们都继承了 ZSubSelector 这个接口,而由于最高一层的接口需要单独提出来,我特地定义了一个 ZEnhancedSelector 接口,在程序里面只有 ZConcatSelector 实现了这个接口
在 ABNF 分析的核心代码里面有一个 Factory Pattern 的应用,由于模版可以嵌套,整个 BNF 表达式是一个 Composite Pattern. 所以每个模版都可能有子模版,子模版的生成是由一个 Factory 统一产生的,每次需要产生子模版的时候就会调用 ZSubSelectorFactory 的 getSubSelector 方法得到一个子模版,这个工厂封装了生成各种模版的不同的参数和方法,这样每个模版都只知道工厂而对其他模版的生成细节不了解,程序的可维护性和扩展性比较好
在 ZSubsSelector 的 interface 里面有 parseNext 方法,实际上这个方法就暗示了 Composite Pattern 的存在,一个非叶节点的模版会调用每个子模版的 parseNext 方法得到匹配的字符串,每个叶结点如 ZQuoteSelector 直接比较内部的数据返回比较值
为了能得到一个用户制定模版里面的每个域的长度,在 ZEnhancedSelector 接口里面定义了新的方法 parseNext2 返回的是一个 List,里面是对应用户各个域的匹配出的字符串,免得用户进行第二次处理用户使用的 class 最后是 ZBNFSelector,这个类相对简单,用户传进去一个 BNF 表达式作为匹配的模版,然后调用 select 返回多个匹配的字符串或者调用 select2 返回一个迭代器,迭代器里每个元素是一个 List,让用户可以直接得到每个域的匹配字符串