更に修正

昨日指摘された部分を修正してみた。また問題点見つかったりしないだろうな…


こうなりました

public class Checker {
	/**
	 * 正しく数字が入力されたことを判断するプログラム ver.0.012
	 * getBytes()で取得するバイトシーケンスの符号
	 * 43 = +
	 * 45 = -
	 * 46 = .
	 * 48〜57 = 0〜9
	 */
	public static boolean isNumber(String value) {
		// null値の判定処理
		if (value == null || value.length() == 0) {
			return true;
		}
		// 変数の宣言
		int chklng = value.length();
		boolean judge = true;
		int dotcount = 0;
		int dotflag = 0;
		// 文字をbyte配列にて取得
		byte chkbt[] = value.getBytes();
		// 判定処理
		for (int g = 0; g < chklng; g++) {
			// 0〜9であればif以下の処理をスルー
			if (chkbt[g] > 57 || chkbt[g] < 48) {
				if (chkbt[g] == 43 && g == 0 && chklng > 1) {
					// +が先頭にあればtrueとする
					// ただし取得文字が1文字以上である場合に限る
					judge = true;
				} else if (chkbt[g] == 45 && g == 0 && chklng > 1) {
					// -が先頭にあればtrueとする
					// ただし取得文字が1文字以上である場合に限る
					judge = true;
				} else if (chkbt[g] == 46) {
					// 小数点を数える
					dotcount++;
					if (g > 0 && g < chklng - 1) {
						// 小数点が先頭・末尾に無いことを確認
						if (dotflag == 1) {
							// .の直前は数字でなくてはならない
							judge = false;
						}
					} else {
						// 先頭・末尾にあるならfalseに変更
						judge = false;
					}
				} else {
					// +でも-でも.でもなければfalseとする
					judge = false;
				}
				// 数字以外と判定されたのでフラグを立てる
				dotflag = 1;
			}

			else {
				// 数字と判定されたのでフラグを消す
				dotflag = 0;
			}
			if (dotcount > 1) {
				// 小数点が1個以上存在した場合falseとする
				judge = false;
			}
		}
		return judge;
	}
}

結果、全て望みどおりの結果を得ることができた。
指摘されてた部分

callChecker("-", false);
callChecker("+", false);
callChecker("-.", false);
callChecker("+.", false);
callChecker("-.2", false);
callChecker("+.2", false);

このうち1,2行目と5,6行目は昨日(id:regasuie:20051027)の状態ではちゃんとfalseを返してくれなかった。昨日と今日のでそれぞれ行ってる判断をリストにしてみるとしようか。

○昨日

  • 取得文字が0〜9でなければ以下の処理へ
    • 取得文字が+/-の場合、それが何字目かの判断
      • 1文字目であれば変数judgeをtrueとする
    • 取得文字が.の場合、変数dotcountに1加える
      • 1文字目/末尾でなければ変数judgeをtrueとする
      • そうでなければ変数judgeをfalseとする
    • 上記条件を満たさない場合、変数judgeをfalseとする
  • dotcountが1以上であれば変数judgeをfalseとする
  • 最終的に得られた変数judgeを返す

こうして見ると、指摘されたやつの1,2行目にtrueを返す理由がよくわかる。「+」と「-」は1文字目であれば、後に何も続かなくってもtrueを返すことになってるんだから、「+」か「-」を1文字だけ入力しても問題無いってことだ。ここは取得文字列が1文字以上であることを条件にしてクリア。
3,4行目にちゃんとfalseを返してたのは、「.」が末尾に来てるからそこで引っかかってたんだな。
5,6行目のとこはかなり悩んだけど…良く考えたら「.」の前が数字であれば問題ないのか。「.」を検出したらその1つ前に取得した文字の値を参照してもらおうと、こんな文を追加してみた。

if(chkbt[g-1] > 57 && chkbt[g-1] < 48){
judge = false;
}

これで「.」を検出したときのchkbt[g]の1つ前の値を取得してくれるかな…って思ったら、エラー発生。どうもそこに-1とか入れるのがまずいらしい…
新たにint型変数を宣言してそこにg-1を入れてみてもダメ。この方法ではいけないらしい…と、あれこれ考えた結果、数字以外を検出した場合にフラグを立てておくことでいけるんじゃないか、と考え付いた。
結果が上のほうに載せた今日のソース。どんな判断させてるか、一覧にしてみる。

○今日

  • 取得文字が0〜9でなければ以下の処理へ
    • 取得文字が+/-である&1文字目である&1文字以上の文字列を取得していることを確認
      • 上記条件を満たす場合、変数judgeをtrueとする
    • 取得文字が「.」の場合、変数dotcountに1加える
    • 「.」が1文字目/末尾であることを確認
      • 直前の文字が数字以外であれば、変数judgeをfalseとする
      • 「.」が1文字目/末尾でなければ、変数judgeをfalseとする
    • 上記条件を一切満たさなければ、変数judgeをfalseとする
    • 最初に数字以外と判定ているので、変数dotflagを1とする
  • dotcountが1以上であれば変数judgeをfalseとする
  • 最初に数字と判定された場合、変数dotflagを0とする
  • 最終的に得られた変数judgeを返す

自分で一覧にしててわけわからんくなってきたorz
judgeの初期値がtrueなので、falseに変更する場合以外ほとんど触れないようにしてるんだけど、そこはちゃんとjudge=trueとか書いてたほうがいいんだろうか?


さ、他に望まない結果を返しそうなパターンが無いか確認しようかな。


今気づいたけど

何で+/-の判定時だけtrueにするパターンの判定してるんだろ…