Java RegEx API "Группа наблюдения не имеет очевидной максимальной длины рядом с индексом ..." - PullRequest
0 голосов
/ 27 апреля 2010

Я перешел к некоторому SQL-запросу, где разбирал предложение и разработал работающий RegEx для поиска столбца вне строковых литералов, используя "Rad Software Desginer регулярных выражений", который использует .NET API. Чтобы убедиться, что сконструированный RegEx работает и с Java, я протестировал его с помощью API (1.5 и 1.6). Но знаете что, это не сработает. Я получил сообщение

"Группа наблюдения не имеет очевидной максимальной длины около индекса 28".

Строка, которую я пытаюсь проанализировать:

Column_1='test''the''stuff''all''day''long' AND Column_2='000' AND  TheVeryColumnIWantToFind      =    'Column_1=''test''''the''''stuff''''all''''day''''long'' AND Column_2=''000'' AND  TheVeryColumnIWantToFind   =    ''   TheVeryColumnIWantToFind   =    '' AND (Column_3 is null or Column_3 = ''Not interesting'') AND ''1'' = ''1''' AND (Column_3 is null or Column_3 = 'Still not interesting') AND '1' = '1'

Как вы уже догадались, я попытался создать какой-то наихудший случай, чтобы гарантировать, что RegEx не потерпит неудачу на более сложных предложениях SQL where.

Сам RegEx выглядит так

(?i:(?<!=\s*'(?:[^']|(?:''))*)((?<=\s*)TheVeryColumnIWantToFind(?=(?:\s+|=))))

Я не уверен, есть ли более элегантный RegEx (скорее всего, он будет), но это сейчас не важно, так как он делает свое дело.

Чтобы объяснить RegEx в двух словах: Если он находит столбец, за которым я следую, он делает негативный обзор, чтобы выяснить, используется ли имя столбца в строковом литерале. Если так, это не будет соответствовать. Если нет, это будет соответствовать.

Вернуться к вопросу. Как я упоминал ранее, это не будет работать с Java. Что сработает и приведет к тому, что я хочу?
Я обнаружил, что Java, похоже, не поддерживает неограниченное количество просмотров, но все же не смог заставить его работать.
Разве не правильно, что предыстория всегда накладывает ограничение на себя от поискового смещения до текущей поисковой позиции? Таким образом, это приведет к чему-то вроде «смещение позиции»?

1 Ответ

0 голосов
/ 28 апреля 2010

Я наконец-то нашел решение, и поскольку я задал вопрос здесь, я, конечно, поделюсь им с вами.

private static final String SQL_STRING_LITERALS_REGEX = "'(?:(?:[^']|(?:''))*)'";
private static final char DOT = '.';

private ArrayList<int[]> getNonStringLiteralRegions(String exclusion) {
    ArrayList<int[]> regions = new ArrayList<int[]>();

    int lastEnd = 0;
    Matcher m = Pattern.compile(SQL_STRING_LITERALS_REGEX).matcher(exclusion);
    while (m.find()) {
        regions.add(new int[] {lastEnd, m.start()});
        lastEnd = m.end();
    }
    if (lastEnd < exclusion.length())
        // We didn't cover the last part of the exclusion yet.
        regions.add(new int[] {lastEnd, exclusion.length()});

    return regions;
}

protected final String getFixedExclusion(String exclusion, String[] columns, String alias) {
    if (alias == null)
        throw new NullPointerException("Alias must not be null.");
    else if (alias.charAt(alias.length() - 1) != DOT)
        alias += DOT;

    StringBuilder b = new StringBuilder(exclusion);
    ArrayList<int[]> regions = getNonStringLiteralRegions(exclusion);
    for (int i = regions.size() - 1; i >= 0; --i) {
        // Reverse iteration to keep valid indices for the lower regions.
        int start = regions.get(i)[0], end = regions.get(i)[1];
        String s = exclusion.substring(start, end);
        for (String column : columns)
            s = s.replaceAll("(?<=^|[\\W&&\\D])(?i:" + column + ")(?=[\\W&&\\D]|$)", alias + column);
        b.replace(start, end, s);
    }

    return b.toString();
}

На этот раз хитрость заключается в том, чтобы просто найти любые строковые литералы SQL и избежать их при замене столбцов на «Alias.ColumnName». Важно обеспечить полные имена столбцов при замене. Так что, если мы должны были заменить столбец "Column_1" в предложении where

WHERE Column_1 = Column_2 AND Column_11 = Column_22

"Столбец_11" следует оставить нетронутым. (Я думаю, что важно помнить об этом, поэтому я упоминаю это здесь для всех, кто сталкивается с подобной проблемой.)
Тем не менее, я думаю, что это только обходной путь, и если вы можете избежать необходимости в этой логике, лучше всего это сделать.

Хорошо, спасибо за помощь в любом случае, и я был бы рад ответить на предстоящие вопросы, если таковые имеются.

...