PHPで作成するジェネレーターでのご質問

このQ&Aのポイント
  • PHPを使用してツイッター診断メーカーに似たジェネレーターを作成しています。しかし、特定の部分の実装方法がわからず困っています。
  • 実装したい機能は、50個の文字列からランダムに1つを選び、10進数に変換してからそれを配列の数で割って余りを求めます。しかし、同じニックネームを入力すると同じ文字列が選ばれる確率が高くなってしまいます。
  • バラけた結果を得るためのロジックや参考になるサイトがあれば教えてください。お願いします。
回答を見る
  • ベストアンサー

PHPで作成するジェネレーターでのご質問

以前も相談させていただいたのですが、 ツイッター診断メーカーに似たものを作成しています。 http://shindanmaker.com/ そこである程度は完成したのですが、1点だけどうしても作成方法が分からず、 その部分をご相談させてもらいたいです。 以下にソースコピペします。 //textAraryには50個ほどの文字列が入っています。 $txtNum = count($textArray); //文字列を10進数に $num = sprintf("%u",crc32($click)); 10進数を配列の数で割り、余りを求める $i= $num % $txtNum; $finish = $textArray[$i]; 抜粋なのですが、上記のソースで実装するとちゃんと意図した動作するのですが、 診断用の異なるニックネームを何回か入力すると、 かなりの確率でfinishに同じ文字列が抽出されてしまいます。 出来る限り、バラけさせたいのですが、 何か良いロジックはありますでしょうか。 当方頭が回らず、、お知恵を拝借できればと幸いです。。 また、参考になるサイトでも結構ですので、 ご教授の程、よろしくお願いいたします。

  • PHP
  • 回答数2
  • ありがとう数1

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

  • ベストアンサー
  • duron
  • ベストアンサー率77% (73/94)
回答No.2

sprintfの"%u"で得られる数値(正しくは数字の文字列)はマイナス符号のない値です。 つまりとりうる範囲は0~4294967295(0xFFFFFFFF)です。 しかしPHPで計算されるときは符号付の数値で計算されます。 つまり範囲は-2147483648~2147483647となります。 $num = sprintf("%u",crc32($click)); で得られる$numは文字列であり $i= $num % $txtNum; の計算の時点で$numは数値として評価されます。 このときに2147483647を超える値の場合にはすべて2147483647として評価されてしまいます。 つまり半分以上の確率で$numは2147483647として計算されるため同じ結果が頻発します。 ですので $num = sprintf("%d",crc32($click)); としてマイナス符号付の数値として$numを受け取り このままでは剰余の計算でマイナスが返ってくることもあるので $i= abs($num % $txtNum); で絶対値を取ればいいと思います。 ・・・断定口調で書いてますが予想して書いたものですので厳密にあっているかは自信ないです。

noguchi74
質問者

お礼

ご回答有難うございます。 頂いた内容で無事解消いたしました!今までからいうとかなり改善されました。 これで問題なく取り組めそうです。 ありがとうございました。

その他の回答 (1)

  • SAYKA
  • ベストアンサー率34% (944/2776)
回答No.1

? 言っている意味がわからない。 普通に乱数を生成するのじゃだめなの?

noguchi74
質問者

補足

ご回答ありがとうございます。 すいません、言い忘れていましたが、同じ名前を入力すると同じ結果を表示させたいのです。 なので、乱数ですと結果がその都度変わってしまうので、ご提示したソースのように入力された文字列をベースに10進数に変換しています。 引き続きよろしくお願いします。

関連するQ&A

  • 現在PHPで診断メーカー的なものを作成しています。

    現在PHPで診断メーカー的なものを作成しています。 そこで、PHPの技術的なことでご質問です。 //$textArrayには50個程の文字列が入っています。 $txtNum = count($textArray); //$clickは入力された名前です。 $num = sprintf("%u",crc32($click)); //1個目の度の番号 $i= $num % $txtNum; //2個目の度の番号 $num2 = sprintf("%u",crc32($textArray[$i])); $i2 = $num2 % $txtNum; //3個目の度の番号 $num3 = sprintf("%u",crc32($textArray[$i2])); $i3 = $num3 % $txtNum; echo $i.'--'.$i2.'--'.$i3; 上記のように、名前に対して固定された文字列を配列から3つ抽出しています。 i,i2,i3ともにそれぞれ被らない数字にしたいのですが、上記のようにやると入力された名前によってはi,i2,i3でそれぞれ数字が被る場合があります。 これを被らないようにするには何か方法がありますでしょうか。 10進数を剰余代入することで、配列の中の数の範囲内で数字を抽出しています。 ばったりと詰まってしまい、ヒント等もらえますと幸いです。 よろしくお願いします。

    • ベストアンサー
    • PHP
  • Cの文字列関連の質問です。よろしくお願いします。

    Cの文字列関連の質問です。よろしくお願いします。 『読み込んだ文字列がナル文字を含めて15文字以下であれば、その文字列をそのまま格納し、そうでない場合、読み込んだ文字列の先頭14文字とナル文字を格納する』 という条件を満たすプログラムを作成しました。 #include <stdlib.h> #include <string.h> #include <stdio.h> int main(void) { int num; char (*p)[15]; printf("文字列の個数: "); scanf("%d", &num); p = (char (*)[15])malloc(num * 15); if (p == NULL) puts("記憶域の確保に失敗"); else { int i; char tmp[100]; /* 書込み */ for (i = 0; i < num; i++) { printf("p[%d]: ", i); scanf("%s", tmp); sprintf(p[i], "%.14s", tmp); } /* 表示 */ for (i = 0; i < num; i++) printf("p[%d]: %s\n", i, p[i]); free(p); } return 0; } この場合は、ちゃんと条件を満たした結果が出ました。 ここで24行目の『sprintf(p[i], "%.14s", tmp);』を『strncpy(p[i], tmp, 14);』に変更する明らかに結果がおかしくなります。 strncpyを使った方法に変更する場合、どのように修正を行えばいいのでしょうか? 長々と書いてしまいましたが、よろしくお願い致します。

  • CRC16コード作成プログラムについて

    お世話なります。 PCと対象機械との通信を行おうと思っております。 内容としてCRC16のコードを使って、日時設定をPC→対象機器へ行いたいです。 CRC16の生成プログラムをいろいろ調べてみたところ、 今、自分のスキルでなんとかわかりそうなCRC16のソースが次の通りでした。 (行列の計算ぐらいならC言語で作れる程度です。。。) unsigned short crc_cal(unsigned short lng, unsigned char *str) { unsigned short crc, i, j, t; crc = 0xffff; for (i = 0; i < lng ; i++) { crc ^= (unsigned short) str[i]; for (j = 1; j <= 8; j++) { if (crc & 1) { // carry bit on crc = crc >> 1; crc ^= 0xa001; } else { // carry bit off crc = crc >> 1; } } } return crc; } “0C0C0C0C0C0C”と入力したら、CRCコードが算出されるプログラムを作りたく、 入力部分を作成してみたのですが・・・ int main(void) { unsigned short i,j, t; unsigned char str[256]; unsigned char str0; unsigned short crc; int k=0; printf("Please input key (HEX)\n"); for(k=0; k < 256; k++) { scanf("%c",&str0); // 文字列標準入力 if( str0=='\n') // Enterが押されたときの実行 { str[k]='\0'; // 文末にNULL文字 break; // for文のループ終了 } else { str[k]=str0; // NULLでなければ入力された文字を代入 } } crc = crc_cal(k,str); printf("crc=%X\n", crc); return 0; } 文字列を分解して・・・やるんだろうなってまではなんとなくわかるのですが、 どのようにしたらよいでしょうか。。。 ご教授よろしくお願いします。

  • PHP「ip2long」について

    「ip2long」について教えてください。 マニュアルを見ると「インターネットプロトコルドット表記のアドレスを適当なアドレ スを有する文字列に変換する」とありますが、「適当なアドレ スを有する文字列」とは何なんでしょうか? 以下のソースを実行すると画面に -800211802 が表示されますが、これが「適当なアドレ スを有する文字列」なのでしょうか? この文字列は何進数なんでしょうか? <?php $ip = gethostbyname('www.example.com'); echo(ip2long($ip)); ?> sprintf("%u", ip2long($ip)) とするとロングIPアドレス(符号無しの 10 進数)になるってことは10進数ではないのでしょうけど・・・ GoogleのIPアドレス 66.249.89.99 だと正の数値 1123637603 が返されます。 正と負の違いはなんなんでしょうか??? 宜しくお願いいたします。

  • cshの文字列操作(0埋め)

    ヤマトです。 cshの文字列操作について質問します。 環境はRed Had Linux7.2です。 数値を文字列に変換し、更に0埋めするのはどのようにしたら良いのでしょうか? 以下に例を書きます。 ====SAMPLE.sh(一部抜粋)==== @ NUM_AAA = 1 ECHO NUM_AAA set CHR_AAA = ××××× ECHO CHR_AAA ====SAMPLE.sh(実行結果)==== 1 01 以上の ××××× に当てはまる処理が分かりません。 C言語とかで言うなら、sprintf のような処理をしたいのですが。 どのようにしたら良いのでしょうか? 教えて頂けると有り難く思います。宜しくお願いします。

  • PHPでGmail署名ジェネレータ

    Gmail署名ジェネレータサービスを見て、コレは便利だと思い、日本語でサービスしているサイトが見当たらなかったので、自らもオリジナルを作成しようと思い立ちましたが、PHP初心者でしてなかなか上手く行きません。 参考にしようとソースを見ても、HTMLにはPHPのスクリプトは書かれていない事に気付きました。(調べるとサーバサイドで動く、との事なので当たり前ですね) 画像にユーザが入力した文字列データを画像に埋め込むというのは具体的にどういった様に処理すれば良いでしょうか。 理想としては、http://www.gmailsignature.net/のような感じです。 オリジナル画像は既に作成してあり、可能であればhttp://services.nexodyne.com/email/のようにいくつか対応させたいなと思っていますが、まずはGmail署名を作りたいです。 宜しくご指導の程、お願い致します。

    • ベストアンサー
    • PHP
  • PHPでの文字操作について

    簡単にいうとPHPで暗号化ロジック関数を作成しようと考えています。 ※この暗号化は復号出来る事を前提に考えています。 簡単なレベルで元の文字列をまず16進数状態に変換して戻す という事が出来ないか?と考えています。 これが出来ればビットに数字を足したり引いたりした値を暗号化 文字列としてできるのではないかと思っています。 一応現在文字列の16進数表記は以下の手順で出来るという事が 分かったのですが、16進数表記にしたデータを元の文字列に 戻す方法が分かりません。 何か良い方法が在れば宜しくお願いします。 少し調べたら16進数から文字列に戻すにはエンディアンを考慮~ という説明があるのですが、私にはハッキリと分からない状態です。 【16進数化テスト】 <?php ### 元データの設定 $data01 = "テストデータ"; ### 16進数表記化 $data02 = bin2hex($data01); ### 暗号化情報の表記 echo "暗号前:" . $data01; echo "暗号後:" . $data02; ?>

    • ベストアンサー
    • PHP
  • 3進数を10進数に変換

    3進数や5進数のように2の階乗ではない任意の進数の文字列を、C言語のビットシフトを使って10進数に変換するプログラムについて、質問させていただきます。 ビットシフトを使わないで、任意の進数の文字列を10進数に変換する方法は分かっていますが、ビットシフトを使った方が非常に計算が高速で出来るので、ビットシフトを使いたいと思っています。 下記のプログラムは4進文字列を10進整数に変換するものです。2進、8進文字列の場合は、シフトするビット数を1ビット、3ビット(つまり、ans <<= 1、ans <<= 3)にすれば計算することが可能です。しかし、3進数や5進数の場合、いろいろと考えたのですが、どのようにすれば良いのか分かりません。 下記のプログラムのようにビットシフトを使って3進数や5進数の文字列を10進数に変換するには、どのように工夫すれば良いでしょうか? どなたかご教授をお願いいたします。 #define STRING_NUM 2 /* 文字列の長さ */ int main(void) { int i; int ans = 0; /* 10進数の整数 */ char buf[STRING_NUM]; /* 4進数の文字列 */ buf[0] = '3'; buf[1] = '1'; for ( i = 0 ; i < STRING_NUM; i++ ){ printf(" %c", buf[i]); } printf("\n"); for ( i = 0 ; i < STRING_NUM; i++ ){ if ( buf[i] == '0' ){ ans <<= 2; /* シフトするビット数 */ ans |= 0; } if ( buf[i] == '1' ){ ans <<= 2; ans |= 1; } if ( buf[i] == '2' ){ ans <<= 2; ans |= 2; } if ( buf[i] == '3' ){ ans <<= 2; ans |= 3; } } printf( "ans = %d\n", ans ); return 0; }

  • CStringの配列要素を関数で受け渡しするには?

    VC6を使っています。 それと当方、古いC言語しか分からず、 CStringの使い方で、ハマってしまっています。 よろしくお願いします。 (例) main関数側で、  CString buf[3]; buf[0] = "abc"; buf[1] = "012"; buf[2] = "xyz"; これを関数に渡して、それぞれの文字列内を加工したいのです。 func1(3,buf); ---(*) func1(int num, CString aaa) ----(*) {   int i;   for(i=0; i<num; i++){    if(i % 2 == 0){      aaa[i] += ".000";    }else{      aaa[i] += sprintf(".%03d",i);    }   } } たとえば、上記のような感じです。sprintf()の使い方が間違っている などもあるかも知れませんが、 それよりも、(*)の呼び出し側と引数定義の部分の書き方について、 ご存知の方お教えください。よろしくお願いします。

  • VC6でCRC64・CRC128が出来るソースを探しています。

    VC6でCRC64・CRC128が出来るソースを探しています。 CRC自体がよくわかっていないので、実際に動作させて理解しようとネットでソースを見つけようとしていますが、うまくコンパイルできるものが見つかりませんでした。 通常はCRCに1バイトをわたすもの?が多いのですが、できましたら文字列(長さは可変長)も扱える高速な関数を探しています。 よろしくお願いいたします。

専門家に質問してみよう