级别: 初级 张 磊 (raphaelzl@263.net), 软件工程师, 银河网络公司
2001 年 4 月 12 日 ABNF是RFC2234里面定义的一个字符串模式匹配的文法定义(syntax),这个syntax在RFC的文档里面被广泛的引用,由此可见重要性,另外在实际的工作中间我们时常需要对表达式进行分析和模式匹配,本文给出一个ABNF字符串匹配的程序。
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() ;
} |
ZMalFormedBNFException异常
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();
} |
实现ABNF分析的核心代码和类工厂
源码清单
外部调用使用的类
源码清单
一个简单的例子程序
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,让用户可以直接得到每个域的匹配字符串
关于作者  | |  | 张磊,现在是银河网络公司的一个软件工程师,近一段时间主要开发的是基于Java的网络通信程序,其中包括文件传输和实时消息传输。在此之前是清华大学电子工程系的学生,主要方向是TCP/IP网络原理和程序编制,还有数字信号变换。 |
对本文的评价
|