効率的な総当たりのアルゴリズム

このQ&Aのポイント
  • 文字列を総当たりで要素に分解するアルゴリズムについて質問です。
  • 文字列の中から順不同でもマッチする要素を求めるメソッドも実装されています。
  • 文字数が増えると処理に時間がかかるため、効率的な処理方法を教えていただきたいです。
回答を見る
  • ベストアンサー

総当たりのアルゴリズムについて

このジャンルでお願いします。 例えば、「aba」という文字列なら、 a b ab aa aba という要素(順不同です)を得たいと思い、自分なりに作ってみたのですが、 やはり調べる文字数が9文字辺りから処理に時間がかかり重くなってしまいます・・・ もちろんこういうアルゴリズムではそうなることはしょうがないと思いますが、 もう少し効率の良いやり方があればアドバイスをい頂けないでしょうか? 下に自分作った例です(メソッド名とか滅茶苦茶ですが・・^^;)) //文字の総当たりを得る //aba なら a,b,ab,aa,aba class AllCombinationCharacter { private $_characters = array(); public function __construct($text) { $this->_characters = self::split($text); } public static function split($text) { $cnt = 0; $arr = array(); while ($chara = substr($text, $cnt++, 1)) { $arr[] = $chara; } return $arr; } private function setList(&$list, $addText) { if (is_array($list)) { $find = false; foreach ($list as $item) { if (self::isMatchInRandomOrder($item, $addText)) { $find = true; break; } } if (!$find) { $list[] = $addText; } } } private function recursive($list, $addText, $startIndex) { for ($i = $startIndex; $i < count($this->_characters); $i++) { $text = ""; $text .= $addText . $this->_characters[$i]; //echo "t=" . $text . "<br>\n"; $this->setList(&$list, $text); $this->recursive(&$list, $text, $i + 1); } } public function getList() { $list = array(); $this->recursive(&$list, "", 0); return $list; } // 順不同の文字列マッチ // "aba" と ”aab”は一緒(true) public static function isMatchInRandomOrder($text1, $text2) { $tips = self::split($text2); for ($i = 0; $i < count($tips); $i++) { $searchString = $tips[$i]; $text1 = preg_replace("/{$searchString}/", "", $text1, 1); if ($text1 == "") { break; } } if ($text1 == "" && $i == count($tips) - 1) { return true; } return false; } } $obj = new AllCombinationCharacter("abaaxyz"); foreach ($obj->getList() as $item) { echo "t=" . $item . "<br>\n"; }

  • PHP
  • 回答数7
  • ありがとう数6

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

  • ベストアンサー
  • bm_hiro
  • ベストアンサー率51% (200/388)
回答No.4

正直、俺は classを 分ってません。なので、そちらのソースも読めてません。 更に言うと正規表現も理解してませんし、習得できているフレームワークも1個もありません。 メンバ変数って何?状態だったりもします。 さて、いきなり関係ない話題から入ってしまいましたが、家に帰ってきてみて、見たら ソートするの忘れてたり、変数 被って使ったりしてたので、修正&説明追加。 <?php $str = "ababcdefgh"; /* 文字列の数をカウント(↓↓で配列にしたものをcount()しても良かったけど) */ $length = strlen($str); /* 文字列を配列に分ける */ $DimStr = str_split($str); /* 上の配列をソート(←忘れてたのコレ) */ sort($DimStr); /* 何回ループさせるか */ $loop = pow(2 , $length); /* ↑なんで 2の累乗にしてるかってのは 二進数で総当りをするから。 */ for($i=1;$i<$loop;$i++) { /* 10進数を二進数に変換(↓変数被ってたのコレ $strだった) */ $bin = decbin($i); /* 左を0で埋めて 桁を揃える。 */ $mask = sprintf("%0{$length}d" , $bin); /* これも 配列に 分解。 */ $DimMask = str_split($mask); $ans = ""; /* 桁数分 繰り返し。 */ foreach($DimMask as $j => $bit) { /* 1に なっている時だけ 文字列の 該当箇所の 文字を くっつける。 */ $ans .= ($bit == 1) ? $DimStr[$j] : ""; } /* 出来上がったものを 配列のキーとして入れる。ついでに、既に同じものがあった時はカウントアップ。 */ $DimAnswer[$ans]++; } print_r($DimAnswer); ?>

takagoo100
質問者

お礼

ご回答ありがとうございます。 なるほど、試してみました凄い速度があがりました。 ありがとうございます。 ただ取得できる値は、自分が求めている結果通りなのですが、 どうも文字列が $str = "abcdefghijkl"; 12桁だと対応してないようなのです・・・ で原因を自分なりに調べてみたら $mask = sprintf("%0{$length}d" , $bin); の%dがどうやら原因らしいのです。 例えばこのやり方で調べてみると $loop = pow(2 , 12); $str = decbin($loop); $mask = sprintf("%0{$length}d" , $str); print "str=" . $str . " m=" . $mask . "<br>\n";//str=1000000000000 m=2147483647 と2147483647の値以上は扱えないらしいのです。 一応windows7の64ビットでXAMPPの環境でやっているのですが、 どうしたら%dの扱える範囲を増やすことができるのでしょうか?

その他の回答 (6)

  • bm_hiro
  • ベストアンサー率51% (200/388)
回答No.7

何度もすみません。 > $mask = sprintf("%0{$length}F" , $bin); > 得られた行の数は1040行で時間は0.06秒ぐらいでした。 > $mask = str_repeat("0" , ($length - strlen($bin))) . $bin; > 得られた行の数は4095行で時間は0.05秒ぐらいでした。 この違いが ちょっと腑に落ちなかったんで、俺も試してみました。 結論 : %F のほうは 小数点入ってしまってました。 ちなみに、%s で str_repeat と同じような結果になるようです。 マニュアルによると、「s - 引数を文字列として扱い、表現します。」 常に %d しか使ってなかったもんですから、すっかり %s の存在を忘れてました。 http://php.net/manual/ja/function.sprintf.php あと 「4095行」って言う数字を見て とある可能性に気が付いたんですけど、これって 「2の12乗-1」ですよね。 多分、「文字列の中に 同じ文字がない12文字の文字列」だったんじゃないですか? 同じ文字がない条件においては、単純に ↑これで計算できるって事かもしれません。 なので、同じ文字の数を数えたりして「なんやかんや」すると、総当りしなくても いいのかもしれません。 「なんやかんや」に関しては ツッコまないでください。 分ってて書いてるわけでなくて、もしかしたら法則性があるのかもと ふと思っただけですので。

takagoo100
質問者

お礼

ご回答ありがとうございます。 >これって 「2の12乗-1」ですよね。 なるほど、たしかにその数字ですね。。 >「文字列の中に 同じ文字がない12文字の文字列」 そうですね、試しているうちに全て違う文字が一番時間がかかっていたようなので 自分は基本的に試すときは全て違う文字から試しています。 >総当りしなくても いいのかもしれません。 なるほど、たしかに何か工夫できそうな気がします。。 しかしとりあえず得られた結果は満足でしたので、これで質問を終わりたいと思います。 ありがとうございました。

  • 1minn
  • ベストアンサー率57% (52/90)
回答No.6

#1です #4で求められている %dに代わるものであれば%F(小文字かも)で対応しては? Int型では10桁が限界ですが、floatだと扱える範囲は大きくなります。 が、どっちにしろ限界はあるので、文字数が倍になれば破たんしちゃいますね。 #4にて提示されているコードで疑問に思ったのですが、「aba」を実行した場合に「aab」になりますよね? 質問には「aba」とありますが・・・ #1への返答にも同様に「abab」という値がありますが、これも「aabb」になっちゃいますよね? 実際に求められているものはこれで正しいんですか? いまいち仕様が理解出来なくてすみません。頭悪いな・・・ あとforeachのエラー(ワーニング)は出ないですね。失礼しました。 日頃から癖で if ( is_array($arr) && count($arr) > 0 ) ってのをチェックしてからforeachを使うようにしてます。なので要素が空だと怒られちゃうと無意識に思ってました。

takagoo100
質問者

お礼

ご回答ありがとうございます。 >「aba」を実行した場合に「aab」になりますよね? いえたしかになりましたが、自分の希望とする結果は aabでもbaaでもabaでも文字の順番は関係なくて、 とにかく aが2文字、 bが1文字 の合わせて3文字のユニークな行が 1つだけ得られればいいのです。 >いまいち仕様が理解出来なくてすみません。 いえこちらこそ自分ですらはっきり理解できなくて^^;) 質問自体のミスをしたり、他の方にうまく説明できない状況です・・・ >if ( is_array($arr) && count($arr) > 0 ) 自分もたまにというか^^;)出ることがあるので、 初めはつけていたのですが、この例のコードではでなかったので 一応取り外したという経緯です。。 今、%Fで試したみたのですが、 $mask = sprintf("%0{$length}F" , $bin); 得られた行の数は1040行で時間は0.06秒ぐらいでした。 No.5のbm_hirosさんの提示して頂いたやり方では $mask = str_repeat("0" , ($length - strlen($bin))) . $bin; 得られた行の数は4095行で時間は0.05秒ぐらいでした。 なんか不思議な^^;)結果というかおそらく行数的には後者の方が 自分が求めている結果だと思います。 それにしても行が多くなったのに秒数が少し減るというのは 自分的には不思議ですね。。。

  • bm_hiro
  • ベストアンサー率51% (200/388)
回答No.5

場当たり的な対応で申し訳ないんですけど、これでやってみてください。 桁を揃えるだけなので、sprintf() にこだわる必要はありませんので。 $mask = str_repeat("0" , ($length - strlen($bin))) . $bin; ただ、二進数の総当りだと 桁が増えると 天文学的数字になりかねないんで、キツいかもしれないですね。(´・ω・`)

takagoo100
質問者

お礼

ご回答ありがとうございます。 >ただ、二進数の総当りだと 桁が増えると 天文学的数字になりかねないんで、キツいかもしれないですね。 いやいやこれ滅茶苦茶早くないですか^^;) 12文字の$str = "abcdefghijkl"; で試したのですが、0.05秒でした^^;) 全部あるかどうかというのは多すぎて分からないのですが、 一応上から下まで見渡してa~lまで含んであったので、おそらくその通りなんでしょうね。。 自分的には12文字くらいは必要だったので助かりました。 ありがとうございます。 ちなみにいいろいと試してみたのですが、16文字から急にきつく(時間がかかる)なりました。 $str = "abcdefghijklmnop";

  • bm_hiro
  • ベストアンサー率51% (200/388)
回答No.3

今 あまり時間無いので 説明はしょりますが、つまりは こんな感じです。 何か 意図してたものと違ってたらすみません。 <?php $str = "ababcdefgh"; $length = strlen($str); $DimJob = str_split($str); $loop = pow(2 , $length); for($i=1;$i<$loop;$i++) { $str = decbin($i); $mask = sprintf("%0{$length}d" , $str); $DimMask = str_split($mask); $ans = ""; foreach($DimMask as $j => $bit) { $ans .= ($bit == 1) ? $DimJob[$j] : ""; } $DimAnswer[$ans]++; } print_r($DimAnswer); ?>

  • bm_hiro
  • ベストアンサー率51% (200/388)
回答No.2

正直、なんで こんな長いスクリプトになってるのかなー。。。と思いました。 とか言っておきながら、自分で書いてもこんな長くなるかもしれません。 面倒なので ちゃんと動くものは作りませんが、俺なら以下のような感じにします。 1.まず、与えられた文字列を ソートします。 配列にぶった切って sort()すると楽かもしれません。 マルチバイト文字はないって前提で考えてますのでご了承ください。 これは↓の対策としてソートしただけです。 // 順不同の文字列マッチ // "aba" と ”aab”は一緒(true) 2.文字の数の分の2進数を用意します。 3.2進数でマスクかけてフラグが立ってる(1になってる)部分だけ結合していって文字列にします。 4.んで、その文字列を「配列のキー」として、格納します。こうすると自動的に重複は除外されます。要素はカウンタにするなりなんなりお好みで。 5.配列のキーが お望みの答えになってるはずです。 テキトーに考えたので、どっかでおかしな事になるかもしれませんし、処理速度とかはどうなるか分りません。 俺なら とりあえず こんな感じで試してみますかねーって程度の意見としてお聞きください。

takagoo100
質問者

お礼

ご回答ありがとうございます。 なるほど、たしかに連想配列なら自然と重複が出なくなりますね。 参考になりました。 ですが、 >3.2進数でマスクかけてフラグが立ってる(1になってる)部分だけ結合していって文字列にします。 これの(1になってる)と仰ったのですが、どのようにして1にしているのでしょうか? >配列にぶった切って sort()すると この部分と関係してるのかな?と思ったのですが、 これは for ($i = $startIndex; $i < $cnt; $i++) { $text = ""; $text .= $addText . $this->_characters[$i]; この部分で置き換えると、$this->_flagsみたいなフィールドがあったとして それをこのforループと全く一緒のループの仕方でフラグを1にするということなのでしょうか? つまり自分のこのループでキーを作ってやるやり方と、bm_hiroさんが仰ってるフラグを立ててからキーを作る やり方の大きなといったらあれですが、違いというかメリットがよく分からないのですが、 そこらへんを教えて頂けないでしょうか?

  • 1minn
  • ベストアンサー率57% (52/90)
回答No.1

仮に「abab」だった場合は「ab」ってのが二つになるんでしょうか? 重複は省くかどうかで作り方も少し変わるかな・・・ 「aba」と「aab」は一緒ってルールがよくわかんないです・・・ この場合は「ab」二つにはならないのかな? というかまずエラーかワーニングでますよねこの状態だと。 初回にsetListが実行される段階だとforeachのとこで出ませんか? (ナナメ読みな感じなので間違ってたらごめんなさい) あと、想定外かもしれませんが、getListを実行したあとの結果も同様に。 で、ところどころ「参照」を使ってますが効率的ではないと思いました。 最終的に処理が終わった段階でreturn $listに入ってる値が欲しいんですよね? それであれば、やたらと&が登場して読みにくい事も含め、メンバ変数にした方がよいです。 あとループでcountを使うのはメモリ資源の無駄遣いになります。こことか。 for ($i = $startIndex; $i < count($this->_characters); $i++) 例えば $this->_cnt = count($this->_characters); 的な事をコンストラクタでやっとけば、あとはその変数を使えばいいだけですから、count関数が実行される数は減りますよ。 こんな感じで for ($i = $startIndex; $i < $this->_cnt; $i++) 全部はちゃんと見てないんで他にもありそうです。

takagoo100
質問者

お礼

ご回答ありがとうございます。 >仮に「abab」だった場合は「ab」ってのが二つになるんでしょうか? いえそのケースなら、 a ab aba abab abb aa b bb になります(例のコードの結果です)。 つまり「ab」というのはその得た行のユニーク値です。 ですが、No.2でbm_hirosさんも仰っていますが、 自分も同じ候補のカウント数が欲しいと思ったので 例のコードと意図が少し変わってきますが、 a 2 ab 2 abab 1 ・・・ という具合で結果が得たいです(と思いました。。) >というかまずエラーかワーニングでますよねこの状態だと。 >初回にsetListが実行される段階だとforeachのとこで出ませんか? 確認なのですが、これは太字(^^)のPHPエラーが出るということですよね? それならば今のところは出てないです。。 >それであれば、やたらと&が登場して読みにくい事も含め、メンバ変数にした方がよいです。 >あとループでcountを使うのはメモリ資源の無駄遣いになります。こことか。 なるほど、たしかに効率以前に見難いですよね・・・ そこで仰るように修正して文字列「abcdefgh」試してみたところ 0.62~0.65秒 から 0.57~0.59秒 になりました。 まあこれは測度がどうとかいう問題じゃないかもしれませんが とにかく良くなったと思います。 参考になりました。

takagoo100
質問者

補足

すいません、補足を借ります。。。 //文字の総当たりを得る //aba なら a,b,ab,aa,aba class AllCombinationCharacter { private $_characters = array(); private $_list = array(); public function __construct($text) { $this->_characters = self::split($text); } public static function split($text) { $cnt = 0; $arr = array(); while ($chara = substr($text, $cnt++, 1)) { $arr[] = $chara; } return $arr; } private function setList($addText) { if (is_array($this->_list)) { $find = false; foreach ($this->_list as $item) { if (self::isMatchInRandomOrder($item, $addText)) { $find = true; break; } } if (!$find) { $this->_list[] = $addText; } } } private function recursive($addText, $startIndex) { $cnt = count($this->_characters); for ($i = $startIndex; $i < $cnt; $i++) { $text = ""; $text .= $addText . $this->_characters[$i]; //echo "t=" . $text . "<br>\n"; $this->setList($text); $this->recursive($text, $i + 1); } } public function getList() { $list = array(); $this->recursive("", 0); return $this->_list; } // 順不同の文字列マッチ // "aba" と ”aab”は一緒(true) public static function isMatchInRandomOrder($text1, $text2) { $tips = self::split($text2); $cnt = count($tips); for ($i = 0; $i < $cnt; $i++) { $searchString = $tips[$i]; $text1 = preg_replace("/{$searchString}/", "", $text1, 1); if ($text1 == "") { break; } } if ($text1 == "" && $i == count($tips) - 1) { return true; } return false; } } $startTime = microtime(true); $obj = new AllCombinationCharacter("abcdefgh"); foreach ($obj->getList() as $item) { echo "t=" . $item . "<br>\n"; } $endTime = microtime(true); echo $endTime - $startTime . "秒";

関連するQ&A

  • returnするには?

    下記のようなソースなのですがarray_walk_recursiveを使用しつつ値を returnするにはどうすればいいでしょうか? 可能であれば仕様上あまり構造変更なくできる方法がいいのですが・・・ class Test { public function hoge($arr){ if (is_array($arr)) { //↓をreturnすると1が返る array_walk_recursive($arr['types'], array($this, 'fuga')); } } function fuga($val){ //echo $val;とすると意図する値が渡っています switch($val) { case 'str': return $this->str();//ここの値が返らない } }

    • 締切済み
    • PHP
  • 割り切れなくなるまで分割して配列に入れたい

    <?php make(7); function make($n) { $arr = array($n); $arr_new = division_arr($arr); print_r($arr_new); } function division_arr($arr) { for ($i = 0; $i < count($arr); $i++) { $arr_new[$i] = division($arr[$i]); if ($arr_new[$i][0] > 0) { return division_arr($arr_new[$i]); } else { } } return $arr_new; } function division($n) { $a = $b = floor($n / 2); if ($n % 2 != 0) { $b+=1; } return array($a, $b); } /* array( [3,4], [[1,2],[2,2]], [[0,1],[1,1],[1,1],[1,1]] ); 再帰的に配列を分割していき、最終的にこのような出力にしたいです。 */ ?> 教えて下さい。よろしくお願いいたします。m(_ _)m

    • ベストアンサー
    • PHP
  • 2つの配列を再帰的に上書きでマージしたい

    array_merge_recursive では配列が同じ数値キーを有している場合、 後の値は元の値を上書せず、追加されます。 これを上書されるようにしたいのですが、どのようにすれば良いでしょうか? $arr3 = mymerge($arr1,$arr2); のような形で$arr3が得られると助かります。 $arr1,$arr2は再利用したいので書き換えられないようにしたいです。 次のような物をネット上で見つけたのですが、これでは$arr1が書き換えられてしまいます。 function mymerge(&$arr1,$arr2){ foreach ($arr2 as $key=>$value){ if(is_array($value)){ mymerge(&$arr1[$key],$value); }else{ $arr1[$key]=$value; } } return $arr1; } 次のようにすれば良いのかもしれませんが、1つのfunctionでできると助かります。 $temp1 = array(); $temp2 = mymerge($temp1,$arr1); $arr3 = mymerge($temp2,$arr2); いくら考えても分からないので、すみませんがどなたか教えてください。_○_

    • ベストアンサー
    • PHP
  • どのような関数名を付けるべきなのでしょうか?

    比重(比率)を利用して乱数を取得したいと思って、 そのような関数を探してたのですが見つからなかったので自作したのですが、 関数名の付け方に迷いがあるのでアドバイス頂けないでしょうか? 例えば array(  array('weight' => 3, 'min' => -3, 'max' => -1),  array('weight' => 7, 'min' => 4, 'max' => 5), ) と値を渡せば、 30%の確率で-3から-1の間でランダムした結果を取得 70%の確率で4から5の間でランダムした結果を取得 できます。 比重(weight)を利用してるので 「randByWeight」 と仮に名前を付けたのですが、 自分としてはそもそも文法的に合ってるのかも曖昧ですし、 プログラム的な命名規則に則してるかも分かりません・・・ まあそんなに深く考えずに「myrand」とかでもいいんでしょうけど、 この関数の作り方や設計の誤りなども含めてアドバイスして頂きたいです。 /**  * randByWeight  *   * @param $params  * @return int  */ function randByWeight($params) {  if (!isset($params[0])) {   $params = array($params);  }    $index = 0;  $range = array();  foreach ($params as $param) {   if ($index >= 1){    $range[$index]['start'] = $range[$index - 1]['end'] + 1;   } else {    $range[$index]['start'] = 1;   }   $range[$index]['end'] = $range[$index]['start'] - 1 + (isset($param['weight']) ? $param['weight'] : 1);   $index++;  }   // srand( (int)( ((float)microtime()) * 1000000 ) );  $ran = rand(1, $range[$index - 1]['end']);  for ($i = 0; $i < $index; $i++) {   if ($range[$i]['start'] <= $ran && $ran <= $range[$i]['end']) {    if (isset($params[$i]['recursive']) && is_array($params[$i]['recursive'])) {     return randByWeight($params[$i]['recursive']);    } else {     if($params[$i]['min'] > $params[$i]['max']) {      $params[$i]['min'] = $params[$i]['max'];     }       return rand($params[$i]['min'], $params[$i]['max']);    }   }  } } // 使用例 $arr = array(  array('weight' => 3, 'min' => -10, 'max' => 1),  array(   'weight' => 1,   'recursive' => array(    array('weight' => 1, 'min' => 2, 'max' => 2),    array(     'weight' => 10,     'recursive' => array(      array('weight' => 3, 'min' => 3, 'max' => 3),      array('weight' => 7, 'min' => 4, 'max' => 4),     ),    ),   ),  ), ); $result = array(); for ($i = 1; $i <= 100; $i++) {  $result[randByWeight($arr)]++; } $sum = 0; ksort($result); foreach ($result as $value => $cnt) {  print "{$value}:{$cnt}<br>\n";  $sum += $cnt; } print "sum={$sum}<br>\n";

    • ベストアンサー
    • PHP
  • array_intersectで空欄を比較しない

    お世話になります。 $arr1 = array(1,2,3); $arr2 = array(2,3,4); という配列が存在していたとき、これらすべてに共通する値を取り出すとき、 array_intersect($arr1,$arr2) で良いと思うのですが、上記に更に値があるか分からない配列($arr3,$arr4)を比較したいときどのように記述すればよいでしょうか? $array_list[] = $arr1; $array_list[] = $arr2; if($arr3 != NULL){$array_list[] = $arr3;} if($arr4 != NULL){$array_list[] = $arr4;} $array_list = implode(",",$array_list); と半ば強引に配列に追加したのですが、var_dump($array_list)したところ、 Array,Arrayとなってしまいました。 $arr3,$arr4に値が入っている場合と入っていない場合でif分岐させて、 array_intersect($arr1,$arr2) array_intersect($arr1,$arr2,$arr3) array_intersect($arr1,$arr2,$arr4) array_intersect($arr1,$arr2,$arr3,$arr4) の4パターンを書くこともできるかと思いますがスマートではないような気がしまして・・・。 なにかよい方法が有りましたらよろしくお願い致します。

    • ベストアンサー
    • PHP
  • 改行コードの変換と削除

    改行コード変換メソッドで$dataには配列形式のデータが入ります。 public function v_line($val, $arr = false) { $line = ''; if(is_array($val)){ return array_map(array($this, 'v_line'), $val); } return str_replace(array("\r", "\n"), $line, $val); } //メソッド実行 $this->v_line($data); この結果全ての改行コードが削除されます。これを特定のキーのみ削除ではなく"\n"に 統一させるように変換したいのですがどのようにすればできますでしょうか? //改行コード削除しないキー配列 $arr = array('comment01', 'comment02'); //$arrのキーのみ改行コードを変換しその他は改行コード削除 $this->v_line($data, $arr);

    • ベストアンサー
    • PHP
  • 「checkText3」が処理されない

    とあるHOWTO本を見ながら、独学でPHPを勉強中です。 サンプルプログラムを動作させようとマニュアル通りに記述してみたのですが、一部分だけが上手く処理されません。 付属CDに収められているphpファイル自体がこのような記述になっている為、マニュアル自体に間違いがあるのかな?と思うのですが、 どこがおかしいのか解らずにいます。 お分かりになる方がいれば、ご教授願えませんでしょうか? 上手く処理されないのは「//テキストチェック3.バイバイされたらバイバイを返す」の部分です。 よろしくお願い致します<(_ _)> <?php $res = ""; if(isset($_POST['text1']) == false) {$res = getAisatsu();} else{$text1 = $_POST['text1']; if($text1 == "") {$res = "え? なんていったの?";} else{$flag =false; //まずcheckTextであいさつ文をチェック $str = checkText($text1); if($str != false) {$flag = true; $res = $str; } //続いてcheckText2で悪口の対応 if($flag == false) {$str = checkText2($text1); if($str != false) {$flag = true; $res = $str; } } //最後にcheckText3でさよならの対応 if($flag == false) {$srt = checkText3($text1); if($str != false) {$flag = true; $res = $str; } } //すべてダメならテキストを分解してチェック if($flag == false) {$arr = bunkatsu($text1); foreach($arr as $str) {if(getWordCheck($str) == true) {$flag = true; $res = $str . "って、なぁに?"; break; } } } //それでもダメなら全文で聞き返す if($flag == false) {$res = delTouten($text1) . "って、なぁに?";} } } //時間によって異なるあいさつ文を返す function getAisatsu(){ $arr = array('……ね、眠い','おはよう!','こんにちは~','こんばんわ',); $d = getdate(); $t = $d['hours']; $t2 = (int)($t / 6); return $arr[$t2]; } //テキストチェック。あいさつ文があれば対応する挨拶を返す function checkText($s){ if($s == ""){return false;} $res = false; $data = array('こんにちは','こんにちわ','こんちは','こんちわ'); foreach($data as $str) {if (mb_strpos($s,$str) !== false) {$res = 'どうも、' . $str . '!'; break; } } return $res; } //テキストチェック2.悪口が書かれていたら文句をいう function checkText2($s) {if ($s ==""){return false;} $res = false; $data = array('バカ','馬鹿','あほ','アホ','阿呆'); foreach($data as $str) {if(mb_strpos($s,$str) !== false) {$res =$str . 'じゃないもん!'; break; } } return $res; } //テキストチェック3.バイバイされたらバイバイを返す function checkText3($s) {if ($s == ""){return false;} $res = false; $data = array('ばいばい','バイバイ','じゃあね'); foreach($data as $str) {if(mb_strpos($s,$str) !== false) {$res = 'それじゃ' . $str . '!'; break; } } return $res; } //句読点を削除する function delTouten($s) {$res = str_replace('。','',$s); $res = str_replace('?','',$res); $res = str_replace('!','',$res); $res = str_replace('.','',$s); $res = str_replace('?','',$res); $res = str_replace('!','',$res); return $res; } //テキストを句読点で分割し、配列として返す function bunkatsu($s) {mb_regex_encoding("sjis"); $res = mb_ereg_replace('[。、?!,.!?]','',$s); $arr = mb_split(' ',$res); return $arr; } //主語や接続詞が含まれているかを調べる function getWordCheck($s) {if ($s == ""){return false;} $res = $s; $data = array('私','わたし','僕','ぼく','俺','おれ','オレ'); foreach($data as $str) {if(mb_strpos($s,$str) !== false) {$res = false; break; } } return $res; } //サニタライズ function getSeftyText($s) {$res = str_replace("<","<",$s); $res = str_replace(">",">",$res); return $res; } ?>

    • ベストアンサー
    • PHP
  • forの中にいれたcreateTextの使い方

    はじめまして、 内容をまとめて書いてあるテキストがあり、これを変数に入れて分割したものを画面に表示させたいのですが、表示するところがうまくいきません。 createTextの書き方がおかしいと思うのですがどこを書き換えればいいのかわかりません。 すいませんがどなたかお教え願えないでしょうか。 var text1=new LoadVars(); text1.load("test.txt") text1.onLoad=function(){   var test_array:Array=text1.split(",");   for(var i=0;i<test_array.length;i++){   this.createTextField("c"+[i],this.getNextHighestDepth(),50,20+i*20,200, 20); this.c[i].text =test_array[i]; } 多分thisのあたりがおかしいと思っているのですが、どう書けばいいのかわかっていません。 すいませんがどなたかお願いします。

  • null除去、これで大丈夫ですか?

    function sanitize(&$arg){ if (is_array($arg)){ array_walk_recursive($arg,function(&$val,$key){if(is_string($val))$val=str_replace("\0", "", $val);}); }else{ if(is_string($arg))$arg=str_replace("\0", "", $arg); } return $arg; }

    • ベストアンサー
    • PHP
  • JavaScriptで全くの初心者なのですが、

    JavaScriptで全くの初心者なのですが、 フィッシャーイェーツのシャッフルをaのリスト内でしてから、 そこから一つ値をとり、 別の関数内で、その関数内での新たな変数に代入するようにしたいです。(function(){var b = this.result;}のような) プログラミングはやらないのに急に使うことになり困っているのでだれか助けてください。 a = [1,1,1,5,5,5,9,9,9]; for (var a=[],i=0;i<9;++i) a[i]=i; this.result = a[shuffle(a.length)] ; function shuffle(array) { var tmp, current, top = array.length; if(top) while(--top) { current = Math.floor(Math.random() * (top + 1)); tmp = array[current]; array[current] = array[top]; array[top] = tmp; } return array; }

専門家に質問してみよう