Как использовать Perl и регулярные выражения для преобразования документа SQL в скрипт ColdFusion? - PullRequest
0 голосов
/ 09 апреля 2011

Мне нужно преобразовать документ операторов SQL в документ ColdFusion. У меня только небольшой опыт работы с регулярными выражениями, и я супер-новичок в Perl (я только вчера научил его основам, чтобы справиться с этой задачей).

Я пытаюсь сопоставить и заменить шаблон сценарием, написанным на Perl, сохраненным как фильтр в BBEdit, который я запускаю на открытом документе. Хорошая новость в том, что в основном это работает, но плохая новость в том, что она не работает полностью. Я почти уверен, что это связано с моим ограниченным пониманием сопоставления нескольких строк и анализа всего документа в параграфах.

Мне дан документ SQL, который выглядит примерно так (большинство операторов находятся в отдельной строке (т. Е. В абзаце), но не все):


DELETE FROM example_db.example_tbl;

INSERT INTO example_db.example_tbl (
example_id, example_name
)
(
SELECT 
example_id, example_name
FROM example_2_db.example_tbl ORDER BY example_id
);

INSERT INTO example_db.example_tbl
(SELECT * FROM example_2_db.example_tbl ORDER BY example_id);

UPDATE example_db.example_tbl, example_2_db.example_sub_types_tbl, example_2_db.example_tbl SET example_db.example_tbl.example_sub_type_label=example_2_db.example_sub_types_tbl.example_sub_type_label WHERE example_2_db.example_sub_types_tbl.example_sub_type_id = example_2_db.example_tbl.example_sub_type_id AND example_2_db.example_tbl.example_id=example_db.example_tbl.example_id;

UPDATE example_db.example_tbl, example_2_db.example_tbl SET example_db.example_tbl.example_status_label='Example' WHERE example_2_db.example_tbl.example_status='1' AND example_2_db.example_tbl.example_id=example_db.example_tbl.example_id;

UPDATE example_db.example_tbl, example_2_db.example_tbl SET example_db.example_tbl.example_status_label='Example' WHERE example_2_db.example_tbl.example_status='1' AND example_2_db.example_tbl.example_id=example_db.example_tbl.example_id;
UPDATE example_db.example_tbl, example_2_db.example_tbl SET example_db.example_tbl.example_status_label='Example' WHERE example_2_db.example_tbl.example_status='2' AND example_2_db.example_tbl.example_id=example_db.example_tbl.example_id;
UPDATE example_db.example_tbl, example_2_db.example_tbl SET example_db.example_tbl.example_status_label='Example' WHERE example_2_db.example_tbl.example_status='3' AND example_2_db.example_tbl.example_id=example_db.example_tbl.example_id;

Мне нужно обернуть каждый отдельный SQL-оператор в код, чтобы преобразовать страницу в документ ColdFusion. Я никогда не использовал Perl до вчерашнего дня, но он казался идеальным для этой задачи. По большей части у меня это работает, но я сталкиваюсь с проблемой.

Это скрипт Perl, который я запускаю в документе (я упростил замену строки только ради этого вопроса):

#!/usr/bin/perl -w

use strict;
use warnings;

my $num = 0;
$/ = '';
while (<>) {
  s/(INSERT[\s\S]*?;|DELETE[\s\S]*?;|UPDATE[\s\S]*?;|SELECT[\s\S]*?;)/'<!--- SQL Number: ' . ++$num . ' ' . '<p> ' . $1 . "<\/p> --->\r"/e;
  print;
}

__END__

Это работает почти для всех операторов в документах, которые разделены дополнительной строкой (\ r). Те, где между ними нет лишней строки, не заменяются, как ожидалось. Обратите внимание на три оператора обновления выше - он работает с первым из трех, но не с оставшимися двумя.)

Я предполагаю, что это связано с моим шаблоном и использованием $ / = ''; что, я думаю, заставляет скрипт читать в абзацах, а не в строках.

Я знаю, что есть много способов решить эту задачу, но это то, что сделало меня ближе всего. Я собрал это воедино из примеров в Интернете и некоторых проб и ошибок. Я знаю, что это должно быть просто для новичка, но, увы, мне нужны некоторые указатели.

Может ли кто-нибудь помочь мне заставить это работать полностью?

Ответы [ 3 ]

0 голосов
/ 09 апреля 2011

Вы можете воспользоваться тем фактом, что отдельные операторы sql во входном файле заканчиваются точкой с запятой. Установите в качестве входного разделителя записи точку с запятой $/ = ';' в вашем скрипте perl, а затем он будет читать один полный оператор sql при каждом чтении STDIN, независимо от того, сколько фактических строк он охватывает.

#!/usr/bin/perl -w                                                                                                                                                                                                                                                                          

use strict;

$/ = ';';

my $num = 0;
while (my $sql = <>) {
  $sql =~ s/^\s+//;
  printf "<!--- SQL Number: " . ++$num . " <p>$sql</p> --->\n" if $sql;
}
0 голосов
/ 09 апреля 2011

Как только у вас есть ; в заявлении, вам будет больно. Используйте специальный инструмент, такой как SQL :: SplitStatement , это работает точно.

0 голосов
/ 09 апреля 2011

Из документации perlvar.html:
$/ Разделитель входных записей, новая строка по умолчанию. Это влияет на представление Perl о том, что такое «линия». Работает как переменная RS в awk, включая обработку пустых строк как терминатора, если для него задана нулевая строка. (Пустая строка не может содержать пробелов или табуляций.)

Если вы используете $/, он всегда должен быть локальным.
Я лично сделал бы это так:

my $file = join '', <DATA>
$file =~ s/.../.../eg;

Но вы можете сделать это, как показано ниже, но вы должны включить модификатор /g.
Посмотрите на куски >>>, которые перл берет. Когда $/ is set to '', он использует пустую строку в качестве разделителя записей.

use strict;
use warnings;

my $num = 0;

{
   local $/ = '';
   while (<DATA>)
   {
      print ">>> '$_'\n\n";
      s/(INSERT[\s\S]*?;|DELETE[\s\S]*?;|UPDATE[\s\S]*?;|SELECT[\s\S]*?;)/'<!--- SQL Number: ' . ++$num . ' ' . '<p> ' . $1 . "<\/p> --->\n"/eg;
      print;
   }
}

__END__
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...