文字列の形の確認No.02650
megmin さん 01/11/22 11:52
 
はじめまして。

独学でやっているので、基本的なことかもしれませんがわかりません。
教えてください。
文字列型変数 $nentuki に
 2001.08.25 のような形で文字を入力します。

その文字列が、その形になっているかどうかを確かめて、
違っていたらエラーを返したいのですが、
どうすればいいのかわかりません。
年月日を別々に input させれば、そのたびごとに
確認できるのですが、一度の入力で済ませられる方法はありませんか。

ヒントでいいので教えていただけないでしょうか?
よろしくお願いします。

[ ]
RE:02650 文字列の形の確認No.02651
TAKA さん 01/11/22 13:09
 
megminさん、こんにちは。TAKA と申します。

>ヒントでいいので教えていただけないでしょうか?

情報が少なすぎて、どこまでのチェックがしたいのか分かりません
が・・・

// テストマクロ(ここから)
    $Def = year + "." + month + "." + day;
L1000:
    // 年月日入力
    $Str = input( "年月日", $Def );
    if( !result )
    { // キャンセル
        goto LEND;
    }

    // 年月日分割
    #I = 0;
    while( 1 )
    {
        #Pos = strstr( $Str, "." );
        if( #Pos == -1 )    break;
        if( #I >= 2 )
        {
            message ".の数が多すぎます。";
            goto L1000;
        }
        $Wk = leftstr( $Str, #Pos );
        $Str = rightstr( $Str, strlen( $Str ) - #Pos - 1 );
        $Tbl[#I] = $Wk;
        #I = #I + 1;
    }
    if( #I != 2 )
    { // 入力エラー
        message ".の数が少なすぎます。";
        goto L1000;
    }
    $Tbl[#I] = $Str;

    // 数値チェック
    #I = 0;
    while( #I < 3 )
    {
        call NumCheck $Tbl[#I];
        if( ##return != 0 )
        { // 入力エラー
            message "年月日は半角数値で入力して下さい";
            goto L1000;
        }
        #I = #I + 1;
    }

    // 範囲チェック
    // どこまで正確なチェックが必要か分かりませんが、ここでチェック

    // 年月日の表示
    message $Tbl[0] + "年" + $Tbl[1] + "月" + $Tbl[2] + "日";

LEND:
    endmacro;

NumCheck:
    ##RC = -1;

    ##StrLen = strlen( $$1 );
    ##I = 0;
    while( ##I < ##StrLen )
    {
        if( ( ascii( midstr( $$1, ##I, 2 ) ) & 0xff00 ) != 0 )
        { // 2バイト文字
            goto NumCheckLEND;
        }
        else
        {
            $$Wk = midstr( $$1, ##I, 1 );
            if( strstr( "0123456789", $$Wk ) == -1 )
            { // 数値以外
                goto NumCheckLEND;
            }
            ##I = ##I + 1;
        }
    }

    ##RC = 0;

NumCheckLEND:
    return ##RC;
// テストマクロ(ここまで)

[ ]
RE:02650 文字列の形の確認No.02652
ENCODINGSHIFTJIS さん 01/11/22 13:46
 
>文字列型変数 $nentuki に
> 2001.08.25 のような形で文字を入力します。
>違っていたらエラーを返したいのですが、
>年月日を別々に input させれば、そのたびごとに

「マクロライブラリ」を日付で検索すると参考になります。

マクロの関数を使い
両端の不要な空白を消す(必要なら)から、部分文字列切り出し
数値化、範囲検査の順でします。
                  $YYYY=leftstr($nentuki,4);if(strlen($YYYY)!=4)///桁数?
#YYYY=val($YYYY);if(!result)//数値?
#YYYYの範囲チェック、うるう年判定
                  $MM=midstr($nentuki,6,2);
桁数、数値、範囲の検査など
                  $DD=rightstr($nentuki,9,2);

現状では、strstrの正規表現は審議中らしいです
形だけなら 、\d{4}\.\d{2}\.\d{2}  あたり

スクリブト言語なら、文字列→日付型のデータ変換をして
エラーが返るか、判定するです。もし外部プロでコマンドラインや
DLLで動くのが作れるなら, マクロで run や dllfunc で呼べます。


>確認できるのですが、一度の入力で済ませられる方法はありませんか。
>
>ヒントでいいので教えていただけないでしょうか?
>よろしくお願いします。

[ ]
RE:02651 ありがとうございますNo.02653
megmin さん 01/11/22 14:34
 
TAKAさん

ありがとうございます。

書いていただいたテストマクロの内容が難しくて、
これからじっくり勉強させていただきます。
サブルーチンの使い方が、ちんぷんかんぷんなので、
先が遠そうです。

とりあえず、お礼をいわせていただきます。

チェックさせたかった中身は、
半角で入力されていること、
月、日が二桁で入力されていること、
ピリオドの数の3点です。

が、月日が二桁でなかった場合は
マクロの側で、0を入れて補完してあげてもいいわけですよね。
ちょっと考えてみます。

本当にありがとうございました。

[ ]
RE:02652 ありがとうございますNo.02654
megmin さん 01/11/22 14:36
 
ENCODINGSHIFTJISさん

難しくて、おっしゃっていることが理解できません。
申し訳ありません。

これからがんばって勉強させていただきます。


本当にありがとうございます。

[ ]
RE:02651 教えてくださいNo.02655
megmin さん 01/11/22 16:44
 
やはりわかりません。
すみません。

>    // 年月日分割
>    #I = 0;
>    while( 1 )
>    {

この部分ですが、while(1)というのはどういう状態のことなのでしょうか?
while(2)とか、while(3)というのもありえるのですか?

もうひとつ。
>NumCheck:
>    ##RC = -1;
>
>    ##StrLen = strlen( $$1 );
>    ##I = 0;
>    while( ##I < ##StrLen )
>    {
>        if( ( ascii( midstr( $$1, ##I, 2 ) ) & 0xff00 ) != 0 )
>        { // 2バイト文字
>            goto NumCheckLEND;
>        }

引用が長くてすみません。
最後のほうの、if( (ascii(うんたら の部分は何をさせているのか
教えていただけませんか?
「&」の使い方がよくわかっていないものですから。
どうしてこれで2バイト文字かどうかのチェックができるのかわかりません。
甘えたことを申しまして、すみません。

どうかよろしくお願いします。

[ ]
RE:02653 ありがとうございますNo.02660
TAKA さん 01/11/22 21:54
 
TAKA です。

>書いていただいたテストマクロの内容が難しくて、
>これからじっくり勉強させていただきます。

私のマクロは、コメント(「//」がついている部分)がありますの
で、コメントを読みながら見れば分かると思います。
「その他→ファイルタイプ別の設定→表示」で「コメント/文字定
数のカラー表示」をON、「モード」を「秀丸マクロ」にし、「そ
の他→ファイルタイプ別の設定→カラー」で「コメント」に適当な
色を設定するとコメントが見やすいです。


>サブルーチンの使い方が、ちんぷんかんぷんなので、
>先が遠そうです。

http://win.blue.co.jp/~jr-kun/hidemaru_qa/3_sub.html
が参考になります。
最後まで読めば、嫌でも分かります。


>半角で入力されていること、

ピリオドが半角であることと、年月日のが半角数値であることでチ
ェックしています。


>月、日が二桁で入力されていること、

これは、対応していませんが、簡単です。(後述)


>ピリオドの数の3点です。

これは、年月日分割のところで、半角ピリオドが2つあることをチ
ェックしています。


>が、月日が二桁でなかった場合は
>マクロの側で、0を入れて補完してあげてもいいわけですよね。

「// 範囲チェック」というコメントの下に以下のソースコードを
追加するだけです。

// 追加(ここから)
    // 範囲チェック
    // 年は特にチェックしない。
    // 日付の正当性(閏年等)もチェックしない。
    // 月と日は2桁までとする。1桁の場合は0をつける
    #I = 1;
    while( #I < 3 )
    {
        #Len = strlen( $Tbl[#I] );
        if( ( #Len != 1 ) && ( #Len != 2 ) )
        { // 1桁か2桁でない
            if( #I == 1 )   message "月は1桁か2桁です。";
            else            message "日は1桁か2桁です。";
            goto L1000;
        }
        else if( #Len == 1 )
        { // 1桁
            $Tbl[#I] = "0" + $Tbl[#I];  // 頭に0をつける
        }
        #I = #I + 1;
    }
// 追加(ここまで)


最初の発言をもう一度見てみると、日付のチェックの部分自体をモ
ジュールにしたいようですね。
というわけで、上記も含めて整理すると、以下のようになります。

// テストマクロ(ここから)
    $Def = year + "." + month + "." + day;

L1000:
    // 年月日入力
    $Str = input( "年月日", $Def );
    if( !result )
    { // キャンセル
        goto LEND;
    }
    $Def = $Str;    // 次回入力を差し替える

    // 年月日チェック
//  call DayChek $Str, 0;   // エラーメッセージ表示なし
    call DayChek $Str, 1;   // エラーメッセージ表示あり
    $Str = $$return;
    if( $Str == "" )
    { // エラー
        goto L1000;
    }

    // 年月日の表示
    message $Str;

LEND:
    endmacro;


// 第1引数に年月日
// 第2引数にメッセージフラグ 0:表示なし 1:表示あり
// リターン値に正常な日付。不正な場合はヌル
DayChek:
    $$Str = "";

    $$DayWk = $$1;

    // 年月日分割
    ##I = 0;
    while( 1 )
    {
        ##Pos = strstr( $$DayWk, "." );
        if( ##Pos == -1 )   break;
        if( ##I >= 2 )
        {
            if( ##2 == 1 )  message ".の数が多すぎます。";
            goto LDayChekEND;
        }
        $$Wk = leftstr( $$DayWk, ##Pos );
        $$DayWk = rightstr( $$DayWk, strlen( $$DayWk ) - ##Pos - 1 );
        $$Tbl[##I] = $$Wk;
        ##I = ##I + 1;
    }
    if( ##I != 2 )
    { // 入力エラー
        if( ##2 == 1 )  message ".の数が少なすぎます。";
        goto LDayChekEND;
    }
    $$Tbl[##I] = $$DayWk;

    // 数値チェック
    ##I = 0;
    while( ##I < 3 )
    {
        call NumCheck $$Tbl[##I];
        if( ##return != 0 )
        { // 入力エラー
            if( ##2 == 1 )  message "年月日は半角数値で入力して下さい";
            goto LDayChekEND;
        }
        ##I = ##I + 1;
    }

    // 範囲チェック
    // 年は特にチェックしない。
    // 日付の正当性(閏年等)もチェックしない。
    // 月と日は2桁までとする。1桁の場合は0をつける
    ##I = 1;
    while( ##I < 3 )
    {
        ##Len = strlen( $$Tbl[##I] );
        if( ( ##Len != 1 ) && ( ##Len != 2 ) )
        { // 1桁か2桁でない
            if( ##2 == 1 )
            {
                if( ##I == 1 )  message "月は1桁か2桁です。";
                else            message "日は1桁か2桁です。";
            }
            goto LDayChekEND;
        }
        else if( ##Len == 1 )
        { // 1桁
            $$Tbl[##I] = "0" + $$Tbl[##I];  // 頭に0をつける
        }
        ##I = ##I + 1;
    }

    $$Str = $$Tbl[0] + "年" + $$Tbl[1] + "月" + $$Tbl[2] + "日";
//  $$Str = $$Tbl[0] + "." + $$Tbl[1] + "." + $$Tbl[2] + ".";

LDayChekEND:
    return $$Str;


// 第1引数に文字列
// リターン値 0:半角数値 -1:半角数値以外
NumCheck:
    ##RC = -1;

    ##StrLen = strlen( $$1 );
    ##I = 0;
    while( ##I < ##StrLen )
    {
        if( ( ascii( midstr( $$1, ##I, 2 ) ) & 0xff00 ) != 0 )
        { // 2バイト文字
            goto LNumCheckEND;
        }
        else
        {
            $$Wk = midstr( $$1, ##I, 1 );
            if( strstr( "0123456789", $$Wk ) == -1 )
            { // 数値以外
                goto LNumCheckEND;
            }
            ##I = ##I + 1;
        }
    }

    ##RC = 0;

LNumCheckEND:
    return ##RC;
// テストマクロ(ここまで)


>ちょっと考えてみます。

#あっ、答えを全部書いてしまった。
#後は、日付の妥当性のチェックさえ入れればいいのかな。

[ ]
RE:02655 教えてくださいNo.02661
TAKA さん 01/11/22 21:55
 
TAKA です。

>この部分ですが、while(1)というのはどういう状態のことなのでしょうか?
>while(2)とか、while(3)というのもありえるのですか?

これは、時々ある質問でして、次回のQ&A集には必要と思ってい
たところです。
ちなみに、Q&A集は、
http://win.blue.co.jp/~jr-kun/hidemaru_qa/hmindex0.html
です。

これは、真と偽の概念を利用しています。

秀丸マクロヘルプの「while文」に
>while文は,その直後にある条件式の値が0以外である間,処理を
>くりかえします。
とある通り、0以外である間(真の場合)は処理を繰り返します。
      ^^^^^^^

ですので、while( 1 )でも、while( 2 )でも、while( 3 )でもかま
いません。(0以外であれば何でも良い)
一般的に無限ループを作る場合は、while( 1 )とします。
^^^^^^^^^^^^^^^^^^^^^^^^^^

無限ループの場合は、何らかの条件でループを抜ける必要がありま
す。そのため、ループの中である特定の条件を満たした場合にbreak
でループを抜けさせます。

次回のQ&A集には、真(0以外)と偽(0)について記述したいと思い
ます。
#時間があれば。


>最後のほうの、if( (ascii(うんたら の部分は何をさせているのか
>教えていただけませんか?
>「&」の使い方がよくわかっていないものですから。
>どうしてこれで2バイト文字かどうかのチェックができるのかわかりません。

これは、ビット演算という技法を使用しています。
以下は、「#01879 2001/03/22」からの引用です。

>ビット演算には、AND,OR,XORなどがあります。
>
>0011
>0101 AND
>----
>0001 結果(両方が1の時に1)
>
>0011
>0101 OR
>----
>0111 結果(どちらか1方に1があれば1)
>
>0011
>0101 XOR
>----
>0110 結果(片方が0で片方が1の時に1)
>
>0xffffをビットで表現すると、「1111 1111 1111 1111」となりま
>す。
>1バイト文字の場合は、「0000 0000 ???? ????」となります。
>2バイト文字であれば、先頭の部分の8ビットのどこかに「1」が
>たっている訳ですから、「1111 1111 0000 0000」とのANDを取るこ
>とで、お互いのビットが「1」であれば、演算の結果そのビットは
>「1」となります。
>
>例(2バイト文字)
>1111 1111 0000 0000
>0101 0101 0101 0101 AND
>-------------------
>0101 0101 0000 0000
>
>例(1バイト文字)
>1111 1111 0000 0000
>0000 0000 0101 0101 AND
>-------------------
>0000 0000 0000 0000
>
>つまり、1バイト文字であれば「0」となります。
>というわけで、「0xff00」とANDを取って「0」でなければ、2バイ
>ト文字と見なせるわけです。

ちなみにif( チェックしたいコード > 0x00ff )というは使わない
方がいいです。(時々みかけますが)
理由は、「#01884」を参照。但し、意味が分からないかもしれませ
ん。1の補正が理解できないと、苦しい。

ビット演算についても、次回のQ&A集には入れたいと思います。
#同じく時間があれば。

[ ]
RE:02661 遅くなって申し訳ありませんNo.02684
megmin さん 01/11/26 11:04
 
megminです

返事が遅くなってしまい、本当に申し訳ありません。

書いていただいたマクロを、また、じっくり勉強させていただきます。

本当にありがとうございます。

[ ]
RE:02654 ありがとうございますNo.02719
ENCODINGSHIFTJIS さん 01/11/30 16:11
 
DLLでもいくぶんかはできます。直接呼び出せるのはこの程度です

// testJRE32.mac
//JRE32.DLLのロード  通常は arimac JRE32.dll にしているため
loaddll(hidemarudir + "\\YAMJre32.dll");// 山田JRE32.dll
if (!result) {
message "DLL をロードできませんでした。";
endmacro;// 馬場BREGEXP.dllはcall規則がdllfuncと合わないらしい
}
//
         #ver=dllfunc("JreGetVersion");
menu str(#ver);
//●BOOL EXTAPI IsMatch(LPSTR lpszStr, LPSTR lpszRe);
#bool=dllfunc("IsMatch","11/12/13","[0-9][0-9]/[0-9][0-9]/[0-9][0-9]");// こ
れくらいしか
menu str(#bool);
// 切断・開放
freedll;

[ ]
RE:02719 ありがとうございますNo.02721
杉浦 まさき さん 01/12/01 13:43
 
ども、杉浦 まさき です。

ここにコメントを入れるのは適切ではないかもしれませんが…

>endmacro;// 馬場BREGEXP.dllはcall規則がdllfuncと合わないらしい

田楽鯖&DLLの Ver.2.XX から
BREGEXP.DLL の関数を呼び出すためのラッパー関数を用意する予定です。
#まだちょっと不安定な所があるので
 いつ頃出せるかは??ですが。


[ ]
RE:02721 ありがとうございますNo.02722
encodingshiftjis さん 01/12/01 19:43
 
> いつ頃出せるかは??ですが。

素晴らしい、正規表現が他スクリプト言語と同水準に近くなると
書く行数が段違いに少なくなります。(1文字操作が少なくできる)
テキスト処理系のエンジンみたいなとこですから
(例外は REBOL言語くらい )

●ひとりごと
「.NET の CLR(コモン・ランゲージ・ランタイム)あたりは、どうなって
いるんでしょう。」.NETβは業務のPCには入れられないし。

[ ]