phpのarray_searchとarray_count_valuesではまった事
phpのarray_searchでちょっとつまずいてしまった事です。
array_searchって自分としては割と良く使ったりするのですね。
良く使ってんだから、良く知ってるはずなんだけど・・・。
php使いとして当然のごとく知っていなければいけないことといえば。
array_searchにおいては、マッチした対象が配列の先頭にあった場合、戻り値は0になるのでif 文では注意が必要と。strposなんかと同じことですね。
こんなことをやったりすると・・・、
<?php
$testary = array( 'a', 'b', 'c', 'd', 'e' );
if ( array_search( 'a', $testary ) ) {// 戻り値は0なのでfalse
echo '<p>Yes! true!</p>';
} else {
echo '<p>No! false!</p>';
}
?>
「No!」が返されてきたりするのです。
これは、if ( false !== array_search( 'a', $testary ) ) と書けばよいだけのこと。
まぁ、ただしこんな場合は、ただあるかないかだけのことならarray_searchを使うことでもないのかとも。
ところで、と・・・。
今回、ちょっとつまずいてしまったのは、array_count_valuesがらみでのこと。
画像をクリックした時のログをとっていて、その画像が何度クリックされたかを表示しようとしていたのです。
たとえば、そのログというのは下のようにとっているのですが。
2016/09/14 11:21:45 [127.0.0.1] [strix-ss-PC] [1546] [bird_image] ./img/1001546.jpg
2016/09/14 11:21:47 [127.0.0.1] [strix-ss-PC] [1546a] [bird_image] ./img/1001546a.jpg
2016/09/14 11:21:49 [127.0.0.1] [strix-ss-PC] [1546b] [bird_image] ./img/1001546b.jpg
2016/09/14 12:15:59 [127.0.0.1] [strix-ss-PC] [1539] [Broad-billed_Sandpiper] ./img/1001539.jpg
2016/09/14 12:16:04 [127.0.0.1] [strix-ss-PC] [1516] [Common_Greenshank] ./img/1001516.jpg
2016/09/14 12:21:45 [127.0.0.1] [strix-ss-PC] [1546] [bird_image] ./img/1001546.jpg
このファイルを読み込んでexplodeを使ってスペースで分割して配列にして使っています。
画像をクリックした回数を得るのに必要なデータは、スペースで分割した場合の5番目のデータだけで良いので、余分なものを省いてそれだけの配列にしています。そして、array_count_valuesを使って重複したデータの個数を計算させているわけです。
array_count_valuesは、引数で渡された配列の、重複した値の個数を出し、その配列の値をキーとして、個数を値とした新たな配列を戻り値として返します。
で、その個数の入った配列は、あとでキーを検索して使用するために、そのキーを値とした配列をarray_keysにて作っています。
<?php
$qimgfile = './team/qlickimg.php';
$qiline = array();
$qiline = file( $qimgfile );
$qlist = array();
foreach ( $qiline as $val ) {
if ( strlen( $val ) > 40 and false !== strpos( $val, ' ' ) ) {
$qtmplist = explode( ' ', $val );
if ( count( $qtmplist ) > 4 ) {
$qlist[] = str_replace( array( '[', ']' ), '', $qtmplist[4] );
}
}
}
$qcount = array_count_values( $qlist );
$rqlist = array_keys( $qcount );
?>
ちなみにこの元々の配列$qlist はどういう配列なっているかというと下のような感じ。 この数字による文字列が画像を識別できる固有の文字列ということになります。
Array (
[0] => 1546
[1] => 1546a
[2] => 1546b
[3] => 1539
[4] => 1516
[5] => 1546
)
実際に画像のファイル名というのが ./img/1001546b.jpg とかだったりするのですが、その画像固有の文字列を正規表現で抜き出して、たとえばこの画像の場合なら”1546b”という文字列を得ます。この得られた文字列にて上の配列を検索することとなります。
しかし、問題はここで起こってしまうのであります。
まぁ、下のようなことをやってみたのではありますが・・・。
<?php
// このurlから1546bを抜き出したいというのが意図するところ
$img = './img/1001546b.jpg';
$pattern = '/.\/img\/(100)*(\d{2,5}[ab]*).jpg/';
if ( preg_match( $pattern, $img, $matches ) ) {
$targetstr = $matches[2];// $targetstrには"1546b"
$searchflg = array_search( $targetstr, $rqlist );
$numclick = 0;
if ( $searchflg !== false ) {
$numclick = $qcount[ $rqlist[ $searchflg ] ];
}
}
?>
が、しかしこの場合のarray_searchの戻り値$searchflg には 0 が入っていて、1546にマッチしたということがわかります。
あれっ!なんだこれっ!と思いつつもこれはピ~ンときます。
array_searchは、第三引数のstrict にtrue を指定しないと、== による比較を行うという事。
1546 == 1546b となってしまったということは、これは数字の1546と文字列である1546bの比較が行われて、自動的に型変換をしてくれてマッチしたものと思われます。
元々が文字列だったわけなので、どこでこうなったかというのは、ほぼあてがつきます。
ちなみに、$qlist、$qcount、$rqlist、において各値の型はどうなっているかと一応調べて見ると以下のようになります。
$qlist
array(6) {
[0]=>string(4)"1546"
[1]=>string(5)"1546a"
[2]=>string(5)"1546b"
[3]=>string(4)"1539"
[4]=>string(4)"1516"
[5]=>string(4)"1546"
}
$qcount
array(5) {
[1546]=>int(2)
["1546a"]=>int(1)
["1546b"]=>int(1)
[1539]=>int(1)
[1516]=>int(1)
}
$rqlist
array(5) {
[0]=>int(1546)
[1]=>string(5)"1546a"
[2]=>string(5)"1546b"
[3]=>int(1539)
[4]=>int(1516)
}
と、いうことでやはりということになります。
これに関しては、array_count_valuesがどうこうという問題では無く、php の配列における基本的な仕様ということです。
php において配列のkey は整数 または 文字列であり、
「integer として妥当な形式の文字列は integer 型にキャストされます。」と、いうことです。
ちなみに、floatやboolもキーの場合はinteger にキャストされるということです。はは・・・、実はこれ、知らなかったのでありまして。知っていないといけないことだったと。
ちなみに、値が'01'とかであった場合、これは文字列のままということのようです。違う時にarray_flip() でやってみましたが、これはそのまま文字列のキーとして入れ替わりました。
これはこの状態で、array_searchの第三引数のstrict にtrue を指定しても無意味です。結局数字と文字列の比較になってしまうので、期待した結果は得られないということになります。
$rqlist の全ての値を同じく文字列にそろえてしまえば解決する事だと思います。これが最善なのかはわからないのですが、私的に考えてarray_keys を使用せずに以下のようにしてみました。
<?php
$qimgfile = './team/qlickimg.php';
$qiline = array();
$qiline = file( $qimgfile );
$qlist = array();
foreach ( $qiline as $val ) {
if ( strlen( $val ) > 40 and false !== strpos( $val, ' ' ) ) {
$qtmplist = explode( ' ', $val );
if ( count( $qtmplist ) > 4 ) {
$qlist[] = str_replace( array( '[', ']' ), '', $qtmplist[4] );
}
}
}
$qcount = array_count_values( $qlist );
$rqlist = array();
$ralist = array();
foreach ( $qcount as $key=>$val ) {
$rqlist[] = strval( $key );
$ralist[] = $val;
}
?>
そして、
<?php
// このurlから1546bを抜き出したいというのが意図するところ
$img = './img/1001546b.jpg';
$pattern = '/.\/img\/(100)*(\d{2,5}[ab]*).jpg/';
if ( preg_match( $pattern, $img, $matches ) ) {
$targetstr = $matches[2];// $targetstrには"1546b"
$searchflg = array_search( $targetstr, $rqlist );
$numclick = 0;
if ( $searchflg !== false ) {
// ↓これでも機能しますが・・・?
//$numclick = $qcount[ $rqlist[ $searchflg ] ];
// ↓型変換が行われないゆえにこちらの方が良いように思える
$numclick = $ralist[ $searchflg ];
}
}
?>
全て同じ文字列同士の比較ということになるので、array_searchの第三引数のstrict は指定しなくても期待した結果が得られました。
Post : 2016/09/14 20:10
Comments feed
Trackback URL : https://strix.main.jp/wp-trackback.php?p=71326