如何使用Perl和Regular Expressions将SQL文档转换为ColdFusion脚本?

时间:2011-04-08 21:34:24

标签: regex perl

我需要将SQL语句的文档转换为ColdFusion文档。我对正则表达式只有一点经验而且我是Perl super-newb(我昨天只是自学了它的基础知识,所以我可以完成这个任务。)

我正在尝试使用Perl编写的脚本匹配和替换模式,在BBEdit中保存为Filter,我在打开的文档上运行。好消息是它主要起作用,但坏消息是它不能完全发挥作用。我很确定这与我对多行匹配的有限理解以及在段落中解析整个文档有关。

我得到一个看起来像这样的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 \ n)分隔的语句。它们之间没有额外线的那些没有按预期被替换。请注意上面的三个更新语句 - 它适用于三个中的第一个,但不适用于剩下的两个。)

我猜这与我的模式和$ / ='';的使用有关,我认为这会使脚本读入段落而不是行。

我知道有很多方法可以解决这个问题,但这就是让我最接近的方法。我从网上的例子和一些反复试验中将它拼凑在一起。我知道这对于非新手来说一定很简单,但是我需要一些指示。

任何人都可以帮我完全开始工作吗?

3 个答案:

答案 0 :(得分:0)

来自perlvar.html docs:
$/输入记录分隔符,默认为换行符。这影响了Perl关于“线”是什么的想法。像awk的RS变量一样工作,包括将空行设置为终止符(如果设置为空字符串)。 (空行不能包含任何空格或制表符。)

如果您使用$/,则应始终为本地 我个人会这样做:

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

但你可以像下面这样做,但你必须包含/g修饰符 看看Perl抓住的>>>块。 $/ 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__

答案 1 :(得分:0)

您可以利用输入文件中的各个sql语句以分号字符终止的事实。在perl脚本中将记录输入分隔符设置为分号$/ = ';',然后在每次读取STDIN时读取一个完整的sql语句,无论它跨越多少实际行。

#!/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;
}

答案 2 :(得分:0)

一旦你在声明中有;,你就会受伤。使用像SQL::SplitStatement这样的专用工具,这非常精确。