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

ここにはいくつかの複雑な答えがあります。私は単純な分割を使用すると思います:

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 に答える