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

Я перехожу к некоторому SQL, в котором анализирую предложение и разработал работающий RegEx для поиска столбца вне строковых литералов, используя "Rad Software Desginer Regular Expression 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 ответ

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

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" следует оставить нетронутым. (Я думаю, что важно помнить об этом, поэтому я упоминаю это здесь для всех, кто сталкивается с подобной проблемой.)
Тем не менее, я думаю, что это только обходной путь, и если вы можете избежать необходимости в этой логике, лучше всего это сделать.

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

Другие вопросы по тегам