Как очистить комментарии из файла sql raw - PullRequest
10 голосов
/ 03 мая 2011

У меня проблема с очисткой комментариев и пустых строк из уже существующего файла sql. Файл содержит более 10 тыс. Строк, поэтому его очистка вручную невозможна.

У меня есть небольшой скрипт на python, но я не знаю, как обрабатывать комментарии внутри многострочных вставок.

Код:

f = file( 'file.sql', 'r' )
t = filter( lambda x: not x.startswith('--') \
            and not x.isspace() 
  , f.readlines() )
f.close()
t #<- here the cleaned data should be

Как это должно работать:

Это должно быть очищено:

-- normal sql comment

Это должно остаться как есть:

CREATE FUNCTION func1(a integer) RETURNS void
    LANGUAGE plpgsql
    AS $$
BEGIN
        -- comment
       [...]
END;
$$;

INSERT INTO public.texts (multilinetext) VALUES ('
and more lines here \'
-- part of text 
\'
[...]

');

Ответы [ 5 ]

9 голосов
/ 03 мая 2011

Попробуйте модуль sqlparse .

Обновленный пример: оставляя комментарии внутри значений вставки и комментарии в блоках CREATE FUNCTION . Вы можете изменить настройки, чтобы настроить поведение:

import sqlparse
from sqlparse import tokens

queries = '''
CREATE FUNCTION func1(a integer) RETURNS void
    LANGUAGE plpgsql
        AS $$
        BEGIN
                -- comment
       END;
       $$;
SELECT -- comment
* FROM -- comment
TABLE foo;
-- comment
INSERT INTO foo VALUES ('a -- foo bar');
INSERT INTO foo
VALUES ('
a 
-- foo bar'
);

'''

IGNORE = set(['CREATE FUNCTION',])  # extend this

def _filter(stmt, allow=0):
    ddl = [t for t in stmt.tokens if t.ttype in (tokens.DDL, tokens.Keyword)]
    start = ' '.join(d.value for d in ddl[:2])
    if ddl and start in IGNORE:
        allow = 1
    for tok in stmt.tokens:
        if allow or not isinstance(tok, sqlparse.sql.Comment):
            yield tok

for stmt in sqlparse.split(queries):
    sql = sqlparse.parse(stmt)[0]
    print sqlparse.sql.TokenList([t for t in _filter(sql)])

Выход:

CREATE FUNCTION func1(a integer) RETURNS void
    LANGUAGE plpgsql
        AS $$
        BEGIN
                -- comment
       END;
       $$;

SELECT * FROM TABLE foo;

INSERT INTO foo VALUES ('a -- foo bar');

INSERT INTO foo
VALUES ('
a
-- foo bar'
);
2 голосов
/ 31 июля 2018

Добавление обновленного ответа:)

import sqlparse

sql_example = """--comment
SELECT * from test;
INSERT INTO test VALUES ('
-- test
a
');
 """
print sqlparse.format(sql_example, strip_comments=True).strip()

Выход:

ВЫБРАТЬ * из теста;

INSERT INTO VALUES (' -- тестовое задание «);

Он достигает того же результата, но также охватывает все другие угловые случаи и более лаконичен

1 голос
/ 03 мая 2011

Это расширенный ответ на выборку, который работает с вашим примером:

import sqlparse

sql_example = """--comment
SELECT * from test;
INSERT INTO test VALUES ('
-- test
a
');
"""

new_sql = []

for statement in sqlparse.parse(sql_example):
    new_tockens = [stm for stm in statement.tokens 
                   if not isinstance(stm, sqlparse.sql.Comment)]

    new_statement = sqlparse.sql.TokenList(new_tockens)
    new_sql.append(new_statement.to_unicode())

print sqlparse.format("\n".join(new_sql))

Выход:

SELECT * from test;

INSERT INTO test VALUES ('
-- test
a
');
0 голосов
/ 15 февраля 2018
# Remove comments i.e. lines beginning with whitespace and '--' (using multi-line flag)
re.sub('^\s*--.*\n?', '', query, flags=re.MULTILINE)

Объясненная строка регулярного выражения:

  • ^ начало строки
  • \ s пробел
  • \ s * ноль или более пробельных символов
  • - два переноса (статический образец строки)
  • . * Ноль или более любых символов (т. Е. Остальная часть строки)
  • \ n символ новой строки
  • ?конец строки
  • flags = re.M - многострочный модификатор

"Если указано, символ шаблона '^' совпадает в начале строки и вначало каждой строки (сразу после каждой новой строки) "

Подробнее см. документацию по регулярным выражениям Python:

https://docs.python.org/3/library/re.html

0 голосов
/ 03 мая 2011

Это можно сделать с помощью регулярных выражений. Сначала вы должны разделить файл на строки, а после этого вы можете разделить файл по комментариям. Это делает следующая Perl-программа:

#! /usr/bin/perl -w

# Read hole file.
my $file = join ('', <>);

# Split by strings including the strings.
my @major_parts = split (/('(?:[^'\\]++|\\.)*+')/, $file);

foreach my $part (@major_parts) {
    if ($part =~ /^'/) {
        # Print the part if it is a string.
        print $part; 
    }
    else {
        # Split by comments removing the comments
        my @minor_parts = split (/^--.*$/m, $part);
        # Print the remaining parts.
        print join ('', @minor_parts);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...