/** * 検索文字列を正規化してメンバ変数に格納する * @param string $address * @return void */ protected function parse($address) { //全角数字を半角に。全角スペースを半角に。 $address = mb_convert_kana($address, 'ns'); //半角スペースを削除 $address = str_replace(' ', '', $address); //県を特定し、検索文字列から県を除外 foreach (Dm_Geocoder_Prefecture::get() as $code => $name) { $splited = preg_split('/' . $name . '/', $address); if (count($splited) <= 1) { continue; } $this->prefectureCode = $code; $this->prefectureName = $name; $address = $name . $splited[1]; break; } //住所中の数値を漢数字に変換する $address = preg_replace_callback('/[0-9]+/msu', create_function('$mt', 'return Dm_Geocoder_Query::num2kan_decimal($mt[0]);'), $address); //都道府県名以降の住所 $this->address = $address; }
/** * csvを検索文字列で検索し、検索結果としてマッチする候補を複数返す * * 検索速度を速くするため、少し処理が複雑になっています * 都道府県、市区町村、大字町丁目名と、段階的に検索をかけていきます。 * * @param Dm_Geocoder_Query * @return Dm_Geocoder_Address[] */ public static function find(Dm_Geocoder_Query $query) { // 都道府県を特定できていれば絞り込む if ($query->prefectureCode) { //入力された権のみを検索対象とする $prefectureCodes = array($query->prefectureCode); //検索文字列の頭に県名がついていれば削除する $needle = mb_substr($query->address, mb_strlen($query->prefectureName)); //県名のみの検索の場合は該当県のAddressを全件返して終了 if (strlen($needle) === 0) { return Dm_Geocoder_GISCSV_Reader::readAll($query->prefectureCode); } } else { //全件を検索対象とする $prefectureCodes = array_keys(Dm_Geocoder_Prefecture::get()); //検索対象文字列 $needle = $query->address; } $finded = array(); foreach ($prefectureCodes as $prefectureCode) { //CSVを読み込む $giscsv = new Dm_Geocoder_GISCSV($prefectureCode); $buf = $giscsv->read(); //都道府県名以降の文字列を市区町村名とマッチングして //1文字ずつCSVから正規表現で検索する $findedInPref = array(); $code = '\\"\\d+\\"'; $l = mb_strlen($needle); for ($i = 1; $i <= $l; $i++) { $mun = mb_substr($needle, 0, $i); $mun = preg_quote($mun); $mun = '\\"' . $mun; $pattern = '/^' . $code . ',\\"[^\\"]+\\",' . $code . ',' . $mun . '.+$/m'; preg_match_all($pattern, $buf, $match); //1件も一致しなければ終了 if (count($match[0]) === 0) { break; } //1件でも一致していれば保持する。これまでのものは破棄する。 $findedInPref = array(); foreach ($match[0] as $key => $row) { $address = new Dm_Geocoder_Address(); $findedInPref[] = $address->importCsv($row); } } $finded = array_merge($finded, $findedInPref); } //これまでに検索した行は市区町村レベルのマッチングだったので //今度は大字町丁目名までを使って1行1行マッチングする $addressMatchedMost = array(); $addressMatchedMostLength = 0; foreach ($finded as $key => $row) { //市区町村と大字町丁目名で検索する $matchesLength = self::forwardMatchesLength($row->municipalityName . $row->localName, $needle); if ($matchesLength === 0) { continue; } if ($matchesLength > $addressMatchedMostLength) { $addressMatchedMostLength = $matchesLength; $addressMatchedMost = array($row); } else { if ($matchesLength === $addressMatchedMostLength) { $addressMatchedMost[] = $row; } } } return $addressMatchedMost; }
/** * _debugPrefLocation * * 県に所属する大字町丁目の緯度経度の最小と最大をechoします。 * デバッグ用メソッドです。 * * @return void */ public static function _debugPrefLocation() { $prefectures = array_keys(Dm_Geocoder_Prefecture::get()); $prefectureLocation = array(); foreach ($prefectures as $prefecture) { $reader = new Dm_Geocoder_GISCSV_Reader($prefecture); foreach ($reader as $key => $row) { if (!isset($prefectureLocation[$prefecture])) { $prefectureLocation[$prefecture] = array('minLat' => $row->lat, 'maxLat' => $row->lat, 'minLng' => $row->lng, 'maxLng' => $row->lng); } else { if ($row->lat < $prefectureLocation[$prefecture]['minLat']) { $prefectureLocation[$prefecture]['minLat'] = $row->lat; } if ($row->lat > $prefectureLocation[$prefecture]['maxLat']) { $prefectureLocation[$prefecture]['maxLat'] = $row->lat; } if ($row->lng < $prefectureLocation[$prefecture]['minLng']) { $prefectureLocation[$prefecture]['minLng'] = $row->lng; } if ($row->lng > $prefectureLocation[$prefecture]['maxLng']) { $prefectureLocation[$prefecture]['maxLng'] = $row->lng; } } } } $varExport = var_export($prefectureLocation, true); echo str_replace(' ', "\t", $varExport); echo "\n"; }