【问题标题】:Regular expression for replacing symbols用于替换符号的正则表达式
【发布时间】:2011-11-29 15:29:39
【问题描述】:

我正在编写一个可以执行不同 SQL 语句的应用程序(用户将这些语句指定为一个字符串值)。我正在使用 ”;”作为语句之间的分隔符(一次用户可以执行许多 DML 语句)。但是在 DML 语句中可以有一个带有“;”的 varchar 值。里面。

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

我的第一个想法是使用String#split(String regex)。但我不知道如何制作一个正则表达式,它只会帮助那些不在 varchars 中的分号进行拆分。您能建议一种或另一种方法来解决这个问题吗?

【问题讨论】:

    标签: java sql regex oracle


    【解决方案1】:

    通常你会通过转义来解决这个问题:

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

    然后,当您String#split() 时,请确保 ; 前面没有使用 negative lookbehind 的 \。像这样的:

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

    【讨论】:

    • 这是个好主意,但最好让用户不知道必须转义分号,因此他/她必须像在 Oracle SQL developer 或 PL/ 中一样输入 sql 字符串SQL 开发人员
    • 如果没有字符转义,您将基本上开始编写解析器。检查分号是否出现在字符串文字中是不平凡的。
    【解决方案2】:

    这是一个简单的解析器,可能正是您要找的。我考虑过使用正则表达式。起初我以为你的语言实际上不是正规的。

    我相信 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;
    }
    

    【讨论】:

      【解决方案3】:

      下面的比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;
         }
      }
      

      【讨论】:

        猜你喜欢
        • 2020-09-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多