2011-11-29 127 views
2

我正在編寫一個可以執行不同SQL語句的應用程序(用戶將這些語句指定爲一個字符串值)。我在用着 」;」作爲語句之間的分隔符(一次用戶可以執行許多DML語句)。但是在DML語句中,可以有一個varchar值「;」內。替換符號的正則表達式

insert into A values(1, 'sda;asdad'); 
insert into A values(2, 'asdsa'); 

我的第一個想法是使用String#split(String regex)。但我不知道如何創建一個正則表達式,這將有助於僅由那些不在varchars中的分號分割。你能提出一個建議嗎?或者有另一種解決方法?

回答

1

這裏有一個天真的解析器,可能是你在找什麼。我想過使用正則表達式。起初我認爲你的語言其實並不經常。

我相信DML是一種上下文無關語言,但實際上,您的目標語言是經常性的,因爲您不關心嵌套語句。你所關心的只是檢測頂級字符串。但即使如此,當你考慮到可能會在varchars中引用引號時,也很難使用正則表達式。即'abcd \'efg'如果你有多個;在varchar裏面。

這段代碼並不漂亮,但它應該做你正在尋找的東西。

public static void main(String[] ar) { 
    String s = "aaa 'bb;bb;bb' aaa; aaa 'bb;bb\\';bb' aaa"; 
    System.out.println(splitStatments(s, ';')); 
} 

private static List<String> splitStatments(String s, char statementDelimiter) { 
    List<String> statements = new ArrayList<String>(); 
    StringBuffer sb = new StringBuffer(); 
    boolean outsideString = true; 
    char lastChar = 0; 
    for (char c : s.toCharArray()) { 
     // in the case of the escaped \', we DON'T want to flip the boolean 
     if (c == '\'' && lastChar != '\\') { 
      outsideString = !outsideString; 
     } 
     if (c == statementDelimiter && outsideString) { 
      statements.add(sb.toString()); 
      sb = new StringBuffer(); 
     } else { 
      sb.append(c); 
     } 
     lastChar = c; 
    } 
    if (sb.length() > 0) { 
     statements.add(sb.toString()); 
    } 
    return statements; 
} 
2

通常你會用逃避解決這個問題:

insert into A values(1, 'sda\\;asdad'); 

然後當你String#split(),確保該;不是由\使用negative lookbehind之前。事情是這樣的:

String rawInput = ...; 
String[] statements = rawInput.split("(?<!\\\\);"); 
+0

這是一個好主意,但它會好一些用戶不知道有關分號必須進行轉義,所以他/她必須有輸入SQL字符串就像在Oracle SQL Developer中或PL/SQL開發人員 – maks

+0

如果沒有字符轉義,你將基本上開始編寫一個解析器。檢查字符串文本中是否出現分號是非平凡的。 –

1

以下是更復雜,String.split,但它的工作原理:

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

public class Regex2 { 

    static Pattern pattern = Pattern.compile(".*'(.*);(.*)'.*"); 

    public static void main(String[] args) { 
     String target = "'asdf;asdf';"; 

     String[] split = split(target); 
     if (split == null) 
     System.out.println("No match"); 
     else 
     for (String word : split(target)) 
      System.out.println(word); 
    } 

    static String[] split(String target) { 
     Matcher matcher = pattern.matcher(target); 
     String[] split = null; 
     if (matcher.matches()) { 
     split = new String[matcher.groupCount()]; 
     for (int i = 1; i <= matcher.groupCount(); i++) 
      split[i - 1] = matcher.group(i); 
     } 
     return split; 
    } 
}