سؤال

لقد وجدت هذا Perl حين ترحيل بلدي سكليتي قاعدة بيانات mysql

كنت أتساءل (منذ أنا لا أعرف بيرل) كيف يمكن للمرء كتابة هذا الثعبان ؟

نقاط المكافأة أقصر (رمز) الجواب :)

تحرير:آسف أقصد أقصر رمز, لا بدقة أقصر إجابة

#! /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 (مقابض سطر واحد إنشاء جدول البيانات الخارجية مفاتيح إصلاح الخلل في البرنامج الأصلي أن تحويل حقول فارغة '' إلى \'.

أنا نشرت مدونة على ترحيل بلدي سكليتي قاعدة بيانات 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()

نصائح أخرى

الحل

أليكس مارتيلي في ما سبق يعمل جيدا، ولكن يحتاج إلى بعض الإصلاحات والإضافات :

في خطوط استخدام استبدال التعبير العادية، يجب أن يكون الإدراج المجموعات المتطابقة هرب المزدوج أو يجب أن يبدأ سلسلة الاستبدال مع 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')

وأخيرا، أسماء الأعمدة في إنشاء عبارات يجب أن يكون backticks في الخلية. هذا إضافة في خط 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" في الخلية المناسبة ل`table_name`. بعض افسدت قيمة سلسلة فارغة.

وأنا لست متأكدا ما هو الصعب جدا أن فهم حول هذا الموضوع أنه يتطلب التصريح سنيد كما هو الحال في تعليقك أعلاه. ملاحظة يسمى هذا <> المشغل الماس. 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)).

والقضية الحقيقية هي هل تعرف فعلا كيفية ترحيل قاعدة البيانات؟ ما هو عرض لا يعدو أن يكون البحث والاستبدال حلقة.

وأقصر؟ تيلدا يدل باستخدام التعابير المنطقية في بيرل. "استيراد إعادة" والذهاب من هناك. الاختلافات الرئيسية الوحيدة هي أن عليك أن تكون باستخدام \ 1 و \ 2 بدلا من 1 $ و 2 $ عند تعيين قيم، وعليك أن تكون باستخدام٪ s للعندما كنت استبدال مطابقة التعبير العادي داخل السلاسل.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top