• 締切済み

正規表現の達人にお聞きしたい。

正規表現で、文字数は4文字ですが、そのうち1つでもaがあれば マッチするということで、1~3まではマッチし、 4はa無しなのでマッチせず、5は4文字でないのでマッチしない ような正規表現は書くことは可能でしょうか? 1) aaaa 2) ajjj 3) kaoa 4) jjjj 5) axxxx

みんなの回答

  • ma5aru
  • ベストアンサー率0% (0/0)
回答No.5

以下スクリプトで、各案のパフォーマンスを計測してみました。 -- #!/usr/bin/perl use Time::HiRes qw(gettimeofday); my @testData = qw(aaaa ajjj kaoa jjjj axxxx); # テストデータ # aを含む4文字にマッチする正規表現 全案 my %matchesIt4CharIncluding_a = ( # Tacosanさん 全ケースベタ書き案 'No.1' => qr/^(?:a...|.a..|..a.|...a)$/, # kirikirkazさん 明示的バックトラック案 'No.2' => qr/^(?=.*a).{4}$/, # poppo64さん 明示的バックトラック逆案 'No.3' => qr/^(?=.{4}$).*a/, # kinoko2009さん 評価コード埋込案 'No.4' => qr/(?(?{length!=4||index($_,"a")<0})(?!))/, # (参考) パターン展開コード埋込案 'No.5' => qr/^[b-z]{0,3}+a(??{'[a-z]{'.(4-length($&)).'}+'})$/, ); my $times = 1000_000; # パフォーマンス計測用 繰り返し回数 foreach my $No (sort(keys(%matchesIt4CharIncluding_a))) { my($start, $n) = (get_utime(), $times); printf("%s MATCH's", $No); printf(" : ( %s )", join(' ', grep(/$matchesIt4CharIncluding_a{$No}/, @testData))); grep(/$matchesIt4CharIncluding_a{$No}/, @testData) while ($n--); printf(" x %d time=%.6fs\n", $times, get_utime() - $start); } sub get_utime { return sprintf('%d.%06d', gettimeofday()); } __END__ 以下、実行結果。 [WindowsVista on Core2DuoT9400@2.53GHz] C:\Users\user\Desktop>matchesIt4CharIncluding_a.pl No.1 MATCH's : ( aaaa ajjj kaoa ) x 1000000 time=8.511500s No.2 MATCH's : ( aaaa ajjj kaoa ) x 1000000 time=8.518548s No.3 MATCH's : ( aaaa ajjj kaoa ) x 1000000 time=8.526566s No.4 MATCH's : ( aaaa ajjj kaoa ) x 1000000 time=12.486100s No.5 MATCH's : ( aaaa ajjj kaoa ) x 1000000 time=51.380000s [Linux on VMwarePlayer for WindowsVista] user@ubuntu:~$ ./matchesIt4CharIncluding_a.pl No.1 MATCH's : ( aaaa ajjj kaoa ) x 1000000 time=4.751165s No.2 MATCH's : ( aaaa ajjj kaoa ) x 1000000 time=5.005868s No.3 MATCH's : ( aaaa ajjj kaoa ) x 1000000 time=5.051104s No.4 MATCH's : ( aaaa ajjj kaoa ) x 1000000 time=8.477054s No.5 MATCH's : ( aaaa ajjj kaoa ) x 1000000 time=36.206683s 見た目にもシンプルで分かりやすい正規表現が高速、という結果となりました。 これは、多少バックトラックが発生したとしても、ユーザーで回避策コードを 埋め込むよりも、Perlの正規表現エンジンの最適化は優れているので、巧妙・ 技巧的なコードに拘る必要はない、ということなのかもしれません。

全文を見る
すると、全ての回答が全文表示されます。
回答No.4

/(?(?{length!=4||index($_,"a")<0})(?!))/

全文を見る
すると、全ての回答が全文表示されます。
  • poppo64
  • ベストアンサー率57% (11/19)
回答No.3

No.2さんのをひっくり返して、次のようにもも書けますね。 /^(?=.{4}$).*a/ ^(?=.{4}$) の部分で文字数が4文字であることを確認し、 .*a で a が含まれていることを確認しています。 # 確認コード foreach my $str ( qw/ aaaa ajjj kaoa jjjj axxxx / ){ $str =~ /^(?=.{0,4}$).{0,3}a/ ? print "$str: MATCH\n" : print "$str: NO MATCH\n"; }; # 出力 # aaaa: MATCH # ajjj: MATCH # kaoa: MATCH # jjjj: NO MATCH # axxxx: NO MATCH

全文を見る
すると、全ての回答が全文表示されます。
回答No.2

こんなのどうでしょう。 /^(?=.*a).{4}$/ (?=.*a) でaが含むかを確認し、また最初の位置まで戻って .{4} で4文字かどうかを確認しています。 ---- テストコード ---- $\ = "\n"; for $p (qw(aaaa ajjj kaoa jjjj)) { print; print $p; print "match?:".($p =~ /^(?=.*a).{4}$/); } ---- テストコード ---- ---- 出力 ---- aaaa match?:1 ajjj match?:1 kaoa match?:1 jjjj match?: axxxx match?: ---- 出力 ----

全文を見る
すると、全ての回答が全文表示されます。
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

ベタに書くなら ^(?:a...|.a..|..a.|...a)$

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 正規表現について

    正規表現について LPIC黒本の問題で1つ困っています。 $ grep -E ^A[^A]A[^A] lpic.txt にマッチする文字列 答え AaAa となっていますが理解できません。 そもそも正規表現ってなんでしょうか? あまり難しいようなら飛ばしますが、 となたか教えてくれるお方おりましたらお願いいたします。

  • この場合の正規表現を教えてください

    AAAA BBBBBBBBBBBBB BBBBBBBBBB... CCCCC DDDDDDDDDDDDDD... AとCの部分の文字列は決まっていて、BとDの部分はどのような文字列か(改行数も含めて)わかりません この場合でのAとCを含むAとCに囲まれたBの部分を正規表現で表すにはどう書けばいいんですか? ↓この部分全体のことです AAAA BBBBBBBBBBBBB BBBBBBBBBB... CCCCC

  • 正規表現の 「 * 」

    正規表現の 「 * 」は、直前パターンの繰り返しですよね? つまり、a* は a, aa, aaa, aaaa, aaaaa, ..... にマッチするわけですよね? ところで、 echo abbbaaa | sed 's/a*/x/g' のようにしたら a, aaa の部分が x に置き換わって  → xbbbx となることを期待していたのですが、  → xbxbxbx となってしまいました。 なぜでしょうか?

  • マッチする部分を除いたものが欲しいのですが(正規表現)

    マッチする部分を除いたものが欲しいのですが。 $a = '/home/user/'; $b = '/home/user/aaaa' $c = [正規表現や置換演算子]で、-----あ $cが aaaaとなってほしい。「あ」の部分の書き方をご存知のかた教えていただけますか?

    • ベストアンサー
    • Perl
  • Perl・正規表現が分かりません

    Perlでプログラムを書く場合、 ある文字列の文字数が5文字且つ、文字列の先頭に[0-5A]を必ず含み、そして残り4文字にも[0-5A]のみを必ず含む場合、Trueを表示。 それ以外はErrを表示する。 多分、全て、正規表現でできると思うのですが、分かりません。教えていただけないでしょうか? 宜しくお願い致します。 $test = "0AAAA"; if(正規表現){ print "True"; }else{ print "Err"; } ↑結果:True $test = "aAAAA";の場合、 結果:Err

    • ベストアンサー
    • Perl
  • 正規表現

    PHPのプログラミングの勉強をしています。 正規表現を使って?の1文字をマッチさせたいのですが http://hogehoge.com/?hoge=hoge などの/?の場合は正規表現でマッチさせないようにしたいのです。 宜しくお願い致します。

    • 締切済み
    • PHP
  • 正規表現について

    お世話になります。 ●●● ●●● という文字列かどうか判断する正規表現を作成したいです。 条件としては、 ・「文字1 (←全角スペース)文字2」という感じで、文字1と文字2に全角スペースが挟まれている感じで、文字列の先頭にも末尾にも空白文字は入ってはいけない(真ん中に1つのみ) ・文字1と文字2には、数字・空白以外の文字が入る(主に感じ・ひらがな・カタカナが入る)(文字数は一文字以上) といったところです。 自分で作成した正規表現は、 $pattern = '/^([\d\S])+ ([\d\S])+$/'; if( !preg_match($pattern,$chkStr) ) print "マッチしていない"; } なんですが、どうもマッチしてほしい文字にマッチしていないようなのです。 お手数ですがご教授ください。

    • ベストアンサー
    • PHP
  • 正規表現を教えてください。

    正規表現を教えてください。 C#で正規表現を用いた文字列検索を勉強中なのですが、うまくマッチさせることができません。教えていただけないでしょうか。 検索対象の文字列は下のようになります。 キーワード;値; 文字列中に該当するキーワードが存在する場合に、その値を取得するプログラムを考えています。しかし、私の正規表現では2つ目の「;」を検出してしまい、キーワードのみを取得することが出来ずに困っています。 見当違いの表記をしているとは思うのですがどなたかお助けください。 match = Regex.Match(line, "^(.*);"); C#初心者なものです。

  • 正規表現について

    正規表現について質問をさせていただきます。 VB6.0にて正規表現を使用し、入力された文字のチェックを行っていますが どうしてもうまくいきません。 チェックしたい文字は A(半角アルファベット大文字1文字)または AAA(半角アルファベット大文字3文字)または (AAA)(半角カッコつき半角アルファベット大文字3文字)で 上記3パターン以外はエラーとしたいと思っています。 パターンは下記のように作成したのですが "(^[\(][A-Z]{3}[\)])|(^[A-Z]{1,3})" A、AAA、(AAA)以外でもA(AA)やAAAA等も正常ケースとして通過してしまいます。 パターンをどのように作成すればよいか教えて下さい。 よろしくお願いします。

  • 「マッチしない」正規表現の書き方

    正規表現について、おたずねします。 文字列 abc,def,ghi のいずれかにマッチする正規表現は (abc|def|ghi) ですよね。 それでは、「abc,def,ghi のいずれにもマッチしない」正規表現は、どう書けばいいのでしょうか? あちこち調べましたが、どうしてもわかりません。 ただし、if $a =~ /(abc|def|ghi)/ などで、=~ を !~ に直す、というのはナシです。あくまでも右辺の式の中で表現したいのですが…