<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    和風(fēng)細雨

    世上本無難事,心以為難,斯乃真難。茍不存一難之見于心,則運用之術(shù)自出。

    使用正則表達式解析SQL語句

    本文詳細代碼請見:
    http://m.tkk7.com/sitinspring/archive/2008/03/14/186372.html

     

    問題:將左邊的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

    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

    按關(guān)鍵字找出SQL語句中各部分

    我們閱讀SQL語句會把整句分來成列,表,條件,分組字段,排序字段來理解,解析SQL的目的也是這樣.
    分解SQL語句有規(guī)律可循,以列為例,它必定包含在select和from之間,我們只要能找到SQL語句中的關(guān)鍵字select和from,就能找到查詢的列.
    怎么找到select和from之間的文字呢?其實一個正則表達式就能解決:(select)(.+)(from),其中第二組(.+)代表的文字就是select和from之間的文字.
    程序見右邊.

    /**
     * 從文本text中找到regex首次匹配的字符串,不區(qū)分大小寫
     * @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;
    }

    解析函數(shù)分析

    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;
    }

    左邊的這個函數(shù),第一個參數(shù)是擬定的正則表達式,第二個是整個SQL語句.
    當正則表達式為(select)(.+)(from)時,程序?qū)⒃赟QL中查找第一次匹配的地方(有Pattern.CASE_INSENSITIVE的設(shè)置,查找不區(qū)分大小寫),如果找到了則返回模式中的第二組代表的文字.
    如果sql是select a,b from tc,則返回的文字是a,b.

    選擇的表對應(yīng)的查找正則表達式

    選擇的表比較特殊,它不想選擇的列一樣固定處于select和from之間,當沒有查找條件存在時,它處于from和結(jié)束之間;當有查找條件存在時,它處于from和where之間.
    因此查詢函數(shù)寫為右邊的形式:

    /**
     * 解析選擇的表
     *
     */
    private void parseTables(){
        String regex="";  
       
        if(isContains(sql,"\\s+where\\s+")){
          regex="(from)(.+)(where)";  
        }
        else{
          regex="(from)(.+)($)";  
        }
       
        tables=getMatchedString(regex,sql);
    }


    isContains函數(shù)

    isContains函數(shù)用于在lineText中查找word,其中不區(qū)分大小些,只要找到了即返回真.

    /**
     * 看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();
    }

    解析查找條件的函數(shù)

    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")){
          // 包括order by,有分組字段
          regex="(order\\s+by)(.+)($)";                 
        }
        else{
          // 不包括GroupBy則分組字段無從談起,返回即可
          return;
        }
         
        orderCols=getMatchedString(regex,sql);
    }

    得到解析后的各部分

    按以上解析方法獲得了列,表,條件,分組條件,排序條件各部分之后,它們會存儲到各個成員變量中.
    注意這些成員變量的原值都是null,如果在SQL語句中能夠找到對應(yīng)的部分的話它們將借助getMatchedString獲得值,否則還是null.我們通過判斷這些成員變量是否為空就能知道它對應(yīng)的部分是否被解析出來.

     /**
       * 待解析的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;

    取得不需要單行顯示時的SQL語句

    進展到這一步,SQL語句中列,表,條件,分組條件,排序條件各部分都被獲取了出來,這時把它們重新組合一下就能得到整理后的SQL語句.
    如下面的SQL語句將變成右邊的部分(先使靜態(tài)成員isSingleLine=false):
    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

    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


    進一步解析

    有時我們需要把列,表,條件,分組條件,排序條件單行顯示以方便查看或加上注釋,這就要求我們對列,表,條件,分組條件,排序條件等進行進一步解析.
    初看解析很方便,以固定的分隔符劈分即可,但需要注意的是查詢條件中分隔符有and和or兩種,如果貿(mào)然分隔會使重新組合時使SQL失真.
    推薦一種做法,我們可以在分隔符后加上一個標志如空行,然后再以這個標志來劈分.這樣就不會使SQL失真了.
    請見下頁的getSplitedParagraph函數(shù).

    getSplitedParagraph函數(shù)

    private static List<String> getSplitedParagraph(String paragraph,String splitStr){
      List<String> ls=new ArrayList<String>();   
     
      // 先在分隔符后加空格
      Pattern p = Pattern.compile(splitStr,Pattern.CASE_INSENSITIVE);

      Matcher m = p.matcher(paragraph);
      StringBuffer sb = new StringBuffer();

      boolean result = m.find();
      while (result) {
        m.appendReplacement(sb, m.group(0) + Crlf);
        result = m.find();
      }
      m.appendTail(sb);
     
      // 再按空格斷行
      String[] arr=sb.toString().split("[\n]+");
      for(String temp:arr){
        ls.add(FourSpace+temp+Crlf);
      }
     
      return ls;
    }

    處理結(jié)果

    把靜態(tài)成員變量isSingleLine=true后我們來看看執(zhí)行結(jié)果:
    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

    小結(jié)

    從這個例子中我們體會了分治的思想:分治是把一個大問題分解成小問題,然后分別解決小問題,再組合起來大問題的解決方法就差不多了.這種思想在工程領(lǐng)域解決問題時很普遍,我們要學(xué)會使用這種思想來看待,分析和解決問題,不要貪多求大,結(jié)果導(dǎo)致在大問題面前一籌莫展.
    其次我們可以從這個例子中學(xué)習(xí)找規(guī)律,然后借助規(guī)律的過程,現(xiàn)實世界千變?nèi)f化,但都有規(guī)律可循,只要我們找到了規(guī)律,就等于找到了事物之門的鑰匙.
    接下了我們復(fù)習(xí)了正則表達式用于查找的方法,以前的正則表達式學(xué)習(xí)多用于驗證匹配,其實這只是正則表達式的一部分功能.
    最后從解析條件成單行的過程中,我們可以學(xué)習(xí)到一種解決問題的技巧,即當現(xiàn)實中的規(guī)律存在變數(shù)時加入人為設(shè)置的規(guī)律,這有時能使我們更好更快的解決問題.

    posted on 2008-03-19 22:00 和風(fēng)細雨 閱讀(9677) 評論(4)  編輯  收藏 所屬分類: 正則表達式

    評論

    # re: 使用正則表達式解析SQL語句 2008-04-22 02:44 java 開發(fā)

    謝謝,很有幫助  回復(fù)  更多評論   

    # re: 使用正則表達式解析SQL語句 2008-11-25 22:46 bza

    謝謝  回復(fù)  更多評論   

    # re: 使用正則表達式解析SQL語句 2011-06-22 17:12 青青園中葵

    復(fù)合的sql就不能處理了,這樣太簡單  回復(fù)  更多評論   

    # re: 使用正則表達式解析SQL語句 2012-10-08 19:44 郭濤

    的確不錯,很有幫助。
    @青青園中葵  回復(fù)  更多評論   


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 国产亚洲精品无码拍拍拍色欲| 中国xxxxx高清免费看视频| 国产网站免费观看| 亚洲精品国产高清在线观看| www.999精品视频观看免费| 国产亚洲情侣久久精品| 日韩在线免费播放| 免费国产草莓视频在线观看黄| 国产免费AV片无码永久免费| 色婷婷精品免费视频| 亚洲国产成人久久综合一区77| 国产国产人免费人成成免视频| 国产成人亚洲精品影院| 成人片黄网站色大片免费观看APP| 亚洲va中文字幕无码久久不卡| 久久大香香蕉国产免费网站| 亚洲精品一区二区三区四区乱码 | 国产A在亚洲线播放| 久热免费在线视频| 亚洲免费黄色网址| 国产免费午夜a无码v视频| 夜夜爽妓女8888视频免费观看| 久久久久噜噜噜亚洲熟女综合| 一个人看的www免费视频在线观看| 99久久亚洲精品无码毛片 | 成人人观看的免费毛片| 亚洲精品女同中文字幕| 中文字幕亚洲电影| 亚洲一级毛片免费看| 亚洲乱码日产精品一二三| 亚洲综合色区在线观看| 91成人在线免费视频| 亚洲日韩一中文字暮| 亚洲欧洲国产成人综合在线观看| 青青青国产手机频在线免费观看| 亚洲成人一级电影| 亚洲欧洲久久av| AA免费观看的1000部电影| 青青青视频免费观看| 中文字幕在线观看亚洲| 亚洲精品无码激情AV|