2009-07-01 68 views
19

我发现虽然migrating my SQLite database to mysql翻译的Perl到Python

这个Perl脚本我想知道(因为我不知道的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; 
    } 
} 

一些额外的代码是必要的成功迁移源码数据库(处理一行)创建表语句,外键,修复原始程序中将空字段''转换为\'的错误

posted the code on the migrating my SQLite database to mysql Question

+17

这难以阅读吗?这可能是有史以来最可读的perl程序。 – 2009-07-01 03:09:44

+7

说了很多关于perl;) – Jiaaro 2009-07-01 03:21:49

+5

@John Kugelman我认为如果没有`$ line`变量,它会更具可读性。 – 2009-07-01 03:22:09

回答

47

这是一个很简单的翻译,只需要最少的显式样式更改(将所有代码放入函数中,在可能的情况下使用字符串而不是重新操作)。

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

基于http://docs.python.org/dev/howto/regex.html ...

  1. 更换$line =~ /.*/re.search(r".*", line)
  2. $line !~ /.*/只是!($line =~ /.*/)
  3. line=re.sub(r".*", "x", line)替换$line =~ s/.*/x/g
  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))
3

我不知道什么是很难理解这个,它需要一个讽刺的评论,如在你的评论上面。请注意,<>被称为钻石操作员。 s///是替代运算符,//是匹配运算符m//

1

最短?代字符表示perl中的正则表达式。 “重新导入”并从那里开始。唯一的区别在于,当您分配值时,您将使用\ 1和\ 2而不是$ 1和$ 2,并且当您替换字符串内的正则表达式匹配时,您将使用%s。

1

真正的问题是你知道如何迁移数据库吗?所呈现的仅仅是一个搜索和替换循环。

6

这是一个稍微好一点的原始版本。

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

Alex Martelli's solution above的作品不错,但需要一些修正和补充:

在使用正则表达式替换,匹配组的插入必须是双重逸出行或替换字符串必须被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() 
5

这个网页的所有脚本,不能用简单的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”重新格式化为适当的mysql的`table_name`。一些搞砸了空字符串值。