2011-11-29 256 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; 
    } 
}