春风博客

春天里,百花香...

导航

<2008年3月>
2425262728291
2345678
9101112131415
16171819202122
23242526272829
303112345

统计

公告

MAIL: junglesong@gmail.com
MSN: junglesong_5@hotmail.com

Locations of visitors to this page

常用链接

留言簿(11)

随笔分类(224)

随笔档案(126)

个人软件下载

我的其它博客

我的邻居们

最新随笔

搜索

积分与排名

最新评论

阅读排行榜

评论排行榜

一个利用正则表达式解析单句SQL的类SqlParser

本文乃原创,转载请注明出处。

先看要解析的样例SQL语句:
select * from dual
SELECT * frOm dual
Select C1,c2 From tb
select c1,c2 from tb
select count(*from t1
select c1,c2,c3 from t1 where condi1=1 
Select c1,c2,c3 From t1 Where condi1=1 
select c1,c2,c3 from t1,t2 where condi3=3 or condi4=5 order   by o1,o2
Select c1,c2,c3 from t1,t2 Where condi3=3 or condi4=5 Order   by o1,o2
select c1,c2,c3 from t1,t2,t3 where condi1=5 and condi6=6 or condi7=7 group  by g1,g2
Select c1,c2,c3 From t1,t2,t3 Where condi1=5 and condi6=6 or condi7=7 Group  by g1,g2
Select c1,c2,c3 From t1,t2,t3 Where condi1=5 and condi6=6 or condi7=7 Group  by g1,g2,g3 order  by g2,g3

解析效果之一(isSingleLine=false):
原SQL为select * from dual
解析后的SQL为
select
     
*  
from
     dual

原SQL为SELECT 
* frOm dual
解析后的SQL为
select
     
*  
from
     dual

原SQL为Select C1,c2 
From tb
解析后的SQL为
select
     C1,c2  
from
     tb

原SQL为select c1,c2 
from tb
解析后的SQL为
select
     c1,c2  
from
     tb

原SQL为select 
count(*from t1
解析后的SQL为
select
     
count(*)  
from
     t1

原SQL为select c1,c2,c3 
from t1 where condi1=1
解析后的SQL为
select
     c1,c2,c3  
from
     t1  
where
     condi1
=1

原SQL为Select c1,c2,c3 
From t1 Where condi1=1
解析后的SQL为
select
     c1,c2,c3  
from
     t1  
where
     condi1
=1

原SQL为select c1,c2,c3 
from t1,t2 where condi3=3 or condi4=5 order   by o1,o2
解析后的SQL为
select
     c1,c2,c3  
from
     t1,t2  
where
     condi3
=3 or condi4=5  
order by
     o1,o2

原SQL为Select c1,c2,c3 
from t1,t2 Where condi3=3 or condi4=5 Order   by o1,o2
解析后的SQL为
select
     c1,c2,c3  
from
     t1,t2  
where
     condi3
=3 or condi4=5  
order by
     o1,o2

原SQL为select c1,c2,c3 
from t1,t2,t3 where condi1=5 and condi6=6 or condi7=7 group  by g1,g2
解析后的SQL为
select
     c1,c2,c3  
from
     t1,t2,t3  
where
     condi1
=5 and condi6=6 or condi7=7  
group by
     g1,g2

原SQL为Select c1,c2,c3 
From t1,t2,t3 Where condi1=5 and condi6=6 or condi7=7 Group  by g1,g2
解析后的SQL为
select
     c1,c2,c3  
from
     t1,t2,t3  
where
     condi1
=5 and condi6=6 or condi7=7  
group by
     g1,g2

原SQL为Select c1,c2,c3 
From t1,t2,t3 Where condi1=5 and condi6=6 or condi7=7 Group  by g1,g2,g3 order  by g2,g3
解析后的SQL为
select
     c1,c2,c3  
from
     t1,t2,t3  
where
     condi1
=5 and condi6=6 or condi7=7  
group by
     g1,g2,g3  
order by
     g2,g3


解析效果之二(isSingleLine=true):
原SQL为select * from dual
解析后的SQL为
select
     
*  
from
     dual

原SQL为SELECT 
* frOm dual
解析后的SQL为
select
     
*  
from
     dual

原SQL为Select C1,c2 
From tb
解析后的SQL为
select
     C1,
     c2  
from
     tb

原SQL为select c1,c2 
from tb
解析后的SQL为
select
     c1,
     c2  
from
     tb

原SQL为select 
count(*from t1
解析后的SQL为
select
     
count(*)  
from
     t1

原SQL为select c1,c2,c3 
from t1 where condi1=1
解析后的SQL为
select
     c1,
     c2,
     c3  
from
     t1  
where
     condi1
=1

原SQL为Select c1,c2,c3 
From t1 Where condi1=1
解析后的SQL为
select
     c1,
     c2,
     c3  
from
     t1  
where
     condi1
=1

原SQL为select c1,c2,c3 
from t1,t2 where condi3=3 or condi4=5 order   by o1,o2
解析后的SQL为
select
     c1,
     c2,
     c3  
from
     t1,
     t2  
where
     condi3
=3 or
      condi4
=5  
order by
     o1,
     o2

原SQL为Select c1,c2,c3 
from t1,t2 Where condi3=3 or condi4=5 Order   by o1,o2
解析后的SQL为
select
     c1,
     c2,
     c3  
from
     t1,
     t2  
where
     condi3
=3 or
      condi4
=5  
order by
     o1,
     o2

原SQL为select c1,c2,c3 
from t1,t2,t3 where condi1=5 and condi6=6 or condi7=7 group  by g1,g2
解析后的SQL为
select
     c1,
     c2,
     c3  
from
     t1,
     t2,
     t3  
where
     condi1
=5 and
      condi6
=6 or
      condi7
=7  
group by
     g1,
     g2

原SQL为Select c1,c2,c3 
From t1,t2,t3 Where condi1=5 and condi6=6 or condi7=7 Group  by g1,g2
解析后的SQL为
select
     c1,
     c2,
     c3  
from
     t1,
     t2,
     t3  
where
     condi1
=5 and
      condi6
=6 or
      condi7
=7  
group by
     g1,
     g2

原SQL为Select c1,c2,c3 
From t1,t2,t3 Where condi1=5 and condi6=6 or condi7=7 Group  by g1,g2,g3 order  by g2,g3
解析后的SQL为
select
     c1,
     c2,
     c3  
from
     t1,
     t2,
     t3  
where
     condi1
=5 and
      condi6
=6 or
      condi7
=7  
group by
     g1,
     g2,
     g3  
order by
     g2,
     g3


使用的类SqlParser,你可以拷贝下来使用之:
package com.sitinspring.common.sqlFormatter;

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

/**
 * SQL语句解析器类
 * 
@author: sitinspring(junglesong@gmail.com)
 * @date: 2008-3-12
 
*/
public class SqlParser{
    
/**
     * 逗号
     
*/
    
private static final String Comma = ",";
    
    
/**
     * 四个空格
     
*/
    
private static final String FourSpace = "    ";
    
    
/**
     * 是否单行显示字段,表,条件的标识量
     
*/
    
private static boolean isSingleLine=true;
    
    
/**
     * 待解析的SQL语句
     
*/
    
private String sql;
    
    
/**
     * SQL中选择的列
     
*/
    
private String cols;
    
    
/**
     * SQL中查找的表
     
*/
    
private String tables;
    
    
/**
     * 查找条件
     
*/
    
private String conditions;
    
    
/**
     * Group By的字段
     
*/
    
private String groupCols;
    
    
/**
     * Order by的字段
     
*/
    
private String orderCols;
    
    
/**
     * 构造函数
     * 功能:传入构造函数,解析成字段,表,条件等
     * 
@param sql:传入的SQL语句
     
*/
    
public SqlParser(String sql){
        
this.sql=sql.trim();
        
        parseCols();
        parseTables();
        parseConditions();
        parseGroupCols();
        parseOrderCols();
    }
    
    
/**
     * 解析选择的列
     *
     
*/
    
private void parseCols(){
        String regex
="(select)(.+)(from)";   
        cols
=getMatchedString(regex,sql);
    }
    
    
/**
     * 解析选择的表
     *
     
*/
    
private void parseTables(){
        String regex
="";   
        
        
if(isContains(sql,"\\s+where\\s+")){
            regex
="(from)(.+)(where)";   
        }
        
else{
            regex
="(from)(.+)($)";   
        }
        
        tables
=getMatchedString(regex,sql);
    }
    
    
/**
     * 解析查找条件
     *
     
*/
    
private void parseConditions(){
        String regex
="";   
        
        
if(isContains(sql,"\\s+where\\s+")){
            
// 包括Where,有条件
            
            
if(isContains(sql,"group\\s+by")){
                
// 条件在where和group by之间
                regex="(where)(.+)(group\\s+by)";  
            }
            
else if(isContains(sql,"order\\s+by")){
                
// 条件在where和order by之间
                regex="(where)(.+)(order\\s+by)";  
            }
            
else{
                
// 条件在where到字符串末尾
                regex="(where)(.+)($)";  
            }             
        }
        
else{
            
// 不包括where则条件无从谈起,返回即可
            return;
        }
        
        conditions
=getMatchedString(regex,sql);
    }
    
    
/**
     * 解析GroupBy的字段
     *
     
*/
    
private void parseGroupCols(){
        String regex
="";   
        
        
if(isContains(sql,"group\\s+by")){
            
// 包括GroupBy,有分组字段

            
if(isContains(sql,"order\\s+by")){
                
// group by 后有order by
                regex="(group\\s+by)(.+)(order\\s+by)";  
            }
            
else{
                
// group by 后无order by
                regex="(group\\s+by)(.+)($)";  
            }           
        }
        
else{
            
// 不包括GroupBy则分组字段无从谈起,返回即可
            return;
        }
        
        groupCols
=getMatchedString(regex,sql);
    }
    
    
/**
     * 解析OrderBy的字段
     *
     
*/
    
private void parseOrderCols(){
        String regex
="";   
        
        
if(isContains(sql,"order\\s+by")){
            
// 包括GroupBy,有分组字段
            regex="(order\\s+by)(.+)($)";                           
        }
        
else{
            
// 不包括GroupBy则分组字段无从谈起,返回即可
            return;
        }
            
        orderCols
=getMatchedString(regex,sql);
    }
    
    
    
/**
     * 从文本text中找到regex首次匹配的字符串,不区分大小写
     * 
@param regex: 正则表达式
     * 
@param text:欲查找的字符串
     * 
@return regex首次匹配的字符串,如未匹配返回空
     
*/
    
private static String getMatchedString(String regex,String text){
        Pattern pattern
=Pattern.compile(regex,Pattern.CASE_INSENSITIVE);
        
        Matcher matcher
=pattern.matcher(text);
 
        
while(matcher.find()){
            
return matcher.group(2);
        }
        
        
return null;
    }
    
    
/**
     * 看word是否在lineText中存在,支持正则表达式
     * 
@param lineText
     * 
@param word
     * 
@return
     
*/
    
private static boolean isContains(String lineText,String word){
        Pattern pattern
=Pattern.compile(word,Pattern.CASE_INSENSITIVE);
        Matcher matcher
=pattern.matcher(lineText);
        
return matcher.find();
    }
    
    
    
public String toString(){        
        
// 无法解析则原样返回
        if(cols==null && tables==null && conditions==null && groupCols==null && orderCols==null ){
            
return sql;
        }
        
        StringBuffer sb
=new StringBuffer();
        sb.append(
"原SQL为"+sql+"\n");
        sb.append(
"解析后的SQL为\n");
        
        
        
for(String str:getParsedSqlList()){
            sb.append(str);
        }
        
        sb.append(
"\n");
        
        
return sb.toString();
    }
    
    
/**
     * 在分隔符后加上回车
     * 
@param str
     * 
@param splitStr
     * 
@return
     
*/
    
private static String getAddEnterStr(String str,String splitStr){
        Pattern p 
= Pattern.compile(splitStr,Pattern.CASE_INSENSITIVE);

        
// 用Pattern类的matcher()方法生成一个Matcher对象
        Matcher m = p.matcher(str);
        StringBuffer sb 
= new StringBuffer();

        
// 使用find()方法查找第一个匹配的对象
        boolean result = m.find();

        
// 使用循环找出模式匹配的内容替换之,再将内容加到sb里
        while (result) {
            m.appendReplacement(sb, m.group(
0+ "\n     ");
            result 
= m.find();
        }
        
// 最后调用appendTail()方法将最后一次匹配后的剩余字符串加到sb里;
        m.appendTail(sb);
        
        
return FourSpace+sb.toString();
    }
    
    
/**
     * 取得解析的SQL字符串列表
     * 
@return
     
*/
    
public List<String> getParsedSqlList(){
        List
<String> sqlList=new ArrayList<String>();
        
        
// 无法解析则原样返回
        if(cols==null && tables==null && conditions==null && groupCols==null && orderCols==null ){
            sqlList.add(sql);
            
return sqlList;
        }
        
        
if(cols!=null){
            sqlList.add(
"select\n");
            
if(isSingleLine){
                sqlList.add(getAddEnterStr(cols,Comma));
            }
            
else{
                sqlList.add(FourSpace
+cols);
            }
        }
        
        
if(tables!=null){
            sqlList.add(
" \nfrom\n");

            
if(isSingleLine){
                sqlList.add(getAddEnterStr(tables,Comma));
            }
            
else{
                sqlList.add(FourSpace
+tables);
            }
        }
        
        
if(conditions!=null){
            sqlList.add(
" \nwhere\n");

            
if(isSingleLine){
                sqlList.add(getAddEnterStr(conditions,
"(and|or)"));
            }
            
else{
                sqlList.add(FourSpace
+conditions);
            }
        }
        
        
if(groupCols!=null){
            sqlList.add(
" \ngroup by\n");

            
if(isSingleLine){
                sqlList.add(getAddEnterStr(groupCols,Comma));
            }
            
else{
                sqlList.add(FourSpace
+groupCols);
            }
        }
        
        
if(orderCols!=null){
            sqlList.add(
" \norder by\n");

            
if(isSingleLine){
                sqlList.add(getAddEnterStr(orderCols,Comma));
            }
            
else{
                sqlList.add(FourSpace
+orderCols);
            }
        }
        
        
return sqlList;
    }
    
    
/**
     * 设置是否单行显示表,字段,条件等
     * 
@param isSingleLine
     
*/
    
public static void setSingleLine(boolean isSingleLine) {
        SqlParser.isSingleLine 
= isSingleLine;
    }
    
    
/**
     * 测试
     * 
@param args
     
*/
    
public static void main(String[] args){
        List
<String> ls=new ArrayList<String>();
        ls.add(
"select * from dual");    
        ls.add(
"SELECT * frOm dual");
        ls.add(
"Select C1,c2 From tb");
        ls.add(
"select c1,c2 from tb");
        ls.add(
"select count(*) from t1");
        ls.add(
"select c1,c2,c3 from t1 where condi1=1 ");
        ls.add(
"Select c1,c2,c3 From t1 Where condi1=1 ");
        ls.add(
"select c1,c2,c3 from t1,t2 where condi3=3 or condi4=5 order   by o1,o2");
        ls.add(
"Select c1,c2,c3 from t1,t2 Where condi3=3 or condi4=5 Order   by o1,o2");
        ls.add(
"select c1,c2,c3 from t1,t2,t3 where condi1=5 and condi6=6 or condi7=7 group  by g1,g2");
        ls.add(
"Select c1,c2,c3 From t1,t2,t3 Where condi1=5 and condi6=6 or condi7=7 Group  by g1,g2");
        ls.add(
"Select c1,c2,c3 From t1,t2,t3 Where condi1=5 and condi6=6 or condi7=7 Group  by g1,g2,g3 order  by g2,g3");
        
        
for(String sql:ls){
            System.out.println(
new SqlParser(sql));
            
//System.out.println(sql);
        }
    }
}

posted on 2008-03-14 20:08 sitinspring 阅读(7578) 评论(10)  编辑  收藏 所属分类: 个人作品

评论

# re: 一个利用正则表达式解析单句SQL的类SqlParser 2008-03-15 20:42 lingos

你这解析了干嘛用?  回复  更多评论   

# re: 一个利用正则表达式解析单句SQL的类SqlParser 2008-03-16 11:48 如坐春风

@lingos

用在我的一个小工具中。
http://download.enet.com.cn/html/030212008012701.html  回复  更多评论   

# re: 一个利用正则表达式解析单句SQL的类SqlParser 2008-03-17 09:30 CowNew开源团队

Great job!
另外也可以使用我们CowNewSQL中的SQL解析器,已经可以解析非常复杂的SQL语句了。CowNewSQL的SQL解析器部分可以单独拿出来使用。  回复  更多评论   

# re: 一个利用正则表达式解析单句SQL的类SqlParser 2008-03-17 20:00 如坐春风

@CowNew开源团队

谢谢。

你们的解析器我刚来Blogjava就听说过,也有想用的念头,只是不知道它是免费的还是协议的,能否用在我的小没有开源的工具中。 也没去问你们,自己写的权当是练手了。以后我会考虑使用贵团队的SQL解析器的。

  回复  更多评论   

# re: 一个利用正则表达式解析单句SQL的类SqlParser 2008-03-17 20:03 CowNew开源团队

@如坐春风
可以使用的。我们的解析器是LGPL协议的,所以可以用在私有软件中。具体可以参考LGPL协议,:)。如果在使用过程中有问题可以和我们联系,:)。  回复  更多评论   

# re: 一个利用正则表达式解析单句SQL的类SqlParser 2008-03-17 20:07 如坐春风

@CowNew开源团队

回帖好快啊!

你们的地址我记下了,忙完这阵我一定会拜访的。  回复  更多评论   

# re: 一个利用正则表达式解析单句SQL的类SqlParser 2008-04-26 11:04 wsand

select c1,c2,c3 from t1,t2 order by o1,o2
没有where,测试一下  回复  更多评论   

# re: 一个利用正则表达式解析单句SQL的类SqlParser 2011-05-05 15:11 谢宇

既然是简单表达式我也不说太难的例子,我只说一个,麻烦帮忙解决一下,就是字段里面有from关键字,但是不是from,比如fromaddr,这种。

select fromaddr from abc;

我试了下解析出来好像是错的,作者可以试一试。
另外至于SQL中有常量的情况,常量中包含关键字的问题,估计会更加复杂一些;SQL文本中如果存在中文全格的空格作者是否有想过如何解决。

更复杂的当然是各类SQL的写法了,尤其是一些方言SQL,但是由于作者只提到简单SQL我觉得至少是说明单条SQL是可以处理吧;前面两个问题应该可以考虑下如何避免。  回复  更多评论   

# re: 一个利用正则表达式解析单句SQL的类SqlParser[未登录] 2011-09-15 02:19 aa

没有解析子查询  回复  更多评论   

# re: 一个利用正则表达式解析单句SQL的类SqlParser[未登录] 2014-01-20 13:58 Jason

不错,解析出来刚好要使用的东西。  回复  更多评论   


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


网站导航:
 
sitinspring(http://www.blogjava.net)原创,转载请注明出处.