ラベル function の投稿を表示しています。 すべての投稿を表示
ラベル function の投稿を表示しています。 すべての投稿を表示

2009年12月4日金曜日

PHPでの配列の並び替え(ソート)の比較

PHP5.3で実験。
何気なくsort()を使うと、意外と意外な結果になるので注意。

$before = array('Google', 'apple', '+11112', 1112, '112', 12, '0', -1);

$array = $before;
sort($array);
foreach ($array as $val) echo $val . ', ';
//sort()の第2引数のデフォルトはSORT_REGULAR
//文字列は大文字優先
//今回のように数値と文字列が混在するとおかしくなる?
// => -1, 0, 112, Google, apple, 12, 1112, +11112,
echo '<hr />';

$array = $before;
sort($array, SORT_NUMERIC);
foreach ($array as $val) echo $val . ', ';
//数値としてソート
//文字列は大文字・小文字を無視したソートで、ゼロの前になるようだ
// => -1, apple, Google, 0, 12, 112, 1112, +11112,
echo '<hr />';

$array = $before;
sort($array, SORT_STRING);
foreach ($array as $val) echo $val . ', ';
//文字列としてソート
//記号、数字、文字列(大文字優先)の順
//数は数ではなく文字列としてソートされる
// => +11112, -1, 0, 1112, 112, 12, Google, apple,
echo '<hr />';

$array = $before;
sort($array, SORT_LOCALE_STRING);
foreach ($array as $val) echo $val . ', ';
//localeごとのソート(今回の環境ではSORT_STRINGと同じだった)
// => +11112, -1, 0, 1112, 112, 12, Google, apple,
echo '<hr />';

$array = $before;
natsort($array);
foreach ($array as $val) echo $val . ', ';
//「自然順アルゴリズム」
//人間がやったらまあこうするだろうという感じか
//記号、数、文字列の順
//数値は文字列ではなく数値としてソートされるのがSORT_STRINGとの違い
// => +11112, -1, 0, 12, 112, 1112, Google, apple,
echo '<hr />';

$array = $before;
natcasesort($array);
foreach ($array as $val) echo $val . ', ';
//「自然順アルゴリズム」、かつ大文字小文字を区別しない
// => +11112, -1, 0, 12, 112, 1112, apple, Google,

natcasesort()が一番しっくりくる。
大文字・小文字の違いは無視して欲しいし。

2009年7月28日火曜日

PHPの URLエンコード (urlencode, rawurlencode, http_build_query)

(2013/5/19 変更:rawurlencode()はRFC3986なのにRFC1738と書いてたので訂正。)


まずはurlencode()rawurlencode()を比較。

  • urlencode()
    • 半角チルダ(~)を%7Eに変換する
    • 半角スペースをプラス(+)に変換する
  • rawurlencode()
    • 半角チルダ(~)の変換についてはPHPのバージョンによって違う
      • PHP 5.2.xまでは、%7Eに変換する
      • PHP 5.3.0からは、%7Eに変換しない(チルダのまま)
    • 半角スペースを%20に変換する

rawurlencode()はRFC1738 RFC3986に沿った変換とされているので、基本的にはurlencode()よりrawurlencode()の方が無難。
ただし、RFC1738 3986ではチルダを%7Eに変換しない。


ちなみに、RFC1738はその後、RFC3986によって更新されているが、RFC3986はパッと見た感じではURLエンコードについては(JavaScriptのencodeURIComponent()で使われるRFC2396の方ではなく、)RFC1738を踏襲しているようだ。(2013/5/19 追記:一部変更されてる。)

Amazonの新しいAPIでも、RFC3986によるURLエンコードを使っている。(参考:Amazon Product Advertising API への対応(PHP版) - もやし日記



次に、http_build_query()の話。
http_build_query()は便利だが、URLエンコードの内容はurlencode()と同じなのが残念。
RFC1738/3986に沿った形にするには、もう1つ変換を咬ませなければならない。
//例
function encodeAlongRFC1738($str) {
return strtr($str, array('%7E' => '~', '+' => '%20'));
}

echo encodeAlongRFC1738(http_build_query($arr));
上記の変換は、PHP5.2までのrawurlencode()にも使える。



あとは実験結果。上記のencodeAlongRFC1738()も交えて。
元の文字
 "~_ _+"

urlencode()の場合
変換結果
 "%7E_+_%2B"
urldecode()すると
 "~_ _+"
rawurldecode()すると(正しくデコードできない)
 "~_+_+"

rawurlencode()の場合(PHP 5.2)
変換結果
 "%7E_%20_%2B"
urldecode()すると
 "~_ _+"
rawurldecode()すると
 "~_ _+"

rawurlencode()の場合(PHP 5.3)
変換結果
 "~_%20_%2B"
urldecode()すると
 "~_ _+"
rawurldecode()すると
 "~_ _+"


urlencode() + encodeAlongRFC1738()の場合
変換結果
 "~_%20_%2B"
urldecode()すると
 "~_ _+"
rawurldecode()すると
 "~_ _+"


元の配列
 array("test[0]" => "~_ _+")

http_build_query()の場合
変換結果
 "test%5B0%5D=%7E_+_%2B"
urldecode()すると
 "test[0]=~_ _+"
rawurldecode()すると(正しくデコードできない)
 "test[0]=~_+_+"

http_build_query() + encodeAlongRFC1738()の場合
変換結果

 "test%5B0%5D=~_%20_%2B"
urldecode()すると
 "test[0]=~_ _+"
rawurldecode()すると
 "test[0]=~_ _+"

urldecode()はurlencode()に対してもrawurlencode()に対しても使える。



参考:URIに使ってよい文字の話 - RFC2396 と RFC3986 - Text::Easyhacking

2009年7月12日日曜日

Pythonのメソッドのパラメータの不思議

Windows上のPython2.5のPytyon Shellで確認した。

こんなclassがあったとする。

class Test(object):
 def foo(self):
  return [self.bar(), self.bar({'buz': 10})]
 def bar(self, p={'buz': 1}):
  p['buz'] += 1
  return p

下記のように、dict型の引数pに初期値が設定されているメソッドbar()を引数無しで呼ぶと、前回呼んだ時のメソッド内の変数pの値が使われるようだ。
>>> Test().foo()
[{'buz': 2}, {'buz': 11}]
>>> Test().foo()
[{'buz': 3}, {'buz': 11}]

ちょっとびっくり。引数の型がdictの場合だけでなく、配列でも同じことが起きた。


また、classじゃなくても同じ現象になった。
def test(foo={'bar': 1}):
 foo['bar'] += 1
 return foo

>>> test()
{'bar': 2}
>>> test()
{'bar': 3}
>>> test({'bar': 10})
{'bar': 11}
>>> test()
{'bar': 4}
引数を付けた時だけ別になっている。

2008年11月14日金曜日

PHPで簡単にURLのGETパラメータを作成する方法

標準関数のhttp_build_query()を使うと、URLのGETパラメータ(クエリーストリング)を簡単に作れる。
PHP5かららしい。


$query = array('foo' => 'ABC', 'bar' => 123, 'baz' => 'あああ');
echo http_build_query($query);
結果
foo=ABC&bar=123&baz=%82%A0%82%A0%82%A0

URLエンコードもしてくれるのが便利。


HTMLエスケープもしたいなら、第3引数を'&amp;'にする。(パフォーマンスを気にしないなら、URLをまるごとhtmlSpecialChars()した方が楽だが。)


echo http_build_query(array('foo' => 'ABC', 'bar' => 123), '', '&amp;');
結果
foo=ABC&amp;bar=123


参考:PHP: http_build_query - Manual

ブログ アーカイブ

tags