前方一致

検索用の文字列比較関数をリファクタリングしてたんです。
最初こんなんでした。


int compare(char *a, char *b) {
   int length_a;
   int length_b;
   int min_length;
   int i;
   int result = 0;
   
   length_a = strlen(a);
   length_b = strlen(b);
   min_length = min(length_a, length_b);
   
   for (i = 0; i < min_length; i++) {
      if (a[i] > b[i]) {
         result = 1;
         break;
      } else if (a[i] < b[i]) {
         result = -1;
         break;
      }
   }
   
   if (result == 0) {
      if (length_a > length_b) {
         result = 1;
      }
   }
   return result;
}

なんか変なことやってるなーと思い、「要は文字列比較だろ?」っていうわけで以下のように『リファクタリング』しました。


int compare(char *a, char *b) {
   int result = 0;
   
   for (i = 0; ; i++) {
      if (a[i] == '\0') {
         if (b[i] == '\0') {
            break;
         } else {
            result = -1;
	        break;
	     }
      } else if ( b[i] == '\0') {
         result = 1;
         break;
      } else if (a[i] > b[i]) {
         result = 1;
         break;
      } else if (a[i] < b[i]) {
         result = -1;
         break;
      }
   }
   
   return result;
}

うむ、合っているはずだ!というか、こんな比較関数を作るくらいならstrcmp使えって話なんだけど、そのときは気づかず。勝利を確信し動かしてみたらちゃんと動かねえ。CppUnitがFalseを出しまくりやがります。テストコードを見ると、なんとこの関数のテストコードがない。「いっけね、忘れてた」ってわけで早速テストコードを作成しテストしてみると、どうやらこの関数は正しく動いとる。むしろ元のコードは新しく作ったテストコードを通過しない。「このプログラムはバグの上に成り立っているのかぁ!?」と、ふとコメントを見ると
『前方一致に対応するためaの長さまでで比較する』
と書いてある。なにぃ!そうだったのか!つまり、a=”abc”, b=”abcde”の場合、0を返さないといけない。・・・ああ、だから最初あんな変なコードになっていたのか。というわけで最終的に下記のようになりました。


int compare(char *a, char *b) {
   int result = 0;
   
   for (i = 0; ; i++) {
      if (a[i] == '\0') {
         break;
      } else if ( b[i] == '\0') {
         result = 1;
         break;
      } else if (a[i] > b[i]) {
         result = 1;
         break;
      } else if (a[i] < b[i]) {
         result = -1;
         break;
      }
   }
   
   return result;
}

ちゃんと動いた。すごく微妙に早くもなった。CppUnitが役に立ったな。

以上

コスミー について

昔(?)はゲーム作ってました。 今もなんか作ろうとしています。
カテゴリー: C言語, プログラム, 聞いて欲しい独り言 パーマリンク

コメントを残す

メールアドレスが公開されることはありません。