Question

J'ai trouvé ce script Perl en migration ma base de données SQLite mysql

Je me demandais (puisque je ne sais pas Perl) comment pourrait-on réécrire ce en Python?

Les points bonus pour le plus court (code) réponse:)

modifier : désolé, je voulais dire code le plus court, pas strictement réponse la plus courte

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

code supplémentaire était nécessaire pour migrer avec succès la base de données SQLite (poignées une ligne Créer des déclarations de table, clés étrangères, corrige un bug dans le programme original qui a converti des champs vides à '' \'.

Je a affiché le code sur la migration mon SQLite base de données mysql question

Était-ce utile?

La solution

Voici une traduction assez littérale avec le minimum de changements de style évidents (mettre tout le code en fonction, chaîne à l'aide plutôt que des opérations re si possible).

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

Autres conseils

solution d'Alex Martelli ci-dessus fonctionne bien, mais a besoin de quelques corrections et ajouts :

Dans les lignes en utilisant une substitution d'expression régulière, l'insertion des groupes appariés doit être double échappement ou de la chaîne de remplacement doit être précédé de r est de marquer comme expression régulière:

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

ou

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

En outre, cette ligne doit être ajoutée avant impression:

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

Enfin, les noms de colonnes dans les instructions create doivent être backticks dans MySQL. Ajouter cette ligne 15:

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

Voici le script complet avec des modifications:

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

Voici une version légèrement meilleure de l'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;
}

tous les scripts sur cette page ne peut pas traiter sqlite3 simple:

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

Aucun ont pu reformater « nom_table » dans `la table_name` de MySQL appropriée. Certains foiré valeur de chaîne vide.

Je ne sais pas ce qui est si difficile à comprendre au sujet de ce qu'il exige une remarque narquoise que dans votre commentaire ci-dessus. Notez que l'on appelle <> opérateur diamant. Est l'opérateur s/// de substitution et est l'opérateur // match m//.

Basé sur http://docs.python.org/dev/howto/regex .html ...

  1. Remplacer avec $line =~ /.*/ re.search(r".*", line).
  2. $line !~ /.*/ est juste !($line =~ /.*/).
  3. Remplacer avec $line =~ s/.*/x/g line=re.sub(r".*", "x", line).
  4. Remplacer par $1 à l'intérieur $9 avec re.sub par \1 respectivement \9.
  5. En dehors d'un sous, enregistrez la valeur de retour, à savoir m=re.search() et remplacez la valeur m.group(1) de retour de "INSERT INTO $1$2\n".
  6. Pour spécifiquement "INSERT INTO %s%s\n" % (m.group(1), m.group(2)), vous pouvez le faire <=>.

vraie question est savez-vous vraiment comment migrer la base de données? Ce qui est présenté est simplement une boucle de recherche et de remplacement.

Shortest? Le tilde signifie un regex en Perl. « Import re » et aller de là. Les seules différences principales sont que vous allez utiliser \ 1 et \ 2 au lieu de 1 et 2 $ lorsque vous attribuez des valeurs, et vous serez en utilisant% s lorsque vous remplacez les regexp dans les chaînes.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top