我在migrating my SQLite database to 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数据库需要一些额外的代码(处理一行创建表语句,外键,修复原始程序中将空字段''
转换为\'
的错误。
我posted the code on the migrating my SQLite database to mysql Question
答案 0 :(得分:49)
这是一个非常直观的翻译,只有最少的明显样式更改(将所有代码放入函数中,使用字符串而不是重新操作)。
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()
答案 1 :(得分: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')
最后,create语句中的列名应该是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()
答案 2 :(得分:7)
这是原版的稍微好一点。
#! /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;
}
答案 3 :(得分: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`。有些搞砸了空字符串值。
答案 4 :(得分:3)
基于http://docs.python.org/dev/howto/regex.html ...
$line =~ /.*/
替换为re.search(r".*", line)
。$line !~ /.*/
只是!($line =~ /.*/)
。$line =~ s/.*/x/g
替换为line=re.sub(r".*", "x", line)
。$1
内的$9
分别改为re.sub
,\1
改为\9
。m=re.search()
,并将$1
替换为m.group(1)
的返回值。"INSERT INTO $1$2\n"
,您可以执行"INSERT INTO %s%s\n" % (m.group(1), m.group(2))
。答案 5 :(得分:3)
我不确定这有什么难以理解的,它需要讽刺评论,如上面的评论。请注意,<>
称为菱形运算符。 s///
是替换运算符,//
是匹配运算符m//
。
答案 6 :(得分:2)
真正的问题是你知道如何迁移数据库吗?所呈现的仅仅是搜索和替换循环。
答案 7 :(得分:1)
最短?代字号表示perl中的正则表达式。 “导入重新”并从那里开始。唯一的关键区别在于,当您分配值时,您将使用\ 1和\ 2而不是$ 1和$ 2,并且当您替换字符串内的regexp匹配时,您将使用%s。