문제
이 Perl 스크립트를 찾았습니다 내 SQLITE 데이터베이스를 MySQL로 마이그레이션합니다
나는 (Perl을 모르기 때문에) 어떻게 파이썬에서 이것을 다시 작성할 수 있을까요?
가장 짧은 (코드) 답변에 대한 보너스 포인트 :)
편집하다: 죄송합니다. 가장 짧은 코드를 의미했습니다. 엄격하게 가장 짧은 답변이 아닙니다.
#! /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 데이터베이스를 성공적으로 마이그레이션하려면 일부 추가 코드가 필요했습니다 (한 줄 작성 테이블 문 생성, 외래 키, 빈 필드를 변환 한 원래 프로그램에서 버그를 수정합니다. ''
에게 \'
.
해결책
다음은 최소한의 명백한 스타일 변경만으로 꽤 문자 그대로 번역됩니다 (가능한 경우 재 작업 대신 문자열을 사용하여 모든 코드를 함수에 넣습니다).
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()
다른 팁
위의 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')
마지막으로, 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()
다음은 원본의 약간 더 나은 버전입니다.
#! /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;
}
이 페이지의 모든 스크립트는 간단한 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`으로 개혁 할 수 없었습니다. 일부는 빈 문자열 값을 엉망으로 만들었습니다.
나는 이것에 대해 이해하기 어려운 것이 무엇인지 확실하지 않아 위의 의견에서와 같이 snide 비고가 필요합니다. 주목하십시오 <>
다이아몬드 운영자라고합니다. s///
대체 연산자입니다 //
경기 연산자입니다 m//
.
기반 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))
.
실제 문제는 실제로 데이터베이스를 마이그레이션하는 방법을 알고 있습니까? 제시된 것은 단지 검색 및 교체 루프 일뿐입니다.
가장 짧습니까? Tilde는 Perl에서 Regex를 나타냅니다. "가져 오기"와 거기에서 가십시오. 유일한 주요 차이점은 값을 할당 할 때 $ 1 및 $ 2 대신 1 및 2를 사용하고 문자열 내부에서 Regexp 일치를 교체 할 때 %S를 사용하게된다는 것입니다.