如何在Perl正则表达式中转换看起来像变量插值的纯文本?

时间:2017-12-14 09:28:17

标签: regex perl

我在一些配置文件中有以下几行文本,需要使用Perl解析该文件,找到File:行并使用一些正则表达式替换其内容以添加一些文本等。

File: logs/${byYearMonth}.log

我遇到的问题是正则表达式,因为我想在其中使用${byYearMonth}.log,因为它易于阅读,可以轻松引用等等。但这看起来像Perl的变量插值而我得到以下简化的reg exp的以下编译错误:

... =~ s/...\Q${byYearMonth}.log\E.../.../m;

Global symbol "$byYearMonth" requires explicit package name (did you forget to declare "my $byYearMonth"?)

当然我可以重新编写reg exp,不要让Perl认为它是一个变量名,但上面提供的版本是我认为最容易阅读和搜索的版本。在思考和研究这个问题时,我没有找到任何解决办法,只允许我按原样保存reg exp并通过只添加一些标志或其他任何东西来防止Perl编译错误。

那么,是否有任何(简单)方法告诉Perl一些简单且已经引用的文本不会被插值以摆脱编译错误?

我觉得我错过了一些非常简单的东西,所以感谢您的提示! : - )

3 个答案:

答案 0 :(得分:2)

\Q\E用于引用正则表达式元字符。它们与变量插值无关。

如果使用带有单引号qr''的{​​{1}}构建模式,Perl将不会插入变量。

''

输出:

use feature 'say';

my $foo = 1;
my $bar = qr/$foo/;
say $bar;

但是(?^:1)

qr''

输出:

my $foo = 1;
my $bar = qr'$foo';
say $bar;

答案 1 :(得分:1)

我打算将其他答案称为错误,因为通过正则表达式操纵看起来很像XML的东西是一个坏主意。

如果它实际上不是XML,那么使用看起来像XML但不是XML的数据格式是更糟糕的想法。

所以答案是“使用解析器”(或者,使用XML规范的累计副本生成文件的任何人)。

这样的内容会改变<File>元素的内容:

#!/usr/bin/perl
use strict;
use warnings;

use XML::Twig;

my $xml = XML::Twig -> new -> parsefile ( 'your_file.xml'); 

my $file_elt = $xml -> get_xpath ('//File',0);

print "Original value:", $file_elt -> text,"\n";
$file_elt -> set_text('some/other/path/${byWeek}.log');

$xml -> set_pretty_print ( 'indented' ); 
$xml -> print;

注意 - get_xpath仅在树中的任何位置找到<File>的第一个实例。如果您需要更具体,可以迭代或向xpath添加其他限定符。

例如:

my $target_text = quotemeta '${byYearMonth}'; 
my $search_regex = qr/$target_text/; 

foreach my $file_elt ( $xml -> get_xpath('//File') ) { 
  if ( $file_elt -> text =~ /$search_regex/ ) { 
      ## set it to something else. 
  }
}

答案 2 :(得分:-3)

使用 quotemeta 转义模式,然后编译正则表达式。像这样的东西,它有效...

my $s = q[<timestamp key="byYearMonth" datePattern="yyyy-MM" />
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <File>logs/${byYearMonth}.log</File>
    <Append>true</Append>

    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <Pattern>%date %-5level %logger.%M: %msg%n</Pattern>
    </encoder>
</appender>];

my $pat = quotemeta('${byYearMonth}.log');
my $re = qr[$pat];

$s =~ s/$re/pop/g;

print $s;