Вопрос

Я нашел этот сценарий Perl, пока перенос моей базы данных SQLite в MySQL

Мне было интересно (поскольку я не знаю Perl), как можно переписать это на Python?

Бонусные баллы за самый короткий (кодовый) ответ :)

редактировать:извините, я имел в виду кратчайший код, а не строго кратчайший ответ

#! /usr/bin/perl

while ($line = <>){
    if (($line !~  /BEGIN TRANSACTION/) && ($line !~ /COMMIT/) && ($line !~ /sqlite_sequence/) && ($line !~ /CREATE UNIQUE INDEX/)){

        if ($line =~ /CREATE TABLE \"([a-z_]*)\"(.*)/){
                $name = $1;
                $sub = $2;
                $sub =~ s/\"//g; #"
                $line = "DROP TABLE IF EXISTS $name;\nCREATE TABLE IF NOT EXISTS $name$sub\n";
        }
        elsif ($line =~ /INSERT INTO \"([a-z_]*)\"(.*)/){
                $line = "INSERT INTO $1$2\n";
                $line =~ s/\"/\\\"/g; #"
                $line =~ s/\"/\'/g; #"
        }else{
                $line =~ s/\'\'/\\\'/g; #'
        }
        $line =~ s/([^\\'])\'t\'(.)/$1THIS_IS_TRUE$2/g; #'
        $line =~ s/THIS_IS_TRUE/1/g;
        $line =~ s/([^\\'])\'f\'(.)/$1THIS_IS_FALSE$2/g; #'
        $line =~ s/THIS_IS_FALSE/0/g;
        $line =~ s/AUTOINCREMENT/AUTO_INCREMENT/g;
        print $line;
    }
}

Для успешной миграции базы данных sqlite потребовался некоторый дополнительный код (обрабатывает одну строку. Операторы создания таблицы, внешние ключи, исправляет ошибку в исходной программе, которая преобразовывала пустые поля. '' к \'.

я опубликовал код переноса моей базы данных SQLite в MySQL. Вопрос

Это было полезно?

Решение

Вот довольно дословный перевод с минимумом очевидных изменений стиля (помещение всего кода в функцию, использование строк, а не повторных операций, где это возможно).

import re, fileinput

def main():
  for line in fileinput.input():
    process = False
    for nope in ('BEGIN TRANSACTION','COMMIT',
                 'sqlite_sequence','CREATE UNIQUE INDEX'):
      if nope in line: break
    else:
      process = True
    if not process: continue
    m = re.search('CREATE TABLE "([a-z_]*)"(.*)', line)
    if m:
      name, sub = m.groups()
      line = '''DROP TABLE IF EXISTS %(name)s;
CREATE TABLE IF NOT EXISTS %(name)s%(sub)s
'''
      line = line % dict(name=name, sub=sub)
    else:
      m = re.search('INSERT INTO "([a-z_]*)"(.*)', line)
      if m:
        line = 'INSERT INTO %s%s\n' % m.groups()
        line = line.replace('"', r'\"')
        line = line.replace('"', "'")
    line = re.sub(r"([^'])'t'(.)", r"\1THIS_IS_TRUE\2", line)
    line = line.replace('THIS_IS_TRUE', '1')
    line = re.sub(r"([^'])'f'(.)", r"\1THIS_IS_FALSE\2", line)
    line = line.replace('THIS_IS_FALSE', '0')
    line = line.replace('AUTOINCREMENT', 'AUTO_INCREMENT')
    print line,

main()

Другие советы

Решение Алекса Мартелли выше работает хорошо, но требует некоторых исправлений и дополнений:

В строках, использующих подстановку регулярных выражений, вставка совпадающих групп должна иметь двойное экранирование ИЛИ строка замены должна иметь префикс r, чтобы пометить ее как регулярное выражение:

line = re.sub(r"([^'])'t'(.)", "\\1THIS_IS_TRUE\\2", line)

или

line = re.sub(r"([^'])'f'(.)", r"\1THIS_IS_FALSE\2", line)

Кроме того, эту строку следует добавить перед печатью:

line = line.replace('AUTOINCREMENT', 'AUTO_INCREMENT')

Наконец, имена столбцов в операторах создания должны быть обратными кавычками в MySQL.Добавьте это в строку 15:

  sub = sub.replace('"','`')

Вот полный скрипт с изменениями:

import re, fileinput

def main():
  for line in fileinput.input():
    process = False
    for nope in ('BEGIN TRANSACTION','COMMIT',
                 'sqlite_sequence','CREATE UNIQUE INDEX'):
      if nope in line: break
    else:
      process = True
    if not process: continue
    m = re.search('CREATE TABLE "([a-z_]*)"(.*)', line)
    if m:
      name, sub = m.groups()
      sub = sub.replace('"','`')
      line = '''DROP TABLE IF EXISTS %(name)s;
CREATE TABLE IF NOT EXISTS %(name)s%(sub)s
'''
      line = line % dict(name=name, sub=sub)
    else:
      m = re.search('INSERT INTO "([a-z_]*)"(.*)', line)
      if m:
        line = 'INSERT INTO %s%s\n' % m.groups()
        line = line.replace('"', r'\"')
        line = line.replace('"', "'")
    line = re.sub(r"([^'])'t'(.)", "\\1THIS_IS_TRUE\\2", line)
    line = line.replace('THIS_IS_TRUE', '1')
    line = re.sub(r"([^'])'f'(.)", "\\1THIS_IS_FALSE\\2", line)
    line = line.replace('THIS_IS_FALSE', '0')
    line = line.replace('AUTOINCREMENT', 'AUTO_INCREMENT')
    if re.search('^CREATE INDEX', line):
        line = line.replace('"','`')
    print line,

main()

Вот немного улучшенная версия оригинала.

#! /usr/bin/perl
use strict;
use warnings;
use 5.010; # for s/\K//;

while( <> ){
  next if m'
    BEGIN TRANSACTION   |
    COMMIT              |
    sqlite_sequence     |
    CREATE UNIQUE INDEX
  'x;

  if( my($name,$sub) = m'CREATE TABLE \"([a-z_]*)\"(.*)' ){
    # remove "
    $sub =~ s/\"//g; #"
    $_ = "DROP TABLE IF EXISTS $name;\nCREATE TABLE IF NOT EXISTS $name$sub\n";

  }elsif( /INSERT INTO \"([a-z_]*)\"(.*)/ ){
    $_ = "INSERT INTO $1$2\n";

    # " => \"
    s/\"/\\\"/g; #"
    # " => '
    s/\"/\'/g; #"

  }else{
    # '' => \'
    s/\'\'/\\\'/g; #'
  }

  # 't' => 1
  s/[^\\']\K\'t\'/1/g; #'

  # 'f' => 0
  s/[^\\']\K\'f\'/0/g; #'

  s/AUTOINCREMENT/AUTO_INCREMENT/g;
  print;
}

все скрипты на этой странице не могут работать с простым sqlite3:

PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE Filename (
  FilenameId INTEGER,
  Name TEXT DEFAULT '',
  PRIMARY KEY(FilenameId) 
  );
INSERT INTO "Filename" VALUES(1,'');
INSERT INTO "Filename" VALUES(2,'bigfile1');
INSERT INTO "Filename" VALUES(3,'%gconf-tree.xml');

Ни один из них не смог переформатировать «table_name» в правильное `table_name` MySQL.Некоторые перепутали пустое строковое значение.

Я не уверен, что в этом такого сложного понять, что требуется ехидное замечание, как в вашем комментарии выше.Обратите внимание, что <> называется алмазным оператором. s/// является оператором замены и // это оператор сопоставления m//.

На основе http://docs.python.org/dev/howto/regex.html ...

  1. Заменять $line =~ /.*/ с re.search(r".*", line).
  2. $line !~ /.*/ просто !($line =~ /.*/).
  3. Заменять $line =~ s/.*/x/g с line=re.sub(r".*", "x", line).
  4. Заменять $1 через $9 внутри re.sub с \1 через \9 соответственно.
  5. Вне подпрограммы сохраните возвращаемое значение, т.е. m=re.search(), и заменить $1 с возвращаемым значением m.group(1).
  6. Для "INSERT INTO $1$2\n" в частности, вы можете сделать "INSERT INTO %s%s\n" % (m.group(1), m.group(2)).

Реальная проблема заключается в том, знаете ли вы, как перенести базу данных?То, что представлено, представляет собой просто цикл поиска и замены.

Самый короткий?Тильда означает регулярное выражение в Perl.«импортировать повторно» и идти оттуда.Единственное ключевое отличие состоит в том, что вы будете использовать \1 и \2 вместо $1 и $2 при присвоении значений, а %s — при замене совпадений с регулярными выражениями внутри строк.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top