Pregunta

He encontrado este script en Perl, mientras que migrar mi base de datos SQLite a mysql

Me pregunto (ya que no sé Perl) ¿cómo se podría reescribir esta en Python?

Puntos de bonificación para el menor (código) respuesta :)

editar:lo siento, no significaba más corta código, no es estrictamente menor respuesta

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

Algún código adicional necesaria para el buen migrar la base de datos sqlite (maneja una línea de instrucciones Create table, claves foráneas, corrige un error en el original programa que convierte los campos vacíos '' a \'.

Yo publicado el código en el migrar mi base de datos SQLite a mysql Pregunta

¿Fue útil?

Solución

He aquí una traducción bastante literal, con sólo el mínimo de cambios en el estilo obvias (poniendo todo el código en una función, utilizando las operaciones de cadena en lugar de volver siempre que sea posible).

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

Otros consejos

La solución de

Alex Martelli anterior funciona bien, pero necesita algunas correcciones y adiciones :

En las líneas utilizando sustitución expresión regular, la inserción de los grupos emparejados debe ser de doble escape o la cadena de sustitución debe tener el prefijo r para marcar es como expresión regular:

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

o

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

Además, esta línea debe añadirse antes de impresión:

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

Por último, los nombres de columna en instrucciones create debe ser invertidas en MySQL. Añadir esto en la línea 15:

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

Aquí está el guión completo con modificaciones:

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

Aquí es una versión ligeramente mejorada de la 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;
}

todas las secuencias en esta página no puede hacer frente a sqlite3 sencilla:

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');

Ninguno era capaz de cambiar el formato de "nombre_tabla" en `table_name` de MySQL adecuada. Algunos desordenado valor de cadena vacía.

No estoy seguro de qué es tan difícil de entender acerca de esto que se requiere un comentario bajo como en su comentario anterior. Tenga en cuenta que <> se llama el operador de diamante. s/// es el operador de sustitución y // es el operador partido m//.

Basado en http://docs.python.org/dev/howto/regex .html ...

  1. Reemplazar $line =~ /.*/ con re.search(r".*", line).
  2. $line !~ /.*/ es sólo !($line =~ /.*/).
  3. Reemplazar $line =~ s/.*/x/g con line=re.sub(r".*", "x", line).
  4. Reemplazar $1 través $9 dentro re.sub con \1 través \9 respectivamente.
  5. Fuera de un sub, guardar el valor de retorno, es decir m=re.search(), y reemplazar m.group(1) con el valor de retorno de "INSERT INTO $1$2\n".
  6. Para "INSERT INTO %s%s\n" % (m.group(1), m.group(2)) específicamente, puede hacerlo <=>.

tema real es en realidad sabes cómo migrar la base de datos? Lo que se presenta no es más que un bucle de búsqueda y reemplazo.

más corta? La tilde significa una expresión regular en Perl. "Import re" e ir de allí. Las únicas diferencias clave son que se va a utilizar \ 1 y \ 2 en lugar de $ 1 y $ 2 cuando se asignan valores, y que va a utilizar% s para cuando usted está reemplazando coincidencias de expresiones regulares dentro de las cadenas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top