将 Perl 翻译成 Python
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1067060/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Translating Perl to Python
提问by Jiaaro
I found this Perl script while migrating my SQLite database to mysql
我在将SQLite 数据库迁移到 mysql时发现了这个 Perl 脚本
I was wondering (since I don't know Perl) how could one rewrite this in Python?
我想知道(因为我不知道 Perl)如何用 Python 重写它?
Bonus points for the shortest (code) answer :)
最短(代码)答案的奖励积分:)
edit: sorry I meant shortest code, not strictly shortest answer
编辑:对不起,我的意思是最短的代码,而不是严格最短的答案
#! /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 = ;
$sub = ;
$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 \n";
$line =~ s/\"/\\"/g; #"
$line =~ s/\"/\'/g; #"
}else{
$line =~ s/\'\'/\\'/g; #'
}
$line =~ s/([^\'])\'t\'(.)/THIS_IS_TRUE/g; #'
$line =~ s/THIS_IS_TRUE/1/g;
$line =~ s/([^\'])\'f\'(.)/THIS_IS_FALSE/g; #'
$line =~ s/THIS_IS_FALSE/0/g;
$line =~ s/AUTOINCREMENT/AUTO_INCREMENT/g;
print $line;
}
}
Some additional code was necessary to successfully migrate the sqlite database (handles one line Create table statements, foreign keys, fixes a bug in the original program that converted empty fields ''
to \'
.
一些额外的代码是成功迁移 sqlite 数据库所必需的(处理一行 Create table 语句、外键,修复了原始程序中将空字段转换''
为\'
.
I posted the code on the migrating my SQLite database to mysql Question
回答by Alex Martelli
Here's a pretty literal translation with just the minimum of obvious style changes (putting all code into a function, using string rather than re operations where 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"THIS_IS_TRUE", line)
line = line.replace('THIS_IS_TRUE', '1')
line = re.sub(r"([^'])'f'(.)", r"THIS_IS_FALSE", line)
line = line.replace('THIS_IS_FALSE', '0')
line = line.replace('AUTOINCREMENT', 'AUTO_INCREMENT')
print line,
main()
回答by bb.
Alex Martelli's solution aboveworks good, but needs some fixes and additions:
上面 Alex Martelli 的解决方案效果很好,但需要一些修复和补充:
In the lines using regular expression substitution, the insertion of the matched groups must be double-escaped OR the replacement string must be prefixed with r to mark is as regular expression:
在使用正则表达式替换的行中,匹配组的插入必须双转义或替换字符串必须以 r 为前缀以标记为正则表达式:
line = re.sub(r"([^'])'t'(.)", "\1THIS_IS_TRUE\2", line)
or
或者
line = re.sub(r"([^'])'f'(.)", r"THIS_IS_FALSE", line)
Also, this line should be added before print:
此外,应在打印之前添加此行:
line = line.replace('AUTOINCREMENT', 'AUTO_INCREMENT')
Last, the column names in create statements should be backticks in MySQL. Add this in line 15:
最后,在 MySQL 中,create 语句中的列名应该是反引号。在第 15 行添加:
sub = sub.replace('"','`')
Here's the complete script with 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()
回答by Brad Gilbert
Here is a slightly better version of the 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 \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;
}
回答by Mickey Mouse
all of scripts on this page can't deal with simple sqlite3:
此页面上的所有脚本都无法处理简单的 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');
None were able to reformat "table_name" into proper mysql's `table_name` . Some messed up empty string value.
没有人能够将 "table_name" 重新格式化为正确的 mysql 的 `table_name`。一些搞砸了空字符串值。
回答by Ken_g6
Based on http://docs.python.org/dev/howto/regex.html...
基于http://docs.python.org/dev/howto/regex.html...
- Replace
$line =~ /.*/
withre.search(r".*", line)
. $line !~ /.*/
is just!($line =~ /.*/)
.- Replace
$line =~ s/.*/x/g
withline=re.sub(r".*", "x", line)
. - Replace
$1
through$9
insidere.sub
with\1
through\9
respectively. - Outside a sub, save the return value, i.e.
m=re.search()
, and replace$1
with the return value ofm.group(1)
. - For
"INSERT INTO $1$2\n"
specifically, you can do"INSERT INTO %s%s\n" % (m.group(1), m.group(2))
.
- 替换
$line =~ /.*/
为re.search(r".*", line)
。 $line !~ /.*/
只是!($line =~ /.*/)
.- 替换
$line =~ s/.*/x/g
为line=re.sub(r".*", "x", line)
。 - 分别将
$1
through$9
inside替换re.sub
为\1
through\9
。 - 在 sub 之外,保存返回值 ie
m=re.search()
,并替换$1
为 的返回值m.group(1)
。 - 对于
"INSERT INTO $1$2\n"
具体而言,你可以做"INSERT INTO %s%s\n" % (m.group(1), m.group(2))
。
回答by Sinan ünür
I am not sure what is so hard to understand about this that it requires a snide remark as in your comment above. Note that <>
is called the diamond operator. s///
is the substitution operator and //
is the match operator m//
.
我不确定这有什么难以理解的地方,以至于需要像上面的评论一样讽刺。请注意,这<>
称为菱形运算符。s///
是替换运算符,//
是匹配运算符m//
。
回答by hpavc
Real issue is do you know actually how to migrate the database? What is presented is merely a search and replace loop.
真正的问题是你真的知道如何迁移数据库吗?所呈现的仅仅是一个搜索和替换循环。
回答by anschauung
Shortest? The tilde signifies a regex in perl. "import re" and go from there. The only key differences are that you'll be using \1 and \2 instead of $1 and $2 when you assign values, and you'll be using %s for when you're replacing regexp matches inside strings.
最短?波浪号表示 perl 中的正则表达式。“导入重新”并从那里开始。唯一的主要区别是,在分配值时将使用 \1 和 \2 而不是 $1 和 $2,并且在替换字符串中的正则表达式匹配时将使用 %s。