\Q 和 \E 中的哈希

Hash inside \Q and \E

我想将包含散列(或井号字符“#”)的模式与 perl 匹配:

#!/usr/bin/perl

use strict;
use warnings;
use utf8;

if( $#ARGV + 1 != 2 ) {
    die "ERROR: Number of command line arguments is not 2";
}
my $input = $ARGV[ 0 ];
my $output = $ARGV[ 1 ];

open( my $ifh, "<:encoding(UTF-8):crlf", "$input" )
    || die "ERROR: Failed to open input file: $!";
my $content = do { local $/; <$ifh> };

open( my $ofh, ">:encoding(UTF-8):crlf", "$output" )
    || die "ERROR: Failed to open output file: $!";

eval { # GLOBAL EXCEPTION HANDLER BEGIN

{ ( ( my $fix, my $dat, my $rest ) = ( $content
=~ / ^ ( \Q# started on \E ) ([^\n]+) \n{3}
       (.*)
     $ /xs
) ) || die "ERROR: No match";
print $ofh __LINE__ . "\tDate\t$dat\n";
$content = $rest; }

}; if( $@ ) { print $ofh "$@____________\n"; print $ofh "$content"; } # GLOBAL EXCEPTION HANDLER END

这给出了以下错误消息:

Unmatched ( in regex; marked by <-- HERE in m/ ^ (  <-- HERE \#\ started\ on\ \E\ \)\ \(\[\^\n\]\+\)\ \n\{3\}\
\ \ \ \ \ \ \ \(\.\*\)\
\ \ \ \ \ $\ / at ./example.pl line 25.

但是,如果我这样修改它,那么它就完美了:

{ ( ( my $fix, my $dat, my $rest ) = ( $content
=~ / ^ ( \# \Q started on \E ) ([^\n]+) \n{3}
       (.*)
     $ /xs
) ) || die "ERROR: No match";
print $ofh __LINE__ . "\tDate\t$dat\n";
$content = $rest; }

不过,我更愿意将主题标签保留在 \Q\E 块中。

那么问题来了,\Q\E是不是把里面的东西都转义了?或者这里有什么问题?

# 在带有 /x 的正则表达式中引入注释。即使在 /x.

下的 \Q...\E 中,您也需要反斜杠

顺便说一句,通过使用 or 而不是 || 进行流量控制,可以使 eval 内的部分更具可读性(无论如何,这是推荐的做法)。另外,不要在错误后继续设置 $@,旧的 Perl 版本中存在错误导致无法正确设置。相反,return 来自 eval 的真实值并检查它,例如

{
    ( my $fix, my $dat, my $rest )
        = $content =~ / ^ ( \Q \# started on \E ) ([^\n]+) \n{3}
                        (.*)
                        $
                      /xs or die "ERROR: No match";
1 } or do { # Handle the exception...

更新: 这是 Perl 中的一个错误。请注意,它仅在字面上使用 octothorpe 时才会命中,即您可以将其存储在变量中并且它会起作用:

my $octothorpe = '#';
print 'a # b' =~ /(\Q $octothorpe \E) b/x