【问题标题】:Perl: apply regular expressions in sequencePerl:按顺序应用正则表达式
【发布时间】:2021-04-19 16:04:45
【问题描述】:

我在编写 Perl 单行代码时需要帮助

  1. 在文件中查找字符串并
  2. 从该字符串中提取一个浮点数或一个指数。

例如,我有一个名为results.log的文本文件:

...
TOL: 0.0244141
ort: 0.000282395
Q orthogonality: True

EPS: 0.000488281
err: 9.58692e-05
QR decomposition: True

Success: True
...

它包含数值实验的结果。我想找到以TOL: 开头的行并提取公差值0.0244141。我可以写一个单行来找到以TOL开头的行:

perl -ne '/TOL:/ && print' results.log
TOL: 0.0244141

我可以找到一行包含浮点数0.0244141

echo "TOL: 0.0244141" | perl -ne '/\d+.\d+/ && print'

有没有办法将两个正则表达式“堆叠”在一起并依次应用它们以提取数值本身?换句话说,是否可以将正则表达式应用于前面的正则表达式的结果?

为了完成这个任务,我想从 Perl 脚本中调用这个单行代码并将提取的结果存储到一个变量中:

my $tol = system( qq{ perl -ne '... && print' results.log } );

【问题讨论】:

  • 这就像一个 XY-problem 包裹在一个 XY 问题中。 ;) 从 Perl 内部调用 Perl 单行代码可能被认为有些奇怪。您可以使用常规代码以更少的问题完成相同的事情。而且,system() 不返回输出,您需要qx() 或反引号。
  • 我完全同意你的评论。但我认为以常规代码方式(打开文件,解析并关闭文件)来查找单个值是一种过度杀伤力。如果我错了,请纠正我。
  • 嗯,这就是你正在做的事情......但你做的更慢,更复杂,更容易出错。
  • 我明白了。你能告诉我一个更好的方法来从脚本中做到这一点,一种正确的 Perl 方式吗?

标签: regex perl text-extraction


【解决方案1】:

一个不错且灵活的解决方案是将值读入哈希,然后您可以随意使用值。

use strict;
use warnings;

my $log = "results.log";
open my $fh, "<", $log or die "Cannot open $log: $!";
my %log;     # declare variable to store values

while (<$fh>) {   # while we can read a line from the file
    chomp;        # remove newline
    my ($key, $val) = split / *: */, $_, 2;   # split the line on :, also remove whitespace
    next unless defined $val;     # skip lines which do not contain values
    $log{$key} = $val;            # store the value in the appropriate key
}

print $log{TOL};    # <--- value is in $log{TOL}

文件中的所有值都存储在%log 中。当然,如果你只是对 TOL 值感兴趣,你可以这样做

my $tol;
while (<$fh>) {
    if (/^TOL: (.+)/) {
        $tol = $1;
        last;              # skip to end
    }
}

与不使用 shell 调用相比的好处是错误控制更快、更容易。

【讨论】:

  • 您能否解释一下,my %log; 在第一个代码 sn-p 的 while 循环中做了什么以及发生了什么?
  • my 只是声明了一个变量。我加了cmets来解释一下。
【解决方案2】:

如果我理解正确,你只需要连接你已经得到的正则表达式:

perl -ne '/TOL: (\d+.\d+)/ && print $1 . "\n"' results.log

输出:

0.0244141

括号使它捕获所有匹配的内容。每对 ( ... ) 将匹配的内容分配给一个新的编号变量。第一场比赛$1,第二场比赛$2等等。

关于该主题的更多信息:Capture groups


如果您希望它作为现有 perl 脚本的一部分,请不要使用system() 来启动另一个 perl 解释器。只需从现有脚本中打开文件。这是我将其放入sub 例程的示例。

sub print_TOL {
    # extract the first argument to the function
    my $filename = shift;

    # open the file - or `die` with an error message
    open my $fh, '<', $filename or die "$0: ERROR: $filename: $!";

    # read line by line from the file into $_
    while(<$fh>) {
        if( /TOL: (\d+.\d+)/ ) {  # same match as before
            print $1 . "\n";
            # If you only want to print the first match, use "last;" here.
            #last;  
        }
    }
}

print_TOL 'results.log';

【讨论】:

  • 是的,我只需要号码。您能否详细解释第二个命令?我不明白括号和$1 的用法。这些概念在 Perl 中是如何调用的?如果可能的话,请您指导我到一个资源,在那里我可以阅读到它们?谢谢!
  • @mabalenk 不客气!我添加了解释和指向 perldoc 页面的链接,其中包含更多信息。希望它让它更清楚一点。
  • 参数. "\n"是做什么的?没有它们,该命令似乎也能工作。
  • @mabalenk 它在每个打印行的末尾添加一个换行符。如果您在文件中获得多个匹配项,否则它们将在同一行上一个接一个地打印。
  • 他正在打印一个换行符,以便在您在终端中测试命令时不会搞砸您的提示。您可以使用-l 开关完成同样的操作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多