当柳上原的风吹向天际的时候...

真正的快乐来源于创造

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  368 Posts :: 1 Stories :: 201 Comments :: 0 Trackbacks
编程中有时需要将一段文本分解成标记,比如说14+2*3需要变成14,+,2,*,3的样式,再比如说select a from b,需要变成select,a,from,b的形式,要写出这样的代码不难,考虑到通用性,于是我制作了下面这个通用类,用户只需要指定合法字符和分隔字符的正则表达式,程序即能将字符串分解成标记并注明类型,下面是源码:

1.用于表示标记的Token类,含有文本和类型两个属性:
package com.heyang.tokenmaker;

/**
 * 标记类,内含文本及类型
 * 说明:
 * 作者:heyang(heyang78@gmail.com)
 
*/
public class Token{
    
// 有效内容类型
    public static final String Type_Content="Content";
    
    
// 分隔符类型
    public static final String Type_Separator="Seperator";
    
    
// 标记文本
    private String text;
    
    
// 标记类型
    private String type;
    
    
/**
     * 构造函数
     * 
@param text
     * 
@param type
     
*/
    
public Token(String text,String type){
        
this.text=text;
        
        
if(type.equals(Type_Content) || type.equals(Type_Separator)){
            
this.type=type;
        }
        
else{
            
throw new IllegalArgumentException(type+"不是有效的类型。");
        }
        
    }

    
public String getText() {
        
return text;
    }

    
public String getType() {
        
return type;
    }
}

2.用于分解的TokenMaker类:
package com.heyang.tokenmaker;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;

/**
 * 传入一个字符串,将它转化为记号放在链表中
 * 说明:
 * 作者:何杨(heyang78@gmail.com)
 
*/
public class TokenMaker{
    
// 来源字符串
    private String sourceString;
    
    
// 用正则表达式表示的,表示单个有效字符的字符串,注意这个是表示合法单字字符的正则表达式
    private String validPatten;
    
    
// 用正则表达式表示的,表示单个分隔符的字符串,注意这个是表示合法单字字符的正则表达式
    private String separatorPattern;
    
    
// 记号链表
    private List<Token> tokens;
    
    
/**
     * 构造函数
     * 
@param sourceString
     * 
@param validPatten
     * 
@param seperatorPattern
     * 
@throws Exception
     
*/
    
public TokenMaker(String sourceString,String validPatten,String seperatorPattern) throws Exception{
        
this.sourceString=sourceString;
        
this.validPatten=validPatten;
        
this.separatorPattern=seperatorPattern;
        
        findTokens(sourceString);
    }
    
    
/**
     * 找到指定的标记并放入链表中
     * 
     * 说明:
     * 
@param sourceString
     * 
@throws Exception
     
*/
    
private void findTokens(String sourceString)throws Exception{
        tokens
=new ArrayList<Token>();
        
        sourceString
=sourceString.toString();
        
final String End = "~";// 结束标志,这个地方注意与有效文本差别化
        sourceString+=End;// 加上结束标志
        
        
// 单词,用来累加字符
        String word = "";
        
        
for (int i = 0; i < sourceString.length(); i++) {
            
// 取得每个字符
            String str = String.valueOf(sourceString.charAt(i));
            
            
if(End.equals(str)){
                
// 将word放入链表
                addTokenToList(new Token(word,Token.Type_Content));
                
break;
            }
            
            
// 字符的验证
            if(isValid(str)==false){
                
throw new Exception(""+this.sourceString+"找到非法的字符'"+str+"',无法进行求值.");
            }

            
// 判断是否空格
            if (StringUtils.isBlank(str)) {
                
if (word.trim().length() < 1) {
                    
// 碰到空格而word中没有字符则从头再来
                    continue;
                } 
else {
                    
// 将word放入链表
                    addTokenToList(new Token(word,Token.Type_Content));

                    
// 然后吧word置空后继续累加
                    word = "";
                }
            } 
            
else if(isSeparator(str)){
                
// 将word放入链表
                addTokenToList(new Token(word,Token.Type_Content));
                
                
// 将符号放入链表
                addTokenToList(new Token(str,Token.Type_Separator));

                
// 然后吧word置空后继续累加
                word = "";
            }
            
else {
                
// 不是则继续累加
                StringBuilder sb=new StringBuilder(word);
                sb.append(str);
                word
=sb.toString();
                
                
//word += str;
            }
        }
    }
    
    
/**
     * 将标记添加到标记链表
     * 
     * 
@param token
     
*/
    
private void addTokenToList(Token token){
        
if(token.getText().trim().length()>0){
            tokens.add(token);
        }
    }
    
    
/**
     * 打印链表中的标记
     * 
     
*/
    
public void printTokens(){
        System.out.println(
"\n将文字"+sourceString+"转化后的标记为:");
        System.out.println(
"序号\t内容\t类型");
        System.out.println(
"-------------------------");
        
        
int index=1;
        
        
for(Token token:tokens){
            System.out.println((index
++)+"\t"+token.getText()+"\t"+token.getType());
        }
    }
    
    
/**
     * 判断是否有效字符
     * 
     * 说明:
     * 
@param str
     * 
@return
     
*/
    
private boolean isValid(String str){
        Pattern p 
= Pattern.compile(validPatten,Pattern.CASE_INSENSITIVE);
        Matcher m 
= p.matcher(str);
        
return m.find();
    }
    
    
/**
     * 判断是否分隔符
     * 
     * 说明:
     * 
@param str
     * 
@return
     
*/
    
private boolean isSeparator(String str) {
        Pattern p 
= Pattern.compile(separatorPattern,Pattern.CASE_INSENSITIVE);
        Matcher m 
= p.matcher(str);
        
return m.find();
    }
    
    
/**
     * 取得标记链表
     * 
     * 说明:
     * 
@return
     * 创建时间:2010-6-27 上午12:46:47
     * 修改时间:2010-6-27 上午12:46:47
     
*/
    
public List<Token> getTokens() {
        
return tokens;
    }
    
    
/**
     * 取得标记的内容链表
     * 
     * 说明:
     * 
@return
     * 创建时间:2010-6-27 上午08:59:34
     * 修改时间:2010-6-27 上午08:59:34
     
*/
    
public List<String> getTokenConcents(){
        List
<String> ls=new ArrayList<String>();
        
        
for(Token token:tokens){
            ls.add(token.getText());
        }
        
        
return ls;
    }
    
    
/**
     * 测试
     * 
     * 说明:
     * 
@param args
     * 
@throws Exception
     * 创建时间:2010-6-27 上午09:00:02
     * 修改时间:2010-6-27 上午09:00:02
     
*/
    
public static void main(String[] args)  throws Exception{
        
new TokenMaker("96.2+8*5-12*(4-1)/2^(3%10)","[0-9\\.+-[*]/()\\^\\%]","[+-[*]/()\\^\\%]").printTokens();
        
new TokenMaker("select A a,b, v from ta,tb where 1=1 and 2=2 order by a asc","[\\w=<>!\\s,]","[\\s,]").printTokens();
    }
}

3.对算式和Sql语句分解的结果:

将文字96.
2+8*5-12*(4-1)/2^(3%10)转化后的标记为:
序号    内容    类型
-------------------------
1    96.2    Content
2    +    Seperator
3    8    Content
4    *    Seperator
5    5    Content
6    -    Seperator
7    12    Content
8    *    Seperator
9    (    Seperator
10    4    Content
11    -    Seperator
12    1    Content
13    )    Seperator
14    /    Seperator
15    2    Content
16    ^    Seperator
17    (    Seperator
18    3    Content
19    %    Seperator
20    10    Content
21    )    Seperator

将文字select A a,b, v from ta,tb where 
1=1 and 2=2 order by a asc转化后的标记为:
序号    内容    类型
-------------------------
1    select    Content
2    A    Content
3    a    Content
4    ,    Seperator
5    b    Content
6    ,    Seperator
7    v    Content
8    from    Content
9    ta    Content
10    ,    Seperator
11    tb    Content
12    where    Content
13    1=1    Content
14    and    Content
15    2=2    Content
16    order    Content
17    by    Content
18    a    Content
19    asc    Content

posted on 2010-06-27 09:34 何杨 阅读(1406) 评论(1)  编辑  收藏

Feedback

# re: 将字符串分解成标记的类[未登录] 2010-06-27 20:34 feenn
敢于尝试很好,其实最通用的是词法解析工具。可以看看JFlex  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: