Java Regex: Попытка конвертировать оракула || CONCAT () - PullRequest
1 голос
/ 11 февраля 2011

У меня есть куча операторов SQL, которые изначально были написаны для поддержки Oracle и используют множество специфических синтаксисов Oracle. Большую часть этого было довольно легко решить с помощью простого поиска и замены в стиле регулярных выражений или с помощью функций JDBC. Этот случай, однако, доставляет мне немного больше хлопот.

Есть несколько случаев, когда конкатенация используется для значений, и я пытаюсь заменить col1 || col2 || col3 должен быть заменен синтаксисом стиля CONCAT (col1, col2, col3) в случае, если ядро ​​базы данных не является Oracle.

Я знаю, что было бы идеально использовать какой-либо ORM, но это не практично в этом случае по разным причинам.

У меня есть настройка тестового приложения для тестирования некоторых случаев, с которыми я, скорее всего, соприкоснусь, но у меня возникают проблемы с выяснением, как заставить его заменить весь экземпляр, а также с переменным числом совпадений после | |. Решение, как у меня сейчас, соответствует только последнему появлению столбца | Может быть, это невозможно, но я хотел бы попытаться исчерпать этот путь решения.

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

public class regex {
    public static void main(String args[]){
        String sSource = "SELECT col1, col2||word||default_col||another field1, col3 || ' quote test ' || default_1 field2 FROM table order by 1";
        try{
            String pattern ="((\\b\\[a-zA-Z0-9_]+|'.*')\\s*(\\|\\|)\\s*(\\w+))";
            Pattern p = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE|Pattern.MULTILINE|Pattern.DOTALL);
            Matcher m = p.matcher(sSource);
            while(m.find()){
                sSource = m.replaceAll("CONCAT($2 , $4)");
                System.out.println("found match");
            }
            System.out.println(sSource);
        } catch( Exception e) {
            System.out.println("Bad things:" + e.getMessage());
        }
    }
}

1 Ответ

2 голосов
/ 11 февраля 2011

Вы не можете сделать замену concat для всех || с регулярными выражениями, так как они недостаточно сильны для обработки грамматики SQL. Вы можете объединить все что угодно, используя || включая символьные литералы, содержащие ||.

Однако в некоторых особых случаях может быть достаточно регулярного выражения. Может быть проще разделить и победить проблему, например

  1. конвертировать (SELECT|,) <content> || в (SELECT|,) concat(<content> ||

  2. конвертировать || <content> <field> (FROM|,) в , <content>) <field> (FROM|,

  3. конвертировать все оставшиеся || до

Сохранять результат после каждой фазы и применять правила для этого промежуточного преобразования.

что-то вроде

private static String identifierOrString = "[a-zA-Z0-9_\\.\\(\\),]+";

public static void main(String[] args) {

  String testCase = "SELECT col1, col2||word||default_col||another field1, col3 || ' quote test ' || default_1 field2 FROM table where 'abc' = col4 || col5 || col6 GROUP BY col7 || col8";

  testCase = convertBeginnings(testCase);
  System.out.println("Phase 1: " + testCase);

  testCase = convertEndings(testCase);
  System.out.println("Phase 2: " + testCase);

  testCase = convertRemainingOperators(testCase);
  System.out.println("Finished: " + testCase);    
}

private static String convertBeginnings(String testCase) {
  return replace("(SELECT|WHERE|=|<>|like|GROUP BY|\\,)(\\s+)(%s|'[^']*')\\s*\\|\\|", testCase, "%s %s concat(%s ||");
}

private static String convertEndings(String testCase) { 
  return replace("\\|\\|\\s*(%1$s|'[^']*')\\s*(\\s%1$s)?\\s*((\\,|FROM|GROUP BY|ORDER BY|=|<>|like|$))", testCase,",%s) %s %s");
}

private static String replace(String regexp, String source , String target) {
  Matcher m = match(regexp, source);
  while(m.find()) {
    source = source.replace(m.group(0), String.format(target, nvl(m.group(1)), nvl(m.group(2)), nvl(m.group(3))));
  }
  return source;
}

private static String nvl(String value) {
  return null == value ? "" : value;
}

private static String convertRemainingOperators(String testCase) {
  return testCase.replaceAll("\\|\\|", ",");
}

private static Matcher match(String regexp, String target ) {
  Pattern p = Pattern.compile(String.format(regexp, identifierOrString), Pattern.CASE_INSENSITIVE|Pattern.MULTILINE|Pattern.DOTALL);
  return p.matcher(target); 
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...