perl正则表达式匹配同一行

jel*_*lly 1 regex perl foreach if-statement hashmap

第一个if ($line =~ ...)语句返回正确的匹配($1),它被分配给 num。

第二个if ($line =~ ...)语句没有返回任何值,因此没有分配给定义散列。我单独测试了这个正则表达式,它确实返回了正确的匹配($1)。

我想$definitions{$file}{$num}被分配给第二个正则表达式的返回值。

谢谢你的帮助。我是 perl/regex 初学者。

my $dir = "/.../...";
my %definitions;
my $num;

opendir (DIR, $dir) or die $!;
    while (my $file = readdir(DIR)) {
        next if ($file =~ m/^\./);
        open FILE, "<$dir/$file" or die $!;
        my @lines = <FILE>;
            foreach my $line (@lines) {
                if ($line =~ m/\', (.*?)\, /g) {
                    $num = $1;
                }
                if ($line =~ m/\'(.*?)\'/g) { # no match is found
                    $definitions{$file}{$num} = $1; # nothing is assigned
                }
            }
        close FILE;
    }
closedir DIR;
Run Code Online (Sandbox Code Playgroud)

编辑:

数据文件示例:(其他文件要长很多,这个是最短的)

('钠阳离子', 169, 183), ('ID 3006450 289000 - 440000', 10, 36)

我试图提取单引号之间的内容并将其分配给定义,然后取第一个数字并将其分配给 num。

zdi*_*dim 5

在我们看到一些数据之前,无法完全回答这个问题。

同时这里是对代码的一些注释。先上节目

use warnings;
use strict;
use 5.012;   # so readdir assigns to $_ in  while (readdir $dh)

my %definitions;

my $dir = '/path/to/dir';
opendir my $dh, $dir  or die "Can't open $dir: $!";

while (my $file = readdir($dh))
{
    next if $file =~ /^\./;
    next if -d $file;        # make sure we don't try to open() a dir

    open my $fh, '<', "$dir/$file" or die "Can't open $dir/$file: $!";

    while (my $line = <$fh>)
    {
        if (my ($num) = $line =~ m/', (.*?), / and    #' 
            my ($val) = $line =~ m/'(.*?)'/       )     
        {
            $definitions{$file}{$num} = $val;
        }   
    }   
    close $fh;
}    
close $dh;
Run Code Online (Sandbox Code Playgroud)

很可能您可以在一个正则表达式中很好地完成两个匹配。请向我们展示一些数据。

注释

  • 始终拥有use warnings;,并且use strict;

  • 额外的缩进似乎有帮助,但它通常会让人更难理解

  • 使用词法文件句柄,my $fh而不是FILE(等)——它们更好

  • 由于V5.12 READDIR受让人到$_作为使用时while (readdir $dh)。然后谨慎起见,至少需要该版本,因此use 5.012. 我把它包括在内,以防它被使用

  • 我们很少需要先将文件读入数组。逐行阅读,while (<$fh>)

  • 小范围声明。$num发布代码中 的 global允许一个错误:当第一个正则表达式失败但第二个匹配时,会为之前$num找到的键分配一个值。原因是对具有依赖性的事物使用单独的s,但 local会有所帮助。ifmy $num

  • 可以从匹配中分配my ($var) = $string =~ /.../,除非有特定原因先测试然后分配。注意括号,施以列表背景上的匹配运算,因为在这种情况下它返回匹配列表。见perlretut

  • 可以声明和分配内部if条件,就像你对while. 在该范围内可以看到变量,就像它应该的那样。这将处理拉入其自己的块中,通常使代码更清晰。我们需要查看数据以寻找更好的方法来做到这一点。

  • /g这里没有意义,虽然它以复杂的方式起作用。见文末评论

  • 正则表达式中的额外转义:无需转义',

  • while循环可以写成

    while (<$fh>) {
        if (my ($num) = /.../ and my ($val) = /.../)    ...
    
    Run Code Online (Sandbox Code Playgroud)

    使用$_ 变量,这是正则表达式的默认值,就像 Perl 中的许多其他操作一样。

冒险进行一些猜测:

  • 该模式.*也不匹配任何内容,因此如果您''之前'stuff'在该行上'(.*?)'匹配'',那么您的模式将匹配,捕获一个空字符串。

  • 第二个正则表达式匹配,但第一个失败,因此没有可分配的键。这与您对正则表达式的测试一致。(你会听到它use warnings的效果。)


/g两个正则表达式中的存在都是错误的,很可能是直接错误(但请注意其他错误)。感谢ikegami的评论。来自perlop 列表上下文中的匹配

在标量上下文中,每次执行都会m//g找到下一个匹配项,如果匹配则返回 true,如果没有进一步匹配则返回 false。[...]

这通常用于结构中,例如while (/(...)/g) { ... }在每次迭代时从最后匹配的位置继续扫描字符串,寻找下一个匹配项。因此,在每次迭代中都会找到一个匹配项,因此在循环内一次处理一个匹配项。

来自文档的短语“找到下一个匹配”隐藏了复杂的行为,这两个if条件/g严重混乱。这可以通过在单独的小脚本中进行测试来看到。

列表上下文中的行为不同,my @all_matches = /(...)/g;。请参阅文档。