IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Java technology  >

ABNF 模式字符串匹配

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 初级

张 磊 (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网络原理和程序编制,还有数字信号变换。




对本文的评价










回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款