Domanda

Ho trovato questo script in Perl, mentre migrare il mio database SQLite a mysql

Mi chiedevo (dato che non conosco il Perl) come si potrebbe riscrivere questo in Python?

Punti Bonus per il più breve (codice) risposta :)

modifica:scusa volevo dire più breve codice, non è strettamente più breve risposta

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

Codice aggiuntivo è necessario per eseguire la migrazione del database sqlite (gestisce una riga di istruzioni Create table, chiavi esterne, corregge un bug nel programma originale che ha convertito i campi vuoti '' per \'.

Io inviato il codice di migrazione mio database SQLite a mysql Domanda

È stato utile?

Soluzione

Ecco una traduzione abbastanza letterale con solo il minimo di cambiamenti di stile di evidenti (mettendo tutto il codice in una funzione, utilizzando stringa piuttosto che le operazioni di ri ove possibile).

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

Altri suggerimenti

Alex Martelli soluzione di cui sopra funziona bene, ma ha bisogno di alcune correzioni ed integrazioni:

Nelle linee usando un'espressione regolare sostituzione, l'inserimento dei gruppi abbinati deve essere il doppio di escape O la stringa di sostituzione deve essere preceduta r a segno è espressione regolare:

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

o

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

Inoltre, questa linea deve essere aggiunto prima della stampa:

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

Ultimo, i nomi delle colonne nella creazione di istruzioni dovrebbero essere gli apici inversi in MySQL.Aggiungere questo in linea 15:

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

Ecco il programma completo con le modifiche:

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

Ecco una versione leggermente migliore di quella originale.

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

tutti gli script in questa pagina non si può fare con semplice 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');

Nessuno era in grado di riformattare "table_name" in `table_name` corretta di MySQL. Alcuni incasinato valore di stringa vuota.

Non sono sicuro di ciò che è così difficile da capire su questo che richiede un'osservazione maligna come nel tuo commento di cui sopra. Si noti che <> si chiama l'operatore diamante. s/// è l'operatore sostituzione e // è l'operatore di corrispondenza m//.

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

  1. Sostituire $line =~ /.*/ con re.search(r".*", line).
  2. $line !~ /.*/ è solo !($line =~ /.*/).
  3. Sostituire $line =~ s/.*/x/g con line=re.sub(r".*", "x", line).
  4. Sostituire $1 attraverso $9 all'interno re.sub con \1 attraverso \9 rispettivamente.
  5. All'esterno un sub, salvare il valore di ritorno, cioè m=re.search(), e sostituire m.group(1) con il valore restituito "INSERT INTO $1$2\n".
  6. Per "INSERT INTO %s%s\n" % (m.group(1), m.group(2)) specificamente, si può fare <=>.

vero problema è fai a sapere in realtà come migrare il database? Quello che viene presentato è solo una ricerca e sostituzione ciclo.

più breve? La tilde indica una regex in perl. "Import re" e passare da lì. Le uniche differenze principali sono che userete \ 1 e \ 2 invece di $ 1 e $ 2 quando si assegnano i valori, e sarete usando% s per quando si sta sostituendo le partite regexp all'interno delle stringhe.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top