LoginSignup
1
0

More than 3 years have passed since last update.

【PHP】"mb_range()"(マルチバイト対応版 "range")〜 MD5 ハッシュ値を 10 桁に圧縮する 〜

Last updated at Posted at 2017-07-19

PHP のrange 関数の範囲を平仮名・カタカナ・漢字にまで対応させたい。

つまり range のマルチバイト版 mb_range 関数が欲しい。こんなの↓

$a = mb_range( 'あ', 'お' );
print_r( $a );
出力結果
Array
(
    [0] => 
    [1] => 
    [2] => 
    [3] => 
    [4] => 
    [5] => 
    [6] => 
    [7] => 
    [8] => 
)
  • 「こんなの何に使うの?」という方は TL; DR 参照

TS; DR(マルチバイト対応版range()

UTF-8 の文字コード表の順になりますが、平仮名だけでなく漢字も範囲対象にして一気に得ることができます

mb_range()
<?php
/**
 * range('A', 'Z') のマルチバイト対応版
 *
 * @author Rodney Rehm (https://gist.github.com/rodneyrehm/1306118)
 * @url    Latest code https://qiita.com/KEINOS/items/f0aa3cf476455390d95f
 *
 * @param  string $start 開始文字
 * @param  string $end   終了文字
 * @return array         開始から終了までの文字の配列
 */
function mb_range($start, $end)
{
    // $start と $end が同じ場合は何もしない
    if ($start == $end) {
        return array($start);
    }

    $_result = array();

    // $start と $end のユニコードを取得
    list(, $_start, $_end) = unpack("N*", mb_convert_encoding($start . $end, "UTF-32BE", "UTF-8"));

    // 処理方向を検知する
    $_offset  = $_start < $_end ? 1 : -1;
    $_current = $_start;

    // BOM なし UTF-32
    while ($_current != $_end) {
        $_result[] = mb_convert_encoding(pack("N*", $_current), "UTF-8", "UTF-32BE");
        $_current += $_offset;
    }
    $_result[] = $end;

    return $_result;
}

TS; DR(mb_range の使いみち)

range 関数、mb_range ユーザ関数とは

PHP の range 関数はrange(1,9);[1,2,...,9]と、指定した範囲の整数の配列を作成してくれます。また、数値だけでなく range('A','Z'); -> ['A','B',...,'Z'] のように ASCII コード表の範囲も取得できます

mb_range ユーザー関数は、この range()マルチバイト対応させて「mb_range( 'あ', 'ん' )」などとして UTF-8 の文字コード表内の指定範囲を配列で得たい人のためのユーザー関数です。

何に使うの?

何に使うのか。ご覧の通り「あ,い,う,え,お」と並ばないため余り用途はないかもしれません。「あ,い,う,え,お」と並ばせたい場合は preg_match などを利用した方が賢いかもしれません。

mb_range() の使いみちの1つとしては、文字列の長さの圧縮に使えます。つまり文字列を短くできるということです。(データの圧縮ではありませんので注意)

アルファベットが足りないなら漢字を使えばいいじゃない

0-9 は 10 文字で 10 進数を表現します。16 進数の場合は 0-9 a-f の 16 文字です。同様に 0-9 a-z A-Z + / の 64 文字(62文字+記号2文字)を使えば 64 進数になります。「進数」ということは1桁で、その文字数ぶんを表現できるということです。逆に言えば ASCII の場合は可視化できる範囲は !~ までの 92 文字です。

しかし、時代は UTF-8 標準。そう、漢字まで使っちゃえば、数値の桁数をより短くできるということです。

数値といえば、「長ければ長いほど良いが、できれば短くしたい」の代表がハッシュ関数によるハッシュ値の長さです。しかし、大量の文字列を配列に入れるのが面倒だったので range 関数のマルチバイト版を探していたら GitHub の gist で公開されていた方いらしたたので利用させていただきました。

MD5の値を10桁に圧縮する
<?php

require('mb_base_encode.php');
require('mb_range.php');

// Input string
$string = 'This is a sample string to be hashed.';

// Output
echo 'Original String: ', $string, PHP_EOL;
echo 'MD5 hash raw   : ', hash('md5', $string), PHP_EOL;
echo 'MD5 hash short : ', mb_base_encode(hexdec(hash('md5', $string)));
出力結果
Original String: This is a sample string to be hashed.
MD5 hash raw   : baad33e1e97f316b9750c27c86bf64d6
MD5 hash short : 䙔倁屩劷䋾彨䏔䂌䤘剒
mb_base_encode.php
<?php

/**
 * Returns base Nth encoded string from decimal number input.
 *
 * @param  integer $number Decimal number to encode
 * @return string          Encoded string
 */
function mb_base_encode(integer $number): string
{
    $char = array_merge(
        mb_range('䀀', '䶵'), // U+4000 - U+4DB5
        mb_range('一', '俿'), // U+4E00 - U+4FFF
        mb_range('倀', '忿') //  U+5000 - U+5FFF
        // REF: http://www.utf8-chartable.com/unicode-utf8-table.pl?start=16384&number=1024
    );

    $base   = count($char);
    $result = "";
    while ($number > 0) {
        $result = $char[ fmod($number, $base) ] . $result;
        $number = floor($number / $base);
    }

    return ( $result == "" ) ? 0 : $result;
}
mb_range.php
<?php

function mb_range(string $start, string $end): array
{
    // if start and end are the same, well, there's nothing to do
    if ($start == $end) {
        return array($start);
    }

    $_result = array();
    // get unicodes of start and end
    list(, $_start, $_end) = unpack("N*", mb_convert_encoding($start . $end, "UTF-32BE", "UTF-8"));
    // determine movement direction
    $_offset = $_start < $_end ? 1 : -1;
    $_current = $_start;
    while ($_current != $_end) {
        $_result[] = mb_convert_encoding(pack("N*", $_current), "UTF-8", "UTF-32BE");
        $_current += $_offset;
    }
    $_result[] = $end;
    return $_result;
}
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0