Регулярное выражение для замены символов - PullRequest
2 голосов
/ 29 ноября 2011

Я пишу приложение, которое может выполнять различные операторы SQL (пользователь указывает эти операторы как одно строковое значение).Я использую ";"в качестве разделителя между операторами (одновременно пользователь может выполнять много операторов DML).Но внутри оператора DML может быть значение varchar, которое имеет ";"внутри.

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

моей первой мыслью было использовать String#split(String regex).Но я не знаю, как сделать регулярное выражение, которое поможет разделить только те точки с запятой, которые не находятся внутри varchars.Можете ли вы предложить один или, может быть, есть другой подход для решения этой проблемы?

Ответы [ 3 ]

2 голосов
/ 29 ноября 2011

Обычно вы решаете это с помощью экранирования:

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

затем, когда вы String#split(), убедитесь, что ; не предшествует \, используя отрицательный взгляд позади . Примерно так:

String rawInput = ...;
String[] statements = rawInput.split("(?<!\\\\);");
1 голос
/ 29 ноября 2011

Вот наивный парсер, который может быть тем, что вы ищете. Я думал об использовании регулярного выражения. Сначала я думал, что твой язык на самом деле не обычный.

Я полагаю, что DML - это язык без контекста, но на самом деле ваш целевой язык является регулярным, потому что вам нет дела до вложенных операторов. Все, что вам нужно, это обнаружение строк верхнего уровня. Но даже это становится сложным в использовании регулярных выражений, если вы считаете, что внутри ваших вариантов могут быть экранированные кавычки. то есть '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;
}
1 голос
/ 29 ноября 2011

Следующее более сложное, чем 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;
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...