0

我正在尝试编写正则表达式,但无法传递单词空间

我有一个这样的数据文件(由另一个实用程序生成)

* field      : 100
blahbla      : <Set>
scree        : <what>
.Cont.asasd  :
Othreaol     : Value, Other value
Point->IP    : 0.0.0.0 Port 5060

模式必须像这样匹配和捕获数据

"field" "100"
"blahbla" "<Set>"
"scree" "<what>"
".Cont.asasd" ""
"Othreaol" "Value, Other value"

我的早期解决方案是

/^([\s\*]+)([\w]+[\s\.\-\>]{0,2}[\w]+)(\s*\:\s)(.*)/

但我对一些字符串有问题,比如

Z.15 example : No

空格阻止模式匹配

H.25 miss here : No

同样的事情

4

3 回答 3

5

这里有一些复杂的答案。我想我会使用一个简单的split

while( <DATA> ) {
    chomp;
    my( $field, $value ) = split /\s*:\s*/, $_, 2;
    print "Field [$field] value [$value]\n";
    }

__DATA__
* field      : 100
blahbla      : <Set>
scree        : <what>
.Cont.asasd  :
Othreaol     : Value, Other value
Point->IP    : 0.0.0.0 Port 5060

这给出了:

Field [* field] value [100]
Field [blahbla] value [<Set>]
Field [scree] value [<what>]
Field [.Cont.asasd] value []
Field [Othreaol] value [Value, Other value]
Field [Point->IP] value [0.0.0.0 Port 5060]

从那里,我会根据需要过滤名称和值,而不是尝试在单个正则表达式中完成所有操作:

my @pairs = 
    grep { $_->[0] !~ /->/ }                   # filter keys
    map  { $_->[0] =~ s/\A\*\s+//; $_ }        # transform keys
    map  { chomp; [ split /\s*:\s*/, $_, 2 ] } # parse line 
    <DATA>;

use Data::Printer;
p @pairs;

__DATA__
* field      : 100
blahbla      : <Set>
scree        : <what>
.Cont.asasd  :
Othreaol     : Value, Other value
Point->IP    : 0.0.0.0 Port 5060
于 2012-08-01T22:58:02.867 回答
1

由于您想用冒号分隔值,因此在拆分之前对所有这些字符使用正则表达式中该字符的补码。

my $regex 
    = qr{
         ( # v- no worry, this matches the first non-space, non-colon
           [^\s:]      
           (?> [^:\n]* # this matches all non-colon chars on the line
               [^\s:]  # match the last non-space, non-colon, if there
           )?          # but possibly not there
         )             # end group

         \s*           # match any number of whitespace
         :             # match the colon
         \s*           # followed by any number of whitespace

         ( \S          # Start second capture with any non space
           (?> .*      # anything on the same line
               \S      # ending in a non-space
           )?          # But, possibly not there at all
         |             # OR 
         )             # nothing - this gives the second capture as an 
                       # empty string instead of an undef
    }x;

while ( <$in> ) { 
    $hash{ $1 } = $2 if m/$regex/;
}

%hash然后看起来像这样:

{ '* field'        => '100'
, '.Cont.asasd'    => ''
, 'H.25 miss here' => 'No'
, Othreaol         => 'Value, Other value'
, 'Point->IP'      => '0.0.0.0 Port 5060'
, 'Z.15 example'   => 'No'
, blahbla          => '<Set>'
, scree            => '<what>'
}

当然,当我开始考虑它时,如果您可以确定一个/\s+:\s+/模式或至少一个/\s{2,}:\s{2,}/模式,那么像这样的行可能会更简单split

while ( <$in> ) { 
    if ( my ( $k, @v ) 
         = grep {; length } split /\A\s+|\s+\z|(\s+:\s+)/
       ) { 
        shift @v; # the first one will be the separator
        $hash{ $k } = join( '', @v );
    }
}

它做同样的事情,不需要做几乎同样多的回溯来修剪结果。它忽略了转义的冒号,没有更多的语法,因为它必须是一个被空格包围的裸冒号。您只需将以下内容添加到 if 块:

$k =~ s/(?<!\\)(\\\\)*\\:/$1:/g;
于 2012-08-01T21:42:31.697 回答
0

我不明白为什么Point->IP您的示例输出中省略了该行,但类似下面的代码应该适合您。

use strict;
use warnings;

while (<DATA>) {
  next unless /([^\s*].+?)\s*:\s*(.*?)\s*$/;
  printf qq("%s" "%s"\n), $1, $2;
}

__DATA__

  * field      : 100
  blahbla      : <Set>
  scree        : <what>
  .Cont.asasd  :
  Othreaol     : Value, Other value
  Point->IP    : 0.0.0.0 Port 5060
  Z.15 example : No
  H.25 miss here : No

输出

"field" "100"
"blahbla" "<Set>"
"scree" "<what>"
".Cont.asasd" ""
"Othreaol" "Value, Other value"
"Point->IP" "0.0.0.0 Port 5060"
"Z.15 example" "No"
"H.25 miss here" "No"
于 2012-08-01T21:37:48.943 回答