将Perl翻译成Python
我在把我的SQLite数据库迁移到MySQL的时候,发现了这个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;
}
}
为了成功迁移SQLite数据库,还需要一些额外的代码(处理一行的创建表语句、外键,并修复了原程序中将空字段''
转换为'
的一个bug)。
8 个回答
8
这是原始内容的一个稍微改进的版本。
#! /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的解决方案效果不错,但需要一些修正和补充:
在使用正则表达式替换的那几行中,匹配到的部分必须进行双重转义,或者替换的字符串前面要加上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()
56
这里是一个非常直接的翻译,只有一些明显的风格调整(把所有代码放进一个函数里,尽量使用字符串操作而不是正则表达式)。
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()