Pergunta

Eu encontrei este script Perl enquanto migrar meu banco de dados SQLite para mysql

Eu estava pensando (desde que eu não sei Perl) como se poderia reescrever isso em Python?

Os pontos de bónus para a resposta mais curta (código):)

Editar : desculpe, eu quis dizer o código mais curto, não resposta estritamente menor

#! /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;
    }
}

Alguns código adicional foi necessário para migrar com êxito o banco de dados SQLite (alças uma linha CREATE TABLE, chaves estrangeiras, corrige um bug no programa original que converteu campos vazios '' para \'.

postou o código da migração meu SQLite banco de dados para Pergunta mysql

Foi útil?

Solução

Aqui está uma tradução muito literal com apenas o mínimo de mudanças de estilo óbvias (colocando todo o código em uma função, usando a corda ao invés de operações de re sempre que possível).

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()

Outras dicas

A solução de

Alex Martelli acima funciona bem, mas precisa de algumas correções e acréscimos :

Nas linhas usando substituição expressão regular, a inserção dos grupos emparelhados deve ser de escape duplo ou a cadeia de substituição deve ser prefixado com a marca r é como expressão regular:

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

ou

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

Além disso, essa linha deve ser adicionado antes de impressão:

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

Por último, os nomes das colunas em criar declarações devem ser backticks em MySQL. Adicione esta na linha 15:

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

Aqui está o script completo com modificações:

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()

Aqui está uma versão ligeiramente melhor do original.

#! /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;
}

todos os scripts nesta página não pode lidar com simples 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');

Nenhum foram capazes de reformatar "table_name" em `table_name` do mysql adequada. Alguns desarrumada valor de cadeia vazia.

Eu não sei o que é tão difícil de entender sobre o que ele requer uma observação snide como em seu comentário acima. Note-se que <> é chamado o operador de diamante. s/// é o operador de substituição e // é o m// operador de jogo.

Com base http://docs.python.org/dev/howto/regex .html ...

  1. Substitua $line =~ /.*/ com re.search(r".*", line).
  2. $line !~ /.*/ é apenas !($line =~ /.*/).
  3. Substitua $line =~ s/.*/x/g com line=re.sub(r".*", "x", line).
  4. Substitua $1 através $9 dentro re.sub com \1 através \9 respectivamente.
  5. Fora de um sub, salvar o valor de retorno, ou seja m=re.search(), e substituir $1 com o valor de retorno de m.group(1).
  6. Para "INSERT INTO $1$2\n" especificamente, você pode fazer "INSERT INTO %s%s\n" % (m.group(1), m.group(2)).

questão real é que você sabe realmente como migrar o banco de dados? O que é apresentado é meramente uma pesquisa e substituir loop.

Shortest? O til significa um regex em Perl. "Import re" e de lá ir. As diferenças apenas principais são que você estará usando \ 1 e \ 2 em vez de US $ 1 e US $ 2 quando você valores atribuir e você estará usando% s para quando você estiver substituindo partidas expressões regulares dentro de strings.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top