2016-12-07 23 views
3

値をマッチさせようとしていますが、コンマで区切って正規表現を使用しています。基本的には、文字列の値に3番目または3番目の3番目の文字が含まれていない場合はtrueを返します。次のようにPerlのパターンマッチが期待どおりに動作しない

私のテストコードは次のとおりです。

my @a = ('in3g123456,dh3k123456,dhec110101','dhec110101,dhec123456','in3g123456,dh3k123456', 'c3kasdf', 'usdfusdufs3gsdf'); 

foreach (@a) { 
    print $_; 
    say $_ =~ /(?:^|,)\w{2}[^(?:3G|3K)]/i ? " true" : " false"; 
} 

これは、第四1が真でない理由を私は理解していない

in3g123456,dh3k123456,dhec110101 true 
dhec110101,dhec123456 true 
in3g123456,dh3k123456 false 
c3kasdf false <- whaaaaaaaat? 
usdfusdufs3gsdf true 

を返します。どんな助けもありがとう。

+0

リマインダーあなたの文字列を配列に適用される[誰かが私の質問に答えるとき、私は何をすべき?](http://stackoverflow.com/help/someone-答え) – zdim

答えて

2

[^(?:3G|3K)]は、「(,?などを除く任意の文字」と読みます。

     failed 
         v 
     c3   kasdf 
/(?:^|,)\w{2}[^(?:3G|3K)]/i 

使用この:

/(?:^|,)\w{2}(?!3G|3K)/i 

デモ:https://regex101.com/r/P2XsgN/1

+0

または '(?!3 [GK])'? –

+0

これは当てはまりますが、問題は正規表現を最適化することではなく、最小の変更が何が間違っているのかを最も明確に示すはずです。 –

1

/\b\w{2}(?!3g|3k)/iです。

\bは、単語の先頭または末尾の空の文字列と一致します。この状況では、(^|,)とやや簡単に等価です。

(?!foo)は、ゼロ幅の否定先読みアサーションです。したがって、空の文字列の後ろに、fooと一致する部分文字列がない限り、一致します。

0

substrを使用すると、3番目と4番目のデータを取得し、それを(3g|3k)と比較することができます。

substr $_,2,2 


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

my @a = ('in3g123456,dh3k123456,dhec110101','dhec110101,dhec123456','in3g123456,dh3k123456', 'c3kasdf', 'usdfusdufs3gsdf'); 

foreach (@a) { 
    my @inputs = split /,/,$_; 
    my $flag = 0; 
    foreach (@inputs){ 
    $flag = 1 unless ((substr $_,2,2) =~ /(3g|3k)/); 
    } 
    $flag ? print "$_: True\n" : print "$_: False\n"; 
} 

出力:

in3g123456,dh3k123456,dhec110101: True 
dhec110101,dhec123456: True 
in3g123456,dh3k123456: False 
c3kasdf: True 
usdfusdufs3gsdf: True 

Demo

1

することもできますsplit文字列まず、代わりに正規表現ですべてを解析します。それははるかに柔軟でメンテナンスが容易で簡単です。

抽出された「値」のリストを処理するときは、の任意の文字「」とパターンの2倍の/^..$patt/を一致させることができます。モジュールList::MoreUtilsはリスト操作に便利で(しかも高速です)、そのnotall関数はあなたの条件に合わせて作成されています。

use warnings 'all'; 
use strict; 
use List::MoreUtils qw(notall); 

my $file = '...'; 
open my $fh, '<', $file or die "Can't open $file: $!"; 

while (<$fh>) 
{ 
    my $res = notall { /^..(?:3k|3g)/ } split /,/; 

    print "$_: " . ($res ? 'true' : 'false'), "\n"; 
} 

ファイルから読み込むと仮定します。そうでない場合はwhile (<$fn>)for (@strings)に置き換えてください。

notall関数は、リストのいずれかの要素が条件を満たさない場合にtrueを返します。

splitはデフォルトで$_を使用しているため、パターンが必要です。ここでは単純に,ですが、区切り文字を柔軟に一致させるためにパターンは正規表現を取ります。たとえば、/[,\s]+/は、,および/または空白の任意の量で分割されます。したがって、,, ,の文字列はセパレータとして一致し、,またはスペースも一致します。

参照、上記プリント

 
in3g123456,dh3k123456,dhec110101: true 
dhec110101,dhec123456: true 
in3g123456,dh3k123456: false 
c3kasdf: true 
usdfusdufs3gsdf: true 
+0

@Jimこの回答を出力とその他の説明で更新しました – zdim

関連する問題