Неужели регулярные выражения игнорируют новые строки и просто совпадают на целой большой строке? - PullRequest
8 голосов
/ 26 августа 2010

У меня есть эта строка здесь:

CREATE UNIQUE INDEX index555 ON
SOME_TABLE
(
    SOME_PK          ASC
);

Я хочу сопоставить несколько строк и сопоставить операторы SQL (всех их будет много в одной большой строке) ... что-то вродеэто, однако я получаю совпадение только на CREATE UNIQUE INDEX index555 ON

(CREATE\s.+;)

примечание: я пытаюсь выполнить это в Java, если это имеет значение.

Ответы [ 5 ]

18 голосов
/ 26 августа 2010

Вам необходимо использовать флаги DOTALL и MULTILINE при компиляции регулярного выражения.Вот пример кода Java:

import java.util.regex.*;

public class test
{
    public static void main(String[] args)
    {
        String s =
        "CREATE UNIQUE INDEX index555 ON\nSOME_TABLE\n(\n    SOME_PK          ASC\n);\nCREATE UNIQUE INDEX index666 ON\nOTHER_TABLE\n(\n    OTHER_PK          ASC\n);\n";

        Pattern p = Pattern.compile("([^;]*?('.*?')?)*?;\\s*", Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE);

        Matcher m = p.matcher(s);

        while (m.find())
        {
        System.out.println ("--- Statement ---");
        System.out.println (m.group ());
        }
    }
}

Вывод будет:

--- Statement ---
CREATE UNIQUE INDEX index555 ON
SOME_TABLE
(
    SOME_PK          ASC
);

--- Statement ---
CREATE UNIQUE INDEX index666 ON
OTHER_TABLE
(
    OTHER_PK          ASC
);
8 голосов
/ 26 августа 2010

Проверьте это

Регулярное выражение.соответствует любому символу, кроме символа конца строки, если не указан флаг DOTALL

Так что вам нужно сделать что-то подобное

5 голосов
/ 26 августа 2010

Флаг DOTALL позволяет . соответствовать символам новой строки, но если вы просто примените его к существующему регулярному выражению, вы в конечном итоге сопоставите все от первого CREATE до последнего ; за один раз.Если вы хотите сопоставить утверждения по отдельности, вам нужно сделать больше.Одним из вариантов является использование не жадного квантификатора:

Pattern p = Pattern.compile("^CREATE\\b.+?;",
    Pattern.DOTALL | Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);

Я также использовал флаг MULTILINE, чтобы привязка ^ соответствовала после новых строк, и CASE_INSENSITIVE, потому что SQL - по крайней мерекаждый аромат, о котором я слышал.Обратите внимание, что все три флага имеют «встроенные» формы, которые вы можете использовать в самом регулярном выражении:

Pattern p = Pattern.compile("(?smi)^CREATE\\b.+?;");

(Встроенная форма DOTALL по историческим причинам равна s; она называлась «одно-строковый режим в Perl, там, где он возник.) Другой вариант - использовать класс символов с отрицанием:

Pattern p = Pattern.compile("(?mi)^CREATE\\b[^;]+;");

[^;]+ соответствует одному или нескольким символам, кроме ; - включая новые строки,поэтому флаг s не нужен.

До сих пор я предполагал, что каждый оператор начинается с начала строки и заканчивается точкой с запятой, как в вашем примере.Я не думаю, что что-то из этого требуется стандартом SQL, но я ожидаю, что вы узнаете, можете ли вы рассчитывать на них в этом случае.Возможно, вы захотите начать сопоставление с границы слова вместо границы строки:

Pattern p = Pattern.compile("(?i)\\bCREATE\\b[^;]+;");

Наконец, если вы думаете о том, чтобы сделать что-то более сложное с регулярными выражениями и SQL, не .Разбор SQL с помощью регулярных выражений - игра для дураков - она ​​даже хуже, чем HTML и регулярные выражения.

3 голосов
/ 26 августа 2010

Вы хотите использовать флаг Pattern.DOTALL для совпадения между строками.

3 голосов
/ 26 августа 2010

Проверьте различные флаги, которые могут быть переданы Pattern.compile . Я думаю, что DOTALL - это то, что вам нужно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...