문제

이 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 데이터베이스를 성공적으로 마이그레이션하려면 일부 추가 코드가 필요했습니다 (한 줄 작성 테이블 문 생성, 외래 키, 빈 필드를 변환 한 원래 프로그램에서 버그를 수정합니다. '' 에게 \'.

내 sqlite 데이터베이스 마이그레이션에 코드를 MySQL 질문으로 게시했습니다.

도움이 되었습니까?

해결책

다음은 최소한의 명백한 스타일 변경만으로 꽤 문자 그대로 번역됩니다 (가능한 경우 재 작업 대신 문자열을 사용하여 모든 코드를 함수에 넣습니다).

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 ...

  1. 바꾸다 $line =~ /.*/ ~와 함께 re.search(r".*", line).
  2. $line !~ /.*/ 그냥이야 !($line =~ /.*/).
  3. 바꾸다 $line =~ s/.*/x/g ~와 함께 line=re.sub(r".*", "x", line).
  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)).

실제 문제는 실제로 데이터베이스를 마이그레이션하는 방법을 알고 있습니까? 제시된 것은 단지 검색 및 교체 루프 일뿐입니다.

가장 짧습니까? Tilde는 Perl에서 Regex를 나타냅니다. "가져 오기"와 거기에서 가십시오. 유일한 주요 차이점은 값을 할당 할 때 $ 1 및 $ 2 대신 1 및 2를 사용하고 문자열 내부에서 Regexp 일치를 교체 할 때 %S를 사용하게된다는 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top