2009-07-01 87 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`。一些搞砸了空字符串值。