PHP MySQL REGEXPでの人名検索のための文字列変換
高崎
や髙﨑
を検索する際に高
と髙
また崎
と﨑
を意識しなくても良いようMySQL REGEXP検索できるよう変換。
どちらのタカサキでもSELECT * FROM users WHERE user_nm REGEXP '[高|髙][崎|﨑]'
となるようにする。
という処理を書いた後、ふと自分の変換処理の書き方が良いコードなのか疑問に思ったため速度を調べた。
入力文字列
浜曻﨑髙熙曻德䑓壱二
出力文字列
[濱|濵|浜][曻|昇][﨑|崎][髙|高][煕|熙][曻|昇][德|徳][䑓|台][1|1|一|壱][2|2|二|弐]
文字のグループ化
<?php function convert_regexp_search($func, $str) { $str = $func(array('濱', '濵', '浜'), $str); $str = $func(array('﨑', '崎'), $str); $str = $func(array('髙', '高'), $str); $str = $func(array('煕', '熙'), $str); $str = $func(array('曻', '昇'), $str); $str = $func(array('德', '徳'), $str); $str = $func(array('䑓', '台'), $str); $str = $func(array('1', '1', '一', '壱'), $str); $str = $func(array('2', '2', '二', '弐'), $str); $str = $func(array('3', '3', '三', '参'), $str); // 続く return $str; }
変換処理候補1 mb_substrで一文字毎に処理
<?php $funcA = function ($group, $str, $encoding = "UTF-8") { $r = array(); $to = '['.implode('|', $group).']'; $keys = array_flip($group); $cnt = mb_strlen($str, $encoding); for($i = 0; $i < $cnt; $i++) { $s = mb_substr($str, $i, 1, $encoding); if (array_key_exists($s, $keys)){ $r[] = $to; } else { $r[] = $s; } } return implode('', $r); };
変換処理候補2 preg_splitで一文字毎に分解
<?php $funcB = function ($group, $str) { $r = array(); $to = '['.implode('|', $group).']'; $keys = array_flip($group); $arr = array_slice(preg_split("//u", $str), 1, -1); foreach ($arr as $s) { if (array_key_exists($s, $keys)){ $r[] = $to; } else { $r[] = $s; } } return implode('', $r); };
変換処理候補3 str_replaceで一度別の文字にして変換
<?php $funcC = function ($group, $str, $tmp = "\t") { $to = '['.implode('|', $group).']'; $str = str_replace($group, $tmp, $str); $str = str_replace($tmp, $to, $str); return $str; };
1万回ループでの速度計測
<?php $functions = array('A'=>$funcA, 'B'=>$funcB, 'C'=>$funcC); foreach ($functions as $key => $func) { $start = microtime(true); for ($i = 0; $i < 10000; $i++ ) { convert_regexp_search($func, $str); } $time = microtime(true) - $start; echo "{$key}: {$time} 秒\n"; }
計測結果
A: 1.9553890228271 秒
B: 0.86666202545166 秒
C: 0.068694114685059 秒
一言
当然の結果であった。