Для начала вам не нужно регулярное выражение - вы просто заменяете «специальные» символы пустым пробелом при замене «один к одному», но кроме этого вам вряд ли нужно анализировать и переворачивать данныедля начала в DataFrame.
Вы можете напрямую работать с подключением к БД и экспортировать столбцы, используя встроенный модуль csv
, даже не углубляясь в pandas
, SQLAlchemy
и аналогичные тяжеловесы, которые добавляютненужные накладные расходы для вашего варианта использования.
Итак, во-первых, вместо регулярного выражения вы можете создать таблицу перевода и использовать ее с str.translate()
для очистки любой строки:
chr_ranges = (0x00, 0x09), (0x0B, 0x20), (0x7F, 0xA0) # 'special' character ranges
trans_table = {x: " " for r in chr_ranges for x in range(*r)} # 'special'->space trans. table
Это позволяет вам быстро и без усилий перевести все специальные символы, определенные в диапазонах chr_ranges
, в пробел любой строки, например:
print("Your string with >\x05\x06\x1A< special characters!".translate(trans_table))
# Your string with > < special characters!
И пока мы работаем над этим, мы можем создать небольшую функцию для обработки попыток перевода для любого переданного поля, поэтому нам не нужно проверять тип при итерации.Перейдем к данным нашей базы данных:
def trans_field(value):
try:
return value.translate(trans_table) # try to translate and return
except AttributeError: # if there's no translate method on the passed value...
return value # return the original value
Теперь все, что нам нужно, это подключиться к базе данных и выполнить наш запрос, который зависит от базы данных, которую вы используете - следующий пример я напишу какесли вы использовали SQLite, но большинство драйверов баз данных используют Python Database API и в значительной степени взаимозаменяемы, поэтому код должен работать с минимальными изменениями:
import sqlite3
connection = sqlite3.connect("your_db") # connect to the database
cursor = connection.cursor() # grab a database cursor
results = cursor.execute("select * from your_table") # execute the select query
header = [c[0] for c in cursor.description] # get the column names for our CSV header
И, наконец, мы можем выполнить итерацию порезультаты, обработайте каждое поле и сохраните все в CSV:
import csv
with open("output.csv", "w", newline="") as f: # open("output.csv", "wb") on Python 2.x
writer = csv.writer(f, delimiter="\t") # create a CSV writer with \t as a delimiter
writer.writerow(header) # write the header (column names)
for result in results: # iterate over the returned results
writer.writerow(map(trans_field, result)) # process result fields and write the row
Это исключает все ненужные преобразования и должно работать так же быстро, как Python и ваша база данных.Технически вы могли бы выжать еще большую скорость, проверив cursor.description
и создав карту замены только для строк в наборе результатов (вместо попыток обработать каждое поле), но это, вероятно, не сильно увеличит общую скорость..
Итак, собрав все вместе:
import csv
import sqlite3
chr_ranges = (0x00, 0x09), (0x0B, 0x20), (0x7F, 0xA0) # 'special' character ranges
trans_table = {x: " " for r in chr_ranges for x in range(*r)} # 'special'->space trans. table
def trans_field(value):
try:
return value.translate(trans_table) # try to translate and return
except AttributeError: # if there's no translate method on the passed value...
return value # return the original value
connection = sqlite3.connect("your_db") # connect to the database
cursor = connection.cursor() # grab a database cursor
results = cursor.execute("select * from your_table") # execute the select query
header = [c[0] for c in cursor.description] # get the column names for our CSV header
with open("output.csv", "w", newline="") as f: # open("output.csv", "wb") on Python 2.x
writer = csv.writer(f, delimiter="\t") # create a CSV writer with \t as a delimiter
writer.writerow(header) # write the header (column names)
for result in results: # iterate over the returned results
writer.writerow(map(trans_field, result)) # process result fields and write the row
В качестве теста я создал таблицу 31x1M
в SQLite с 22 * 1040 * полями (каждое заполнено 10-50случайные символы в диапазоне 0x00 - 0xA0
, вкрапленные полями INTEGER
и REAL
, и в моей системе он очистил данные и выдал output.csv
за 56 секунд.YMMV, конечно, но это определенно не должно занимать 16 минут.