id 转换为字母字符串并且要求字符串要唯一,算法遇到问题,请教大家指点 相同id不同客户端取到的id字母字符串必须不同这是个什么概念?对于字母数字串如果 id 等于 1, 那么至多能映射成 36 种状态,大小写敏感时也只有 62 种状态也就是 36(62)次取值之后必然出现重复 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 回复版主,可能我没有描述清楚,相同id不同客户端取到的id字母字符串必须不同 是指,客户户端向服务器获取数据时候我们事先给他一个rule,然后我们服务器再通过 这个rule返回id字符串:$rule_1 就是客户端口请求数据时用到的 $abc_1 = toAbc($i,$rule_1); <?phpinclude_once(dirname(__FILE__) . '/../inc/include_noDB.php');set_time_limit(600000);function randAbc(){ $a = array_merge(range(0,9),range('a','z')); shuffle($a); $a = implode(',',$a); return $a;}function toAbc($num,$rule,$base=36){ $lastArr = range('a','s'); if($base == 36) { $addNum = 50000; $lastNum = substr($num,-1); } else { $addNum = 5000; $lastNum = substr($num,-2,1); if(!$lastNum) $lastNum = 0; } $num = $num+$addNum; $num = base_convert($num,10,$base); $num = str_split($num); $indexArr = array_merge(range(0,9),range('a','z')); $rule = array_combine($indexArr,explode(',',$rule)); $singleRule = array(); foreach($rule as $v) { if(count($singleRule) == 4) break; if(ord($v)<97) $singleRule[] = $v; } $str = ''; $index = 0; foreach($num as $v) { $str .= $rule[$v]; if($index<4) { $str .= $lastArr[$singleRule[$index]+$lastNum]; $index++; } } return $str;}function toNum($num,$rule,$base=36){ if($base == 36) { $addNum = 50000; } else { $addNum = 5000; } $indexArr = array_merge(range(0,9),range('a','z')); $rule = array_combine(explode(',',$rule),$indexArr); $num = str_split($num); unset($num[1]); unset($num[3]); unset($num[5]); unset($num[7]); $str = ''; foreach($num as $v) { $str .= $rule[$v]; } $str = base_convert($str,$base,10); return $str-$addNum;}$container = array();$count = 0;$rule_1 = '6,a,b,2,n,d,3,g,j,f,x,r,t,l,c,1,4,k,v,e,8,w,s,5,h,p,m,o,0,q,9,7,y,u,z,i';$rule_2 = 't,e,9,6,1,s,f,o,4,l,u,q,a,0,i,d,h,v,r,z,x,j,k,2,m,8,p,c,n,5,y,b,g,3,w,7';for($i=1;$i<100;$i++){ $n = mt_rand(1,100000); //$n = $i; $abc_1 = toAbc($n,$rule_1); $num_1 = toNum($abc_1,$rule_1); $dir_1 = toAbc($n,$rule_1,16); $dir_1_num = toNum($dir_1,$rule_1,16); $abc_2 = toAbc($n,$rule_2); $num_2 = toNum($abc_2,$rule_2); echo "{$dir_1_num}:{$dir_1}/{$abc_1}.html {$num_1}<br/>"; if(in_array($abc_2,$container)) { echo "<font color=red>{$num_1}:{$abc_1}-{$abc_2} {$num_2}</font><br/>"; $count++; } else { echo "{$num_1}:{$abc_1}-{$abc_2} {$num_2}<br/>"; } $container[] = $abc_1;}echo "<hr>";echo $count;?> 你只测试了2个$rule,还不能说明问题吧 是的,我只测试了二个rule 但我认为只要保证每个rule的唯一性,100%不会重复的,您不这要认为吗?版主? 是吗?你有 if($index<4) { $str .= $lastArr[$singleRule[$index]+$lastNum]; $index++; }就是说无论外部数据如何,你只是取了前4组那你有什么理论依据能证明不会出现重复呢? 版主,首先谢谢你的关注哦,哈哈,我的前提只有二点,我认为可以保证100%不会重复一点:保证每个rule的唯一性二点:保证每个rule的前四位和其它rule的前四位唯一性刚才把取前四位的算法改了一下,如下,也测试了一会没有发现重复的请版主指点一下,谢谢:set_time_limit(600000);function randAbc(){ $a = array_merge(range(0,9),range('a','z')); shuffle($a); $a = implode(',',$a); return $a;}function toAbc($num,$rule,$base=36){ $lastArr = range('a','s'); if($base == 36) { $addNum = 50000; $lastNum = substr($num,-1); } else { $addNum = 5000; $lastNum = substr($num,-2,1); if(!$lastNum) $lastNum = 0; } $num = $num+$addNum; $num = base_convert($num,10,$base); $num = str_split($num); $indexArr = array_merge(range(0,9),range('a','z')); $rule = array_combine($indexArr,explode(',',$rule)); $singleRule = array(); foreach($rule as $v) { if(count($singleRule) == 4) break; if(true || ord($v)<97) $singleRule[] = $v; } $str = ''; $index = 0; foreach($num as $v) { $str .= $rule[$v]; if($index<4) { //$str .= $lastArr[$singleRule[$index]+$lastNum]; $str .= $singleRule[$index]; $index++; } } return $str;}function toNum($num,$rule,$base=36){ if($base == 36) { $addNum = 50000; } else { $addNum = 5000; } $indexArr = array_merge(range(0,9),range('a','z')); $rule = array_combine(explode(',',$rule),$indexArr); $num = str_split($num); unset($num[1]); unset($num[3]); unset($num[5]); unset($num[7]); $str = ''; foreach($num as $v) { $str .= $rule[$v]; } $str = base_convert($str,$base,10); return $str-$addNum;}$container = array();$count = 0;$rule = array();for($i=1;$i<10;$i++){ $rule[] = randAbc();}$rule = array_unique($rule);for($i=1;$i<10000;$i++){ //$n = mt_rand(1,10000000); $n = $i; foreach($rule as $v) { $abc = toAbc($n,$v); $num = toNum($abc,$v); if(in_array($abc,$container)) { echo "<font color=red>{$num}:{$abc}</font><br/>"; $count++; } else { //echo "<font color=green>{$num}:{$abc}</font><br/>"; } $container[] = $abc; }}echo "<hr>";echo $count;die(); 你现在的 toAbc 返回的是 8位 36 进制数所以在 pow(36, 8) ==> 2821109907456 次后必然出现重复考虑到输入参数的不确定性,出现重复只会提前请你认真思考一下 我是这么考虑的:$dict = array_merge(range(0,9),range('a','z'));$id = 1;for($i=0; $i<10000; $i++) { $n = base_convert(sprintf('%d%04d', $id, $i), 10, 36); $t = ''; foreach(str_split($n) as $k) $t .= $dict[base_convert($k, 36, 10)]; $res[] = $t;}$t = array_count_values($res);arsort($t);print_r($t); 假定 $i 为用户唯一识别号,这段代码可以保证在 10000 个用户对同一 id 取得唯一串当然,对于不同的 id 得到的是变长的唯一串,并且存在规律性你或许可在此基础上做进一步扰码处理 按照版主的算法加了一个还原id的函数toNum(),以下函数输出可以保证1万个用户(0~99999作为用户唯一识别号),请求对同一id取得唯一串对于不同的 id 得到的是变长的唯一串,还请版主看一下toNum()函数还原写法是否正确(是否有更高效的写法),谢谢function randAbc(){ $rule = array_merge(range(0,9),range('a','z')); shuffle($rule); return implode('',$rule);}function toAbc($id,$userId,$rule)//转换为字符{ /* $id = 数据id号 $userId = 用户唯一识别号 $rule = 36进制排序规则 */ $rule = str_split($rule); $n = base_convert(sprintf('%d%04d',$id,$userId),10,36); $t = ''; foreach(str_split($n) as $k) $t .= $rule[base_convert($k,36,10)]; return $t;}function toNum($abc,$rule)//还原id{ $rule = array_flip(str_split($rule)); $t = ''; foreach(str_split($abc) as $k) $t .= base_convert($rule[$k],10,36); return substr(base_convert($t,36,10),0,-4);}$rule = randAbc();for($id=1;$id<=1;$id++){ for($userId=0;$userId<100;$userId++) { $t = toAbc($id,$userId,$rule); echo $t. "<br>"; $res[] = $t; }}$t = array_count_values($res);arsort($t);$t = current($t);echo $t; php根据日期换背景的问题 php页面出现中文乱码情况,请解决方式 php网页上显示这个Warning是什么意思? 请教如何学习PHP 如何不重启MYSQL就可以修改MYSQL的变量? PHP定时执行任务 关于insert的问题 MYSQL插入数据问题,高手帮我看一眼啊 php做的大型网站一般是用的什么数据库,比如 易趣网 应该是个HTML语法问题,怎么我指定了<td>的宽度,然而过长的字符串还是会把表格撑开?怎么在单元格里自动折行呢? FastCGI Error时不时出现,一会又好了,一会又打不开,哪里出了问题啊 用REMOTE_ADDR获取的IP有可能是被伪造的吗?
然后我们服务器再通过 这个rule返回id字符串:
$rule_1 就是客户端口请求数据时用到的 $abc_1 = toAbc($i,$rule_1);
<?php
include_once(dirname(__FILE__) . '/../inc/include_noDB.php');
set_time_limit(600000);
function randAbc()
{
$a = array_merge(range(0,9),range('a','z'));
shuffle($a);
$a = implode(',',$a);
return $a;
}
function toAbc($num,$rule,$base=36)
{
$lastArr = range('a','s');
if($base == 36)
{
$addNum = 50000;
$lastNum = substr($num,-1);
}
else
{
$addNum = 5000;
$lastNum = substr($num,-2,1);
if(!$lastNum) $lastNum = 0;
}
$num = $num+$addNum;
$num = base_convert($num,10,$base);
$num = str_split($num);
$indexArr = array_merge(range(0,9),range('a','z'));
$rule = array_combine($indexArr,explode(',',$rule));
$singleRule = array();
foreach($rule as $v)
{
if(count($singleRule) == 4) break;
if(ord($v)<97) $singleRule[] = $v;
}
$str = '';
$index = 0;
foreach($num as $v)
{
$str .= $rule[$v];
if($index<4)
{
$str .= $lastArr[$singleRule[$index]+$lastNum];
$index++;
}
}
return $str;
}
function toNum($num,$rule,$base=36)
{
if($base == 36)
{
$addNum = 50000;
}
else
{
$addNum = 5000;
}
$indexArr = array_merge(range(0,9),range('a','z'));
$rule = array_combine(explode(',',$rule),$indexArr);
$num = str_split($num);
unset($num[1]);
unset($num[3]);
unset($num[5]);
unset($num[7]);
$str = '';
foreach($num as $v)
{
$str .= $rule[$v];
}
$str = base_convert($str,$base,10);
return $str-$addNum;
}$container = array();
$count = 0;
$rule_1 = '6,a,b,2,n,d,3,g,j,f,x,r,t,l,c,1,4,k,v,e,8,w,s,5,h,p,m,o,0,q,9,7,y,u,z,i';
$rule_2 = 't,e,9,6,1,s,f,o,4,l,u,q,a,0,i,d,h,v,r,z,x,j,k,2,m,8,p,c,n,5,y,b,g,3,w,7';
for($i=1;$i<100;$i++)
{
$n = mt_rand(1,100000);
//$n = $i;
$abc_1 = toAbc($n,$rule_1);
$num_1 = toNum($abc_1,$rule_1);
$dir_1 = toAbc($n,$rule_1,16);
$dir_1_num = toNum($dir_1,$rule_1,16);
$abc_2 = toAbc($n,$rule_2);
$num_2 = toNum($abc_2,$rule_2);
echo "{$dir_1_num}:{$dir_1}/{$abc_1}.html {$num_1}<br/>";
if(in_array($abc_2,$container))
{
echo "<font color=red>{$num_1}:{$abc_1}-{$abc_2} {$num_2}</font><br/>";
$count++;
}
else
{
echo "{$num_1}:{$abc_1}-{$abc_2} {$num_2}<br/>";
}
$container[] = $abc_1;
}
echo "<hr>";
echo $count;?>
是的,我只测试了二个rule 但我认为只要保证每个rule的唯一性,100%不会重复的,您不这要认为吗?版主?
你有
if($index<4)
{
$str .= $lastArr[$singleRule[$index]+$lastNum];
$index++;
}
就是说无论外部数据如何,你只是取了前4组
那你有什么理论依据能证明不会出现重复呢?
一点:保证每个rule的唯一性
二点:保证每个rule的前四位和其它rule的前四位唯一性
刚才把取前四位的算法改了一下,如下,也测试了一会没有发现重复的
请版主指点一下,谢谢:
set_time_limit(600000);
function randAbc()
{
$a = array_merge(range(0,9),range('a','z'));
shuffle($a);
$a = implode(',',$a);
return $a;
}
function toAbc($num,$rule,$base=36)
{
$lastArr = range('a','s');
if($base == 36)
{
$addNum = 50000;
$lastNum = substr($num,-1);
}
else
{
$addNum = 5000;
$lastNum = substr($num,-2,1);
if(!$lastNum) $lastNum = 0;
}
$num = $num+$addNum;
$num = base_convert($num,10,$base);
$num = str_split($num);
$indexArr = array_merge(range(0,9),range('a','z'));
$rule = array_combine($indexArr,explode(',',$rule));
$singleRule = array();
foreach($rule as $v)
{
if(count($singleRule) == 4) break;
if(true || ord($v)<97) $singleRule[] = $v;
}
$str = '';
$index = 0;
foreach($num as $v)
{
$str .= $rule[$v];
if($index<4)
{
//$str .= $lastArr[$singleRule[$index]+$lastNum];
$str .= $singleRule[$index];
$index++;
}
}
return $str;
}
function toNum($num,$rule,$base=36)
{
if($base == 36)
{
$addNum = 50000;
}
else
{
$addNum = 5000;
}
$indexArr = array_merge(range(0,9),range('a','z'));
$rule = array_combine(explode(',',$rule),$indexArr);
$num = str_split($num);
unset($num[1]);
unset($num[3]);
unset($num[5]);
unset($num[7]);
$str = '';
foreach($num as $v)
{
$str .= $rule[$v];
}
$str = base_convert($str,$base,10);
return $str-$addNum;
}$container = array();
$count = 0;
$rule = array();
for($i=1;$i<10;$i++)
{
$rule[] = randAbc();
}
$rule = array_unique($rule);
for($i=1;$i<10000;$i++)
{
//$n = mt_rand(1,10000000);
$n = $i;
foreach($rule as $v)
{
$abc = toAbc($n,$v);
$num = toNum($abc,$v);
if(in_array($abc,$container))
{
echo "<font color=red>{$num}:{$abc}</font><br/>";
$count++;
}
else
{
//echo "<font color=green>{$num}:{$abc}</font><br/>";
}
$container[] = $abc;
}
}
echo "<hr>";
echo $count;
die();
所以在 pow(36, 8) ==> 2821109907456 次后必然出现重复
考虑到输入参数的不确定性,出现重复只会提前请你认真思考一下
$dict = array_merge(range(0,9),range('a','z'));
$id = 1;for($i=0; $i<10000; $i++) {
$n = base_convert(sprintf('%d%04d', $id, $i), 10, 36);
$t = '';
foreach(str_split($n) as $k) $t .= $dict[base_convert($k, 36, 10)];
$res[] = $t;
}
$t = array_count_values($res);
arsort($t);
print_r($t); 假定 $i 为用户唯一识别号,这段代码可以保证在 10000 个用户对同一 id 取得唯一串
当然,对于不同的 id 得到的是变长的唯一串,并且存在规律性
你或许可在此基础上做进一步扰码处理
对于不同的 id 得到的是变长的唯一串,还请版主看一下toNum()函数还原写法是否正确(是否有更高效的写法),谢谢function randAbc()
{
$rule = array_merge(range(0,9),range('a','z'));
shuffle($rule);
return implode('',$rule);
}
function toAbc($id,$userId,$rule)//转换为字符
{
/*
$id = 数据id号
$userId = 用户唯一识别号
$rule = 36进制排序规则
*/
$rule = str_split($rule);
$n = base_convert(sprintf('%d%04d',$id,$userId),10,36);
$t = '';
foreach(str_split($n) as $k) $t .= $rule[base_convert($k,36,10)];
return $t;
}
function toNum($abc,$rule)//还原id
{
$rule = array_flip(str_split($rule));
$t = '';
foreach(str_split($abc) as $k) $t .= base_convert($rule[$k],10,36);
return substr(base_convert($t,36,10),0,-4);
}
$rule = randAbc();
for($id=1;$id<=1;$id++)
{
for($userId=0;$userId<100;$userId++)
{
$t = toAbc($id,$userId,$rule);
echo $t. "<br>";
$res[] = $t;
}
}
$t = array_count_values($res);
arsort($t);
$t = current($t);
echo $t;