[WebP Vol.020] 入力チェックの極意 その2:やっぱり正規表現使わなくっちゃ

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
【 Webプログラミング Code Sample 】                          Since2001/11/23

      Code020: 入力チェックの極意 その2:やっぱり正規表現使わなくっちゃ

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
                                                    Produced by ichikoro.com

           ▼毎週月曜日と金曜日に配信しています。
           ▼等幅フォントでご覧いただくとキレイに見えます。
           ▼登録・解除はこちらから可能です。
               < http://www.ichikoro.com/webp/ >
                  ※バックナンバーへのリンクもあります。
                  ※お友達にもぜひお勧めください(^^)/


─【Contents】───────────────────────────────
    01.Answer ............... 前回の回答
    02.Tips ................. 入力チェックの極意 文字列長のカウントは難しい?
    03.Tips ................. 入力チェックの極意 やっぱり正規表現使わなくっちゃ
    04.News ................. ネット業界の一週間
    05.From Editor .......... 編集後記


                   【 Webプログラミングは毎週2本立て! 】

             ・月曜日版はWebの実際の活用方法などを特集します。
             ・金曜日版はHTMLやCGIなど一つの分野について最初から
              解説する講座になっています。現在はC言語入門です。



こんにちは、編集者の勝部です。

ebay日本撤退、ISIZE 11シーン閉鎖、また3月1日にはドコモ米英で上場など、先週は
ネット業界の区切り目みたいな感じがしました。来期をあと一ヶ月に控え、この業界
の人、この業界に参入しようとしている人たちが、いったいどんな構想を練っている
のか、何でわかせてくれるか、非常に楽しみです。


ではでは、今週も行ってみましょう!

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  01.Answer  「前回の回答」
──────────────────────────────────────
金曜日版で出題した問題の回答例です。
ちょっとだけ頭を使えば簡単ですよね?

    Q. 変数A と 変数B の値を入れ替え、それぞれ表示しなさい。
       ただし変数へ定数を代入するのは、それぞれ一度とする。

    A. 「2つのコップがあり、オレンジジュースとミルクが入っています。
         さてコップの中身を入れ替えるにはどうしたらいいでしょう?」

       小学校のころ、こんな問題やりませんでした?


        ・プログラム例
            #include<stdio.h>

            int main(void)
            {
                int a;
                int b;
                int temp;

                a = 100;
                b = 200;

                printf("スワップ前\n");
                printf("a -> %d\n", a);
                printf("b -> %d\n", b);
                printf("\n");

                temp = a;
                a = b;
                b = temp;

                printf("スワップ後\n");
                printf("a -> %d\n", a);
                printf("b -> %d\n", b);
                printf("\n");

                return(0);
            }

        ・実行例
            C:>bcc32 swap.c
            Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
            swap.c:
            Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland

            C:\>swap
            スワップ前
            a -> 100
            b -> 200

            スワップ後
            a -> 200
            b -> 100


ようするに、もう一個器を用意して、そこに一旦逃がしてやるわけです。
ジュースの話で言い変えると、

    口    ←  コップa(ミルク)
    コップa ←  コップb(ジュース)
    コップb  ←  口(ミルク)

でしょうか。
口に入れるなって?(笑)

ジュースと違い、正確にはMove(移動)ではなくCopy(複写)になりますが、要領は一緒
です。もう一つジュースと違うところがあります。数値の場合は演算することで同様
のことが実現できます。これを思いついた人います?いたらスゴイですねぇ(^-^)

        #include<stdio.h>

        int main(void)
        {
            int a;
            int b;

            a = 100;
            b = 200;

            printf("スワップ前\n");
            printf("a -> %d\n", a);
            printf("b -> %d\n", b);
            printf("\n");

            a = a + b;
            b = a - b;
            a = a - b;

            printf("スワップ後\n");
            printf("a -> %d\n", a);
            printf("b -> %d\n", b);
            printf("\n");

            return(0);
        }

結果はもちろん同じです。

        C:>bcc32 c_egg.c
        Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
        c_egg.c:
        Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland

        C:\>c_egg
        スワップ前
        a -> 100
        b -> 200

        スワップ後
        a -> 200
        b -> 100

パッと見ただけじゃ分かんないかもしれないですね。そういう時は変数がそれぞれど
ういう状態になっているか考えながら読んでください。理解すれば「何だ」って感じ
ですが、これを初めて見た時は結構シビレました(^^;
コロンブスの卵ですな。


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  02.Tips  「入力チェックの極意:文字列長のカウントは難しい?」
──────────────────────────────────────

このコーナーは読者の皆さんから寄せられた質問や、今すぐにでも使えるプログラ
ムの活用方法、実例などを取り上げていきたいと思います。突発的に色々でてきま
すが、詳細は解説しません。分からない場合は本編でいずれ取り上げると思います
のでそれまで待つか、ご自分で調べてくださいませ。


前回は、下のようなソースで終わりました。

    <HTML>
        <HEAD>
            <TITLE>入力フォーム</TITLE>
            <SCRIPT language="JavaScript"><!--

                /*---------------------------------------------------------*/
                /*■onLoadイベント                                         */
                /*    引数:なし                                           */
                /*  戻り値:なし                                           */
                /*    処理:nameにフォーカスする                           */
                /*---------------------------------------------------------*/
                function setOnLoad(){

                    //名前にフォーカスを当てる
                    document.bbsForm.name.focus();

                }

                /*---------------------------------------------------------*/
                /*■送信前チェック                                         */
                /*    引数:なし                                           */
                /*  戻り値:成功 → true                                   */
                /*          失敗 → false                                  */
                /*    処理:フォームbbsFormの必須項目が入力されていない    */
                /*          場合はダイアログを表示し、当該項目にフォーカ   */
                /*          スする(送信はされない)                         */
                /*          入力内容が大丈夫な場合は、確認ダイアログを出   */
                /*          し、OKであれば送信する。                       */
                /*---------------------------------------------------------*/
                function chkForm(){
                    var name  = document.bbsForm.name;
                    var title = document.bbsForm.title;
                    var naiyou = document.bbsForm.naiyou;

                    /*---------------------------------------*/
                    /*              内容チェック             */
                    /*---------------------------------------*/
                    //名前をチェック
                    if( name.value.length <= 0 ){
                        alert("名前を入力してください");
                        name.focus();
                        return(false);
                    }
                    //タイトルをチェック
                    if( title.value.length <= 0 ){
                        alert("タイトルを入力してください");
                        title.focus();
                        return(false);
                    }
                    //内容をチェック
                    if( naiyou.value.length <= 0 ){
                        alert("内容を入力してください");
                        naiyou.focus();
                        return(false);
                    }

                    /*---------------------------------------*/
                    /*                 送信確認              */
                    /*---------------------------------------*/
                    //送信前に一度確認
                    if( confirm("この内容で送信してもよろしいでしょうか?") ){
                        return(true);
                    }

                    return(false);
                }

            //-->
            </SCRIPT>
        </HEAD>
        <BODY onLoad="setOnLoad()">

            <FORM name="bbsForm" onSubmit="return( chkForm() )"
                                        action="bbs.cgi" method="post">

                <!-- ここから3つは必須項目 -->
                名前:<INPUT type="text" name="name"><BR>
                タイトル:<INPUT type="text" name="title"><BR>
                <TEXTAREA name="naiyou" rows="10" cols="60"></TEXTAREA><BR>
                <BR>

                <!-- この2つはオプション -->
                メール:<INPUT type="text" name="mail"><BR>
                URL:<INPUT type="text" name="url"><BR>
                <BR>

                <INPUT type="submit">
            </FORM>

        </BODY>
    </HTML>


さて、今回はこれをもう少し改造してみましょう。
前回チェックした項目は、

    ・名前が入力されたか
    ・タイトルが入力されたか
    ・内容が入力されたか

でした。

入力されたかということに加え、よくチェック項目として上げられるのは入力された
文字数です。というわけで、下のような要件を追加してみましょう。

    ・名前は10byte以内

chkForm関数の“送信確認”の前あたりに、下記のJavaScriptを追加してみてください。

        /*---------------------------------------*/
        /*             最大文字数チェック        */
        /*---------------------------------------*/
        //名前をチェック
        if( name.value.length > 10 ){
            alert("名前は10文字以内で入力してください");
            name.focus();
            return(false);
        }

ただ、この方法だと注意しないといけないのは、半角も全角も同じように一文字とし
て扱われる点です。ただ、これは最近の話です。ちょっと前のブラウザではバイト数
をそのまま文字列長としていました。つまり現在はその両方が混在する形になってお
り、ブラウザによってその挙動が異なることになります。

詳細は、下記のようになっているそうです。

    ・Netscape
        〜 JavaScript1.2        バイト単位
           JavaScript1.3 〜        文字単位

            NN2.x    1.0
            NN3.x    1.1
            NN4.x    1.2
            NN4.06    1.3        ← これ以降文字単位でのカウントとなります

    ・InternetExploler(日本語版)
        常に文字単位

            IE3.x    1.0
                ただしマイナーバージョンアップの影響で、同じ3であっても
                微妙に挙動が違うそうです。

            IE4.x    1.1
                正式には1.1のみの対応ですが、1.2、1.3のスクリプトも一部
                動くようです。

            IE5.x    1.3
                同じIE5であっても挙動が違うようです。

ということから、単純にlengthではバイト数をカウント出来ないようです。


私も頭を悩ましていたのですが、OpenSpaceさんがこれを実現されています。

    ・文字列のバイト数を求める
      http://www.openspc2.org/reibun/javascript/string/026/index.html


考え方は簡単です。

    ○文字列終端までループ

        (1)一文字抜き出します。
        (2)escape関数でURLエンコードをします。

        (3)エンコード後の文字列
            →1バイトなら %XX もしくはエンコードされないので、文字列長は3以下
            →2バイトなら 4文字以上

        (4)変数countに加算


    (5)countを表示(戻り値に)


なるほどです。
これなら、ブラウザ判定などをすることなく一つのロジックでいけますね。


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  03.Tips  「入力チェックの極意: やっぱり正規表現使わなくっちゃ」
──────────────────────────────────────

今度は、もっと面白いことをやってみましょう。上のHTMLではオプションとなってい
ますが、メールアドレスとURLが正しい形式で入力されているかのチェックです。詳し
いことはここでは割愛しますが、JavaScriptでは正規表現と呼ばれる物が使用できます。
基本的にはPerlなどで使われているものと同じ物が、ほとんどそのまま使えるのです。

    ・正規表現(RegExp)
      http://tohoho.wakusei.ne.jp/js/regexp.htm

この正規表現、初めて触る方にはヤケドしそうになりそうなくらい、奥が深い物です。
そのロジックから、Perlで下手な正規表現を書くと無限ループとも思える回数のルー
プをすることもありデバグを慎重にやらないと、手痛い目にあいます。


話を戻しましょう。では、メールアドレスが正しい形で入力されているかチェックす
るにはどうしたらいいでしょうか?先ほどと同じように下記のソースをchkForm関数
の“送信確認”の前あたりに追加してみてください。


    /*---------------------------------------*/
    /*             入力形式チェック          */
    /*---------------------------------------*/
    //メールアドレスをチェック
    if( ! mail.value.match(/^([0-9a-zA-Z.-_]{1,})@([0-9a-zA-Z.-_]{1,})$/) ){
        alert("メールアドレスの形式が違っています");
        mail.focus();
        return(false);
    }

実際に使ってみると分かりますが、これはかなり簡易的なものです。
(簡易的ですが、まぁそれなりに使えます)

本格的なチェックをしたいという方は、Perlメモで有名な大崎さんのページ

    ・Perlメモ
      http://www.din.or.jp/~ohzaki/perl.htm

        → Perl正規表現雑技
           http://www.din.or.jp/~ohzaki/regex.htm

こちらをチェックしてみてください。
クラッと来ました?(^^;

また、大崎さんも記述されていますが、iモードやJフォンなどでは、通常のEメール
だとありえない表現が可能となっています。実際に使われる方は注意が必要です。


同じような感じで、例えば郵便番号がキチンと7桁で入力されているかを調べるには
次のようにします

    <SCRIPT language="JavaScript"><!--
        checkPostal("100-0000");

        function checkPostal( code ){
            if( code.match(/^([0-9]{3})-([0-9]{4})$/) ){
                alert("OK");
            }
            else{
                alert("NG");
            }
        }
    //-->
    </SCRIPT>


この関数、checkPostalとしてますが、

    if( code.match(/^([0-9]{3})-([0-9]{4})$/) ){

の中にある、

    ^([0-9]{3})-([0-9]{4})$

の部分を変更するだけで様々なチェックが可能になります。長ったらしいプログラム
はもう必要ないのです!たった一行でほとんどのマッチングは完成します。その一例
として、

    ・一番最初が、"I am"で始まっているかチェック

        ^I am

    ・一番最後が、"txt"で終わっているかチェック

        txt$

    ・半角英小文字だけかチェック

        ^([a-z]*)$

    ・半角数字だけかチェック

        ^([0-9]*)$

    ・半角数字が含まれて“いない”かチェック

        [^0-9]

    ・YYYY/MM/DDかチェック

        ^([0-9]{4})\/([0-2][0-9])\/([0-3][0-9])$


    ・その台詞には愛が含まれているかチェック

        love

などなど、ネタがあればいくらでも作れますね(^-^)


正規表現は取っ付き辛そうな雰囲気から食わず嫌いな方が多かったりするので
すが、本当にチョコッと勉強するだけで開発効率が大幅に上がる事うけあいで
す。ぜひマスターしてください。


さぁ次回も前方チェック講座は続きます。
お次は様々なイベントと組み合わせて考えてみましょう。



■参考文献、サイト

    ・詳細 HTML&JavaScript辞典
      岡蔵 龍一 (著), 半場 方人 (著)
      http://www.amazon.co.jp/exec/obidos/ASIN/4879669318/stagefan-22

        →最新版はこちら
          http://www.amazon.co.jp/exec/obidos/ASIN/4798002208/stagefan-22

    ・AllAbout Japan
      http://allabout.co.jp/

        →JavaScriptはこちら
          http://allabout.co.jp/computer/javascript/

    ・OpenSpace
      http://www.shiojiri.ne.jp/~openspc/

        →JavaScript例文辞典はこちら
          http://www.openspc2.org/reibun/javascript/

    ・とほほのWWW入門
      http://tohoho.wakusei.ne.jp/

        →とほほのJavaScriptリファレンス
          http://tohoho.wakusei.ne.jp/js/index.htm


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  04.News  「今週の気になるニュース
                インターネット業界の一週間」
──────────────────────────────────────

───────
  2月25日(月)
───────
・Opera SoftwareのCEOが来日 〜すべてのデバイスにOperaを搭載する
  http://www.watch.impress.co.jp/internet/www/article/2002/0225/opera.htm

・バリュークリック、フロート型のFlash広告「ValueMotion」を開始
  http://www.watch.impress.co.jp/internet/www/article/2002/0225/vmo.htm
    2月15日に5円のクリック単価引き下げを行ったバリュークリック。今後再生
    できるかどうか期待したいところですが、この方向性では正直...。ただたく
    さんの人に満遍なく広告を打つ時代はすでに終わりを迎え始めています。


───────
  2月26日(火)
───────
・ebay ジャパン、営業活動終了 — 日本市場から撤退へ
  http://japan.internet.com/busnews/20020226/1.html

・楽天、全商品を対象にアフィリエイトプログラムを開始
  http://www.watch.impress.co.jp/internet/www/article/2002/0226/rakuten.htm

・KDDIのFTTH商用化,問題はタイミング?
  http://www.zdnet.co.jp/broadband/0202/26/kddi2.html


───────
  2月27日(水)
───────
・ISIZE、3月末に大幅リニューアル〜得意分野に集約
  http://www.watch.impress.co.jp/internet/www/article/2002/0227/isize.htm

・米 eBay、「日本市場には再度戻ってくる」可能性を示唆
  http://japan.internet.com/finanews/20020227/1.html


───────
  2月28日(木)
───────
・RIAJとJASRAC、ファイルローグに対して3億6,500万円の損害賠償請求
  http://www.watch.impress.co.jp/internet/www/article/2002/0228/mmo.htm
    この音楽業界の訴訟って、ナンセンスだと思います。
    ファイル交換できなかったらCD買うかと言えば、それはまた別の問題でしょう。
    たくさんの人が使うということは、そこに需要があるということなんですから、
    もっと上手い持っていき方があるハズです。頭悪いなぁといういい例ですな。

・Google Toolbarに分散コンピューティング機能追加間近か〜GoogleがFAQを掲載
  http://www.watch.impress.co.jp/internet/www/article/2002/0228/googlecom.htm

・残るのはブランドだけか?──ソニーがアイワを完全子会社化
  http://www.zdnet.co.jp/news/0202/28/sony_aiwa.html

・「!広告!」で何が変わったのか?
  http://www.zdnet.co.jp/mobile/0202/28/n_koukoku.html


───────
  3月01日(金)
───────
・NTTドコモ、米英で上場
  http://www.nttdocomo.co.jp/new/contents/02/whatnew0301.html
    日本ではあらかじめ、ある程度シェアがあったから大成功したが、
    アメリカでは厳しいのでは...といわれていますが、これからの動きが
    非常に楽しみです。

・PHP スクリプト言語にセキュリティホール
  http://japan.internet.com/webtech/20020301/12.html

・Linuxのファイアウォールにセキュリティ上の問題点
  http://www.zdnet.co.jp/news/0203/01/e_linux.html


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
                           編    集    後    記
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

毎朝、有楽町マリオンの下(中か?)を通って出勤してるんですが、先週TVの撮影らし
き物をみかけました。と思ったら、王様のブランチで流れているのを目撃(^^; あの
怪しい物体はこの企画だったのね。この付近って撮影多いんですよね。数寄屋橋の交
差点付近とか時々パネルを持ったアナウンサーがインタビューしてたりします。

 ・周辺地図
    http://www.mapfan.com/index.cgi?MAP=E139.45.58.3N35.40.12.5&ZM=11

と聞くと響きはいいのですが、宝くじが発売されるたびに発生する長蛇の列をかき分
け(あまりに多いと整理する人も登場)、毎朝「献血にお願いします」というおじさん
たちの叫び声を聞きつつ(しかも疲れた感じがして悲痛そう)、帰りには大量の「手相
の勉強しているんですが」という謎の方々を撒きながら通勤するのは、田舎物には精
神的に疲れます(^^;

ドラマとかであの交差点が登場すると現実に引き戻され、とってもイヤなんですよ
ね(ーー;)


そうそう、すっかり私も魔法にかかってしまいました(笑)
今ハリーポッターの原作(日本語訳)読んでるのですが、感想は戸田奈津子さんは訳が
上手い!(映画の方)でしょうか(笑)原語の方を読んでいないので映画の脚本が秀逸
なのかもしれないですが。とりあえず、話の組み立て方も台詞も映画の方が出来いい
です。

そうそう、「みぞの鏡」って何やねんと思ったら原作が「The Mirror of Erised」
なのですね。確かにこれ訳すの大変そう。「うぼくよ鏡」「いがね鏡」うーんそう
考えると「みぞの鏡」の方がしっくりくるなぁ。イメージを崩さずに訳すのって本
当に大変なんですねぇ。そんなことを感じました。

もう一回見に行こうかな。
早めに仕事終わらせて、今度はマリオンで!

  ・ハリーポッターショップ
    http://www.amazon.co.jp/exec/obidos/redirect?tag=stagefan-22&path=tg/browse/-/505198


ではでは、今度は金曜日にお会いしましょう (^-^)/~~


---【相互広告(モバイル)】---------------------------------------------------
『おもろい堂』
 最新携帯情報中心に配信!&3月か4月にドラエモンの結末を配信!
 登録→00050388s@merumo.ne.jpにメール送信!
 HP→http://i.mobo.ne.jp/m.asp?U=yt19830410
---------------------------------------------------【相互広告(モバイル)】---

■Information
 「Webプログラミングからのお知らせ」

    【相互広告募集のお知らせ】
      読者数を増やしたいメルマガ発行者さんを募集しています。お互いに一定期間(1〜
      3回程度)広告を掲載し合いませんか?詳細はご相談ください(無料)

         お問い合わせ: mm-webp@ichikoro.com

    【コラム募集のお知らせ】
      Webプログラミングでは、寄稿していただけるコラムやプログラムなどを募集して
      います。たくさんの読者の方にあなたをアピールする場にもなります。ぜひ有意義
      な情報やご意見をお送りください。

         お問い合わせ: mm-webp@ichikoro.com


■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

                   【 Webプログラミング Code Sample 】

                    発  行 : ichikoro.com
                発行責任者 : 勝部 麻季人
                              < katsube@ichikoro.com >
                  発行部数 : 1743部(前回)
                 Webサイト : < http://www.ichikoro.com/webp/ >
            お問い合わせ先 : < mm-webp@ichikoro.com >

                            Powerd by まぐまぐ
    All Right Reserved, CopyRight(C) 2001 Webプログラミング Code Sample
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■