在Perl中,如何使用多个正则表达式匹配跳过从DBI select返回的某些行?

时间:2012-05-01 16:20:36

标签: regex perl

当我写出HTML::Table时,我想跳过某些行。这应该根据我从网页上获得的一些用户参数来完成,并将它们编译为正则表达式。

参数是大写NOT_*,其值为cc08或邮政编码等等。

my $nameRegex =    ($NOT_NAME)  ? qr/$NOT_NAME/  : '';
my $rackRegex =    ($NOT_RACK)  ? qr/$NOT_RACK/  : '';
my $unitRegex =    ($NOT_UNIT)  ? qr/$NOT_UNIT/  : '';
my $addressRegex = ($NOT_ADDR)  ? qr/$NOT_ADDR/  : ''; 
my $townRegex  =   ($NOT_TOWN)  ? qr/$NOT_TOWN/  : '';
my $pcodeRegex =   ($NOT_PCODE) ? qr/$NOT_PCODE/ : '';

在while循环中(对于其他地方的SQL查询)我得到数据,我认为我正在做的是“除非你匹配其中任何一个”添加这一行结果。

while ((my $id, my $name, my $rack, my $unit, my $town, my $address, my $pcode, my $lat, my $lon) = $select_sites->fetchrow_array()) {
        my $checkbox = "<input type='checkbox' name='FILTER_SITE' value='$id' $checked{$id} />";

        unless ($name =~ $nameRegex
            || $rack =~ $rackRegex
            || $unit =~ $unitRegex
            || $address =~ $addressRegex
            || $town =~ $townRegex 
            || $pcode =~ $pcodeRegex) {

            $rows++;
            $sitesResultSection->addRow($checkbox, $name, $rack, $unit, $town, $address, $pcode, $lat, $lon);
        }

对于$NOT_RACK = "cc08"

,吐出正则表达式看起来像这样
  = qr//;
 (?-xism:cc08) = qr/cc08/;
  = qr//;
  = qr//; 
   = qr//;
  = qr//;

但问题是根本没有添加任何行,而“cc08”中必须省略查询中的一个结果,并且必须显示所有其他结果。

我在HTML中执行此操作的原因是因为SQL查询中已经有其他过滤器(显着限制结果集)并根据用户输入使这些过滤器动态化将是一场噩梦。

接受了答案,但我还有一个问题:

这是我初始化那些NOT_s的方式,与我用于查询的REGEXP条件的方式相同。因此,当用户输入“城市机架名称”时,它将在City

中显示机架
my $NOT_NAME = &useOrs(&trim($cgi->param('NOT_NAME')));
my $NOT_RACK = &useOrs(&trim($cgi->param('NOT_RACK')));
my $NOT_UNIT = &useOrs(&trim($cgi->param('NOT_UNIT')));
my $NOT_ADDR = &useOrs(&trim($cgi->param('NOT_ADDR')));
my $NOT_TOWN = &useOrs(&trim($cgi->param('NOT_TOWN')));
my $NOT_PCODE= &useOrs(&trim($cgi->param('NOT_PCODE')));

my $QUICK_SEARCH_SITES = &trim($cgi->param('QUICK_SEARCH_SITES'));
my $searchRegexp = ($QUICK_SEARCH_SITES) ? &useOrs($QUICK_SEARCH_SITES) : '.*';

sub useOrs {
    my $tmp = $_[0];
    $tmp =~ s/\s+/|/g;
    return $tmp;
}

以下是SQL查询WHERE name REGEXP ? OR rack-id REGEXP ? OR [..]的摘录 因此,使用这些黑客可以实现一些合理的灵活性,而无需训练将使用该工具的猴子。 但是,仅使用$var =~ /$NOT_VAR/显然只会匹配,区分大小写等。 为了实现SQL过滤器的松散而不是使用&useOrs我使用

sub useAny {
    my $tmp = $_[0];
    $tmp =~ s/\s/./g;
    return $tmp;
}

最重要的是$var =~ /.*$NOT_VAR.*/i

我的印象是人们应该用Perl劈开那么那里...... :)建议仍然欢迎。

2 个答案:

答案 0 :(得分:4)

来自perldoc perlop

  

空模式//

     

如果PATTERN评估为空字符串,则为最后一个       使用成功匹配的正则表达式。在       在这种情况下,空模式上只有“g”和“c”标志       荣幸;其他标志取自原始模式。如果       以前没有比赛成功,这将(默默地)行动       而是作为一个真正的空模式(总是匹配)。

因此,您可以使用以下方式让您的生活更轻松:

my $nameRegex = qr/$NOT_NAME/;
my $rackRegex = qr/$NOT_RACK/;
my $unitRegex = qr/$NOT_UNIT/;
my $addressRegex = qr/$NOT_ADDR/; 
my $townRegex  = qr/$NOT_TOWN/;
my $pcodeRegex = qr/$NOT_PCODE/;

或者,更好的是,使用哈希值(代码未经过测试):

use List::MoreUtils qw( any );

my %patterns = (
    name => qr/$NOT_NAME/,
    rack => qr/$NOT_RACK/,
    unit => qr/$NOT_UNIT/,
    address => qr/$NOT_ADDR/,
    town => qr/$NOT_TOWN/,
    pcode => qr/$NOT_PCODE/,
);

while (my $row = $select_sites->fetchrow_hashref("NAME_lc")) {
    my $checkbox = '...';

    next if any { $row->{$_} =~ $patterns{$_} } keys %patterns;

    $rows++;
    $sitesResultSection->addRow(
        $checkbox,
        @{ $row }{qw(name rack unit town address pcode lat lon)}
    }
}

这假设列名与您使用的变量名匹配。

最后,您在SQL where中使用select子句吗?如果可以的话,最好指定在获取数据之前应排除哪些行。

例如,select name, rack, unit, address, town, pcode lat lon from TABLE where rack <> 'cc08' and town <> 'Concord'或其他内容。

答案 1 :(得分:1)

更新:

正如SinanÜnür所指出的那样,perlop中描述了隐藏的功能,任何空的正则表达式//都将使用最后一个成功匹配的正则表达式。一个非常奇怪的功能,IMO,在这种情况下会导致细微的错误。

这使得在regex中使用变量是个坏主意,除非先检查它们的内容。

<强>解决方案:

应该做什么,IMO,将其交换为子程序,例如:

sub check_var {
    my ($var, $NOT_VAR) = @_;
    return 0 unless $NOT_VAR;
    return ($var =~ /$NOT_VAR/);
}

然后使用它:

unless ( check_var($name, $NOT_NAME) 
      || check_var($rack, $NOT_RACK)
      ....