搜索全局变量时 perl 正则表达式不一致

perl regex is inconsistent when searching through global variable

我有一个简单的 perl 脚本查询数据库视图的 dml(如果它看起来很奇怪,请忽略 db->query 位 - 我没有使用 DBI 库),然后将其存储在全局变量中

my $dmlRef = $db->query($sql) || die "cannot query the db $! \n for sql: $sql";
our $dml =  $dmlRef->[0]->{'DML'};

当我在子程序中打印此 dml (print "$main::dml\n") 时,它看起来像这样:

"...来自 schema.MY_CALL_LOG..."

dml是一系列常见的table表达式,所以里面提到了很多模式,风格和上面一样。

所以我有一个 sub,我尝试使用全局变量查找我的模式列表是否在其中,我将 dml 保存到:

sub is_in_view_dll {
        my $schema = shift || die "no schema passed in";
        if ($main::dml =~ m/FROM\s+$schema\.MY_CALL_LOG/ig){ ##use global variable $dml here
                print "found $schema in dml!\n";
        }else{
                print "couldn't find $schema in dml \n";
        }

当我使用它时,我发现 perl 无法正则表达式匹配我列表中的一些模式名称,尽管我检查了 a) 它们在 dml 中 b) 大小写在我的模式列表中匹配(模式名称中没有空格)

当我创建全局 $dml 变量的本地副本时,我发现 perl 正则表达式按预期工作

sub is_in_view_dll {
        my $schema = shift || die "no schema passed in";
        my $localdml = "$main::dml";
        if ($localdml =~ m/FROM\s+$schema\.MY_CALL_LOG/ig){ ##search through local copy of global var 
                print "found $schema in dml!\n";            ##works correctly
        }else{
                print "couldn't find $schema in dml \n";
        }

我不明白为什么直接使用全局变量“$main::dml”对所有匹配尝试都不起作用,而在子的正则表达式中使用它的本地副本却起作用

更多信息/如何复制

我创建了一个精简示例,其中我可以复制这个问题(希望你也可以),其中正在生成的 data/input 作为字符串存储在我们的 $dml 变量中:

#!/usr/bin/perl -I/usr/local/lib/perl

use strict;
use Data::Dumper;

our $dml = <<EOM

  CREATE OR REPLACE FORCE EDITIONABLE VIEW "GWMONITORING"."MY_CALL_LOG" ("OWNER", "DAY", "HOUR", "USERNAME", "CALL_ID") AS
  SELECT
    'DEMOGW'                                AS OWNER,
    TRUNC (TIME_START)                          DAY,
    TO_NUMBER (TO_CHAR (TIME_START, 'HH24'))    HOUR,
    USERNAME,
    CALL_ID
FROM
    DEMOGW.MY_CALL_LOG
UNION ALL
SELECT
    'ARMYS'                                    AS OWNER,
    TRUNC (TIME_START)                          DAY,
    TO_NUMBER (TO_CHAR (TIME_START, 'HH24'))    HOUR,
    USERNAME,
    CALL_ID
FROM
    ARMYS.MY_CALL_LOG
UNION ALL
SELECT
    'GFW'                                     AS OWNER,
    TRUNC (TIME_START)                          DAY,
    TO_NUMBER (TO_CHAR (TIME_START, 'HH24'))    HOUR,
    USERNAME,
    CALL_ID
FROM
    GFW.MY_CALL_LOG
UNION ALL
SELECT
    'GLOBE'                                   AS OWNER,
    TRUNC (TIME_START)                          DAY,
    TO_NUMBER (TO_CHAR (TIME_START, 'HH24'))    HOUR,
    USERNAME,
    CALL_ID
FROM
    GLOBE.MY_CALL_LOG
UNION ALL
SELECT
    'VARS'                                   AS OWNER,
    TRUNC (TIME_START)                          DAY,
    TO_NUMBER (TO_CHAR (TIME_START, 'HH24'))    HOUR,
    USERNAME,
    CALL_ID
FROM
    VARS.MY_CALL_LOG
UNION ALL
SELECT
    'ALLHH'                                    AS OWNER,
    TRUNC (TIME_START)                          DAY,
    TO_NUMBER (TO_CHAR (TIME_START, 'HH24'))    HOUR,
    USERNAME,
    CALL_ID
FROM
    ALLHH.MY_CALL_LOG
UNION ALL
SELECT
    'GW'                                     AS OWNER,
    TRUNC (TIME_START)                          DAY,
    TO_NUMBER (TO_CHAR (TIME_START, 'HH24'))    HOUR,
    USERNAME,
    CALL_ID
FROM
    GW.MY_CALL_LOG
UNION ALL
SELECT
    'QUEEN'                                   AS OWNER,
    TRUNC (TIME_START)                          DAY,
    TO_NUMBER (TO_CHAR (TIME_START, 'HH24'))    HOUR,
    USERNAME,
    CALL_ID
FROM
    QUEEN.MY_CALL_LOG
UNION ALL
SELECT
    'GEORGEY'                                 AS OWNER,
    TRUNC (TIME_START)                          DAY,
    TO_NUMBER (TO_CHAR (TIME_START, 'HH24'))    HOUR,
    USERNAME,
    CALL_ID
FROM
    GEORGEY.MY_CALL_LOG
UNION ALL
SELECT
    'MONKEYS'                                 AS OWNER,
    TRUNC (TIME_START)                          DAY,
    TO_NUMBER (TO_CHAR (TIME_START, 'HH24'))    HOUR,
    USERNAME,
    CALL_ID
FROM
    MONKEYS.MY_CALL_LOG
UNION ALL
SELECT
    'MYPAQS'                                AS OWNER,
    TRUNC (TIME_START)                          DAY,
    TO_NUMBER (TO_CHAR (TIME_START, 'HH24'))    HOUR,
    USERNAME,
    CALL_ID
FROM
    MYPAQS.MY_CALL_LOG
UNION ALL
SELECT
    'GWINV'                                   AS OWNER,
    TRUNC (TIME_START)                          DAY,
    TO_NUMBER (TO_CHAR (TIME_START, 'HH24'))    HOUR,
    USERNAME,
    CALL_ID
FROM
    GWINV.MY_CALL_LOG
UNION ALL
SELECT
    'PRIMER'                                  AS OWNER,
    TRUNC (TIME_START)                          DAY,
    TO_NUMBER (TO_CHAR (TIME_START, 'HH24'))    HOUR,
    USERNAME,
    CALL_ID
FROM
    PRIMER.MY_CALL_LOG
UNION ALL
SELECT
    'GWSTIM'                                AS OWNER,
    TRUNC (TIME_START)                          DAY,
    TO_NUMBER (TO_CHAR (TIME_START, 'HH24'))    HOUR,
    USERNAME,
    CALL_ID
FROM
    GWSTIM.MY_CALL_LOG
UNION ALL
SELECT
    'GFW2'                                    AS OWNER,
    TRUNC (TIME_START)                          DAY,
    TO_NUMBER (TO_CHAR (TIME_START, 'HH24'))    HOUR,
    USERNAME,
    CALL_ID
FROM
    GFW2.MY_CALL_LOG
UNION ALL
SELECT
    'GPETW'                                    AS OWNER,
    TRUNC (TIME_START)                          DAY,
    TO_NUMBER (TO_CHAR (TIME_START, 'HH24'))    HOUR,
    USERNAME,
    CALL_ID
FROM
    GPETW.MY_CALL_LOG
UNION ALL
SELECT
    'GWAHG'                                    AS OWNER,
    TRUNC (TIME_START)                          DAY,
    TO_NUMBER (TO_CHAR (TIME_START, 'HH24'))    HOUR,
    USERNAME,
    CALL_ID
FROM
    GWAHG.MY_CALL_LOG
EOM
;

my @schemas = qw(GW GWAHG GPETW GFW2 GFW GWSTIM DEMOGW GWINV GLOBE PRIMER ARMYS MONKEYS QUEEN VARS ALLHH MYPAQS GEORGEY );

foreach(@schemas){
        is_in_view($_);
}


sub is_in_view {
        my $owner = shift || die "no owner passed in";
        my $localdml = "$main::dml";

        if ($localdml  !~ m/FROM\s+$owner\.MY_CALL_LOG/ig){  ##when you use this line, should find no matches fail to be found
        #if ($main::dml !~ m/FROM\s+$owner\.MY_CALL_LOG/ig){  ##when you use this line, should find that some matches fail to be found. For me this was GPETW, GFW DEMOGW GLOBE ARMYS QUEEN GEORGEY
                print "$owner is not in the dml for GWMONITORING\.MY_CALL_LOG\n";
        }
}

这是正则表达式引擎,它存储最后一个位置并从该位置开始下一场比赛(在 /g 下):

#!/bin/env perl
use strict;
use warnings;
my $string = 'bar foo bar baz';

for my $pat (qw/bar foo bar foo/){
    if ($string =~ /$pat/g){
        print "\nmatch for $pat\n"
    }
    else{
        print "\nno match for $pat\n"
    }
    print pos $string;
}

打印:

match for bar
3
match for foo
7
match for bar
11
no match for foo
Use of uninitialized value in print at command.pl line 13.

最后的匹配会失败,因为在字符串中的 pos 11 之后没有 'foo'。

如果您将 pos $main::dml 的调试打印添加到您的函数或每次 pos($main::dml) = 0; 重置 pos,您将看到效果。

请注意,匹配失败后 pos 会重置。

参考perlrequick