话说这个PHP脚本我已经写过好多次了,不过由于国家统计局提供的数据格式有些许的变化,所以我又重写了一遍,问题既涉及到PHP,同时也涉及到MySQL,感觉很适合做面试题,这类问题往往最能反映出求职者的基本素质。
准备工作:需要下载最新县及县以上行政区划代码,并保存成data.txt文件,事先需要提醒的是,如果你在拷贝粘贴的过程中出现格式错乱的问题,可以试着先把拷贝的内容粘贴到Word,WPS等软件中,然后再重新拷贝粘贴到文本文件中,通常就可以了。
说明:不同版本的数据,可能会出现全角空格和半角空格混杂的情况。
首先创建MySQL表:
需要注意的是表的字符集和文件的字符集需要一致。
CREATE TABLE IF NOT EXISTS `places` ( `id` int(10) unsigned NOT NULL, `parent_id` int(10) unsigned NOT NULL, `name` varchar(20) NOT NULL, PRIMARY KEY (`id`), KEY `parent_id` (`parent_id`) ) ENGINE=InnoDB;
补充:更好的存储层次化的数据:Storing Hierarchical Data in a Database Article。
然后编写PHP脚本:
需要注意的是自己保证data.txt文件内容的合法性,代码本身未做严禁的校验。
<?php // config $host = ''; $dbname = ''; $charset = ''; $username = ''; $password = ''; set_time_limit(0); $dsn = "mysql:host={$host};dbname={$dbname};charset={$charset}"; $options = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, ); $dbh = new PDO($dsn, $username, $password, $options); $sth = $dbh->prepare(' REPLACE INTO places (id, parent_id, name) VALUES (:id, :parent_id, :name) '); $parent = array(0); $handle = fopen('data.txt', 'r'); while (!feof($handle)) { $row = trim(str_replace(' ', ' ', fgets($handle))); if (!preg_match('/^(\d+)\s+(.+)$/', $row, $matches)) { continue; } list($row, $id, $name) = $matches; $level = strlen(preg_replace('/(00){1,2}$/', '', $id)) / 2; $parent_id = $parent[$level - 1] ?? $parent[$level - 2]; $parent[$level] = $id; $sth->bindValue(':id', $id, PDO::PARAM_INT); $sth->bindValue(':parent_id', $parent_id, PDO::PARAM_INT); $sth->bindValue(':name', $name); $sth->execute(); } fclose($handle); ?>
说明:通过引入level变量可以消除程序里令人讨厌的「if/else」语句。
……
有了行政区划代码,再配上民间的IP数据库,就更完美了。本文处理的是县级行政区划代码的处理,如果你需要乡级的数据,同样可以参考国家统计局。
更新:最新的行政区划代码地址改变了。
这代码漂亮!
请问大牛在哪里工作呀??
这个版本还没有“三沙市”
I know chinese id card forward six position is this code ,right?
$level直接从$id结构得到,不用判断空格更多还是更少。不过还是赞一下这个判断空格缩进的代码。
太技巧了吧。
我会这样写
$handle = fopen(‘data.txt’, ‘r’);
while (!feof($handle)) {
$row = trim(fgets($handle));
//删除所有空格
//前6位就是ID
//2-6位为0000,则parent_id=0
//5-6为00,则parent_id=前2位+0000
//否则,parent_id=前4位+00
}
似乎没有技巧的代码会是更好的代码。
private function getParentId($id){
$id = (int)$id;
if(($id % 10000) == 0){
$parent_id = 0;
}else if(($id % 100) == 0){
$parent_id = floor($id/10000)*10000;
}else{
$parent_id = floor($id/100)*100;
}
return $parent_id;
}
我的写法,可能效率差点吧
正如大家所说,原始代码有炫技的嫌疑,所以我重写了PHP代码。
Pingback引用通告: 使用PHP解析行政区划代码 | 网络手抄本
Pingback引用通告: 简易云端Hosts的构建 | 火丁笔记