Perl正则表达式匹配配置

时间:2014-03-04 15:06:20

标签: regex perl

我正在尝试匹配配置文件中的所有出现并将其存储在散列变量中的perl中。这是我要解析的配置文件:

# commented area
# still commenting
Key1: Value1 
Key2: 2013/03/04 15:41:30
Key3: Value with spaces whatever you pass here fits
Key4:
      value5
      value6
      value7
Key5:
    some other multiline value
    for testing purpose

我已经创建了这个正则表达式,遗憾的是它没有完全正常运行。 Key4仅包含value5,而Key5完全缺失。

正则表达式:

/^(\w+)\:\s*(.+?)(?=^[^\:]+\:)/smg

知道如何改进吗?

3 个答案:

答案 0 :(得分:1)

您可以尝试这样的事情:

^(\w+):\s*(.+?)(?=^[^\n\r:]+:|\z)

我删除了冒号(:)上的转义符,并在否定的类中插入了\n\r。在(?=^[^\:]+\:)结束时value5(.+?)标记为\r\n,因此(.+?)不愿意继续匹配。

使用内部的^[^:]+:会强制|\z匹配,直到下一行包含^(\w+):\s*((?:(?!^[^\r\n:]+:|^#).)+)

然后我添加了.+?以使正则表达式匹配直到结束。然而问题是它可能还会捕获评论,如果上述内容不合适,可能就是这样吗?

.+

这一次,我将key变成了贪婪的^[^\r\n:]+:并添加了对每个字符匹配的检查:下一行的格式不是^#(即匹配{{1}}和换行符再次出现与前面提到的相同的原因)或注释行({{1}})。可能的问题是值之间的注释或不在行开头的注释将进入值。

实际上应该有配置文件解析器,我认为这对于这类任务会更好。

答案 1 :(得分:0)

看起来像 * 。您可以使用YAML::XS(需要libyaml C库)来解析文件并将其存储在标量中:

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;
use YAML::XS;

my $yaml = YAML::XS::LoadFile('config.yaml');

print Dumper $yaml;

输出:

$VAR1 = { 
          'Key5' => 'some other multiline value for testing purpose',
          'Key2' => '2013/03/04 15:41:30',
          'Key1' => 'Value1',
          'Key4' => 'value5 value6 value7',
          'Key3' => 'Value with spaces whatever you pass here fits'
        };

请注意$yaml是哈希引用。


*假设value5value6value7组成单个标量而不是序列中的多个元素。同时假设您的多行值不包含任何标签:#。这肯定是假设很多,但可能适用于你的情况。

答案 2 :(得分:0)

这有点晚了。
我认为正则表达式应该是一个简单的,面向行的 真正的逻辑是在匹配的体内。

这就像我会这样做(有很多方法,这是基本的)。

   ( ^ [^#:\n]+ )                    # (1), Key
   :                                 # :
|                                  # or,
   (?: ^ [^\S\n]* \# .* \n? )        # BOL comments
|                                  # or,
   \# .*                             # EOL comments
|                                  # or,
   ( [^#\n]* \n? )                   # (2), Line value

Perl测试用例

$/ = undef;

$str = <DATA>;

$key = undef;
$keyval = "";
%keyhash = ();
@order = ();

while ($str =~ /(^[^#:\n]+):|(?:^[^\S\n]*\#.*\n?)|\#.*|([^#\n]*\n?)/mg)
{
    if ( defined $1 ) {
        if (defined $key) {
            $keyval =~ s/\s+$//;
            $keyhash{ $key } = $keyval;
        }
        ($key, $keyval) = ($1,"");
        $keyhash{ $key } = "";
        push @order, $key;
        next;
    }
    if ( defined $2 && defined $key ) {
        $keyval .= $2;
    }
}
if ( defined $key ) {
    $keyval =~ s/\s+$//;
    $keyhash{ $key } = $keyval;
}

foreach $key ( @order ) {
    print "'$key' = '$keyhash{$key}'\n";
}


__DATA__

# commented area
Key0:
# still commenting
Key1: Value1 
Key2: 2013/03/04 15:41:30 # line end comment
   #asfgasfg
      stuff
   #asfgasfg
      here
Key3: Value with spaces whatever you pass here fits
Key4:
      value5
      value6
      value7
Key5:
    some other multiline value
    for testing purpose

输出&gt;&gt;

'Key0' = ''
'Key1' = ' Value1'
'Key2' = ' 2013/03/04 15:41:30
      stuff
      here'
'Key3' = ' Value with spaces whatever you pass here fits'
'Key4' = '
      value5
      value6
      value7'
'Key5' = '
    some other multiline value
    for testing purpose'