• ベストアンサー

正規表現または構文で数値の範囲の指定

if($a =~「1~20」までの数字又は「1_1~1_20」~「20_1~20_20」までの数字){ OK; }else{ NO; } を正規表現や条件分岐を使って範囲指定したいのです。 [1-9] ですと111等も対象になりますし、{n,}とした場合でも数値の1~20までとは出来ないようで・・・。 また正規表現では_の扱いが今一わからない状況で 更に()と?を使って思考錯誤を繰り返しているうちに []//の用途がだんだんと分からなくなってしまいました。 各用途については調べ整理しているつもりなのですが 今回のようなケースに関して参考になる例を見つけられず質問させて頂きました。 ご掲示頂けませんでしょうか。宜しくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.4

#3>各細部についての意味 /^(?:[1-9]|1\d|20)(?:_(?:[1-9]|1\d|20))?$/ /^~$/ ^:先頭から $:最後尾までの間 にある、つまり、今回の対象文字列だけが入っている。(他の文字列に埋もれているのを対象としているのではない) (?:~):グループ化する、()と違うのは$1などに値を設定しないこと、単にグループ化する時に使う。 [1-9]:1から9までの一文字を表す \d:[0-9]の意味 [1-9]|1\d|20:|は、orの意味、1~9であるか10~19(1で始まる0~9)であるか20であるの意味 (~)?:~が0回または1回ある

taku0
質問者

お礼

お忙しい中、親切丁寧にご解説頂きまして本当に有難うございます。 本当に本当に感謝の気持ちで一杯です。 最初解説頂いてる部分を拝見した時、 ^:先頭から・・・の:がえ? 更に $:の:も、ん?・・・みたいに思ったのですが、 アサーションを利用した形のグルーピングの使い方 や、_を(?:_(~))とする辺りは思わず、「そっか~なるほど~」と思わされる瞬間でつい感動してしまいました。 この辺りは自分の経験の浅さから考えがそこまで及ばず中々自分の主観からは逃れられないもんだなぁ・・と自覚さえしてしまいますが、同時に凄いなぁ~有り難いな~と思う反面認識が広がった事に感動してしまいました。 この度はご教授頂きました事、本当に感謝しています。 有難うございました!!

その他の回答 (4)

  • bender
  • ベストアンサー率45% (108/236)
回答No.5

No.2 です。プログラムが動作しなかったとのこと、失礼しました。 後者のプログラムについては、"if( (" の2つの左カッコのうちひとつが余計でした。また、プログラムを投稿する際に、インデントをそろえるために各行のはじめの空白文字に全角を使ったことも問題の一つであったのかもしれません。 いずれにしても、失礼しました!

taku0
質問者

お礼

お忙しい中、わざわざご連絡有難うございます。 ご掲示頂きました内容を再度確認しました所、 前者のは仰る通り全角の空白の為だったようです。 後者のも仰る通りで(が一つ余分と全角の空白になっていたようでした。 内容については、正規表現部分につきましてはBLUEPIXY様のご解説を前提にしている事もあり理解しやすいプログラム内容と拝見する事ができました。 また考え方としまして例を2例もあげて頂き、正規表現だけで解決するのではなく条件分岐を取り入れた形で実現して頂き凄く感謝していますしとても参考になっています。 私自身まだまだ初歩的な事を見落としていて恥かしい限りですが、今回の件を良い機会と受け止め今後の励みに頑張りたいと思います。 この度はbender様にも感謝の気持ちで一杯です。 最後までお付き合い頂き有難うございました!

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.3

#1の方と同じです if($a =~ /^(?:[1-9]|1\d|20)(?:_(?:[1-9]|1\d|20))?$/){

taku0
質問者

お礼

お忙しい中とても参考になる形でご掲示頂きまして、本当に有難うございました。 当初希望していた問題を解決できました。 各細部についての意味につきましては、おおよその検討しかつけようがないのですが、今回を機に正規表現について改めて調べ再勉強する良い機会になりました。 今後も事あるごとに振り返り、長期的な視野で正規表現を自分のものにしてゆけるよう頑張って参りたいと存じます。 この度は本当に感謝の気持ちでいっぱいです。 有難うございました。

  • bender
  • ベストアンサー率45% (108/236)
回答No.2

すでに丁寧な回答が寄せられているのですが、私は以下のような場合にわけて考えました。 (1)変数 $a の中が数字だけの場合 (2)変数 $a の中が「数字_数字」の形の場合 さらに、(1)の場合、その数字が1から20の範囲か、また、(2)の場合については、2つの数字が両方とも範囲内か、を調べるようにします。 if( ( $a=~/^(\d+)$/ && # (1)    $1>=1 && $1<=20 ) ||   ( $a=~/^(\d+)_(\d+)$/ && # (2)    $1>=1 && $1<=20 &&    $2>=1 && $2<=20   ) ) {  printf("yes\n"); } else {  printf("no\n"); } もしくは、 if( ( $a=~/^(\d+)(_(\d+))?$/ &&    $1>=1 && $1<=20 &&   ( $2 eq "" || $3>=1 && $3<=20 )  ) {  printf("yes\n"); } else {  printf("no\n"); }

taku0
質問者

お礼

お忙しい所、貴重なご意見有難うございました。 私のほうで試行錯誤を重ねてみたのですが、折角ご掲示頂いた上記の2点の例はエラーになり自力では動作確認をする事ができませんでした。 この度はお時間割いてご掲示頂きまして有難うございました。

noname#43437
noname#43437
回答No.1

面倒ではあるのですけど、この程度までなら、正規表現だけでなんとかなります。 1~20の数字を表す正規表現は・・ (?<!\d)([1-9]|1[0-9]|20)(?!\d) 連続した数字だけを取り出すために、ゼロ文字幅アサーションを利用するのが、ポイント。あんまり初心者向けの解説には載ってないので、こういう際に覚えてしまいましょう。 あとは、組み合わせてやってみてください。

taku0
質問者

お礼

ご返信の方遅くなったんですけれども、参考になる例とあわせて素早いご反応を頂き有難うございました。 また更にアサーションという概念がある事を知る機会を頂きましてありがとうございました。この件についてはまたおりをみて調べ取り組みたいと思います。 今回はご掲示頂きました正規表現で1~20までの数を対象にできた事は私には凄く感動的でした。 試しに自分で試行錯誤してみたのですが、1_20や1_2_3などまでひっかかってしまうようでした。 自分としてはイメージ的には下記のような形を想定しているのですが、まだ良くわかっておらず認識のあまさからうまく機能しないみたいです。 (?<!\d)([1-9]|1[0-9]|20)(?!\d)?(_)?(?<!\d)([1-9]|1[0-9]|20)(?!\d) もしまたお時間などございましたら、アドバイスなど頂けましたら幸いです。 今回は大変参考になるご意見有難うございました。