PHP生成8位全排列并逐次处理(规避内存溢出问题)
问题描述
我有一组字符集:
0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
希望生成所有8位格式的密钥:
00000000 00000001 00000002 ... zzzzzzzy zzzzzzzz
但已找到的方案都会因分配数组导致PHP内存溢出,因此希望通过循环实现(每次生成一个排列,处理后再生成下一个):
// LOOPS // generate 1 permutation // do something // END LOOP
请问有什么实现思路?
实现方案
直接用进制转换法或者多层嵌套循环就能解决,前者代码简洁易扩展,后者直观易懂,以下是具体实现:
方案1:进制转换法(推荐)
把给定的36个字符看成是一套36进制的“数字”,从0循环到36^8 - 1,将每个十进制数转换成36进制后,用字符集映射替换,最后补前导零到8位。这种方式每次只生成一个密钥,完全不会占用大量内存。
代码示例
// 定义字符集 $chars = '0123456789abcdefghijklmnopqrstuvwxyz'; $charTotal = strlen($chars); $keyLength = 8; // 计算总共有多少种组合 $maxCount = pow($charTotal, $keyLength); for ($i = 0; $i < $maxCount; $i++) { $num = $i; $key = ''; // 将十进制数转换为自定义36进制 for ($j = 0; $j < $keyLength; $j++) { $remainder = $num % $charTotal; $key = $chars[$remainder] . $key; $num = floor($num / $charTotal); } // 补前导零,确保密钥是8位 $key = str_pad($key, $keyLength, '0', STR_PAD_LEFT); // 这里写你处理密钥的逻辑,比如输出、写入文件等 echo $key . PHP_EOL; }
方案2:多层嵌套循环
如果觉得进制转换不好理解,也可以直接写8层嵌套循环,每一层对应密钥的一位,遍历字符集的所有字符。这种方法逻辑直观,但扩展性差——如果要修改密钥长度,就得手动调整循环层数。
代码示例
$chars = str_split('0123456789abcdefghijklmnopqrstuvwxyz'); $charCount = count($chars); // 8层循环对应8位密钥的每一位 for ($a = 0; $a < $charCount; $a++) { for ($b = 0; $b < $charCount; $b++) { for ($c = 0; $c < $charCount; $c++) { for ($d = 0; $d < $charCount; $d++) { for ($e = 0; $e < $charCount; $e++) { for ($f = 0; $f < $charCount; $f++) { for ($g = 0; $g < $charCount; $g++) { for ($h = 0; $h < $charCount; $h++) { $key = $chars[$a] . $chars[$b] . $chars[$c] . $chars[$d] . $chars[$e] . $chars[$f] . $chars[$g] . $chars[$h]; // 处理密钥的逻辑 echo $key . PHP_EOL; } } } } } } } }
实用提示
- 36^8等于2821109907456,也就是超过2.8万亿次循环,实际运行会极慢,建议根据需求添加终止条件,或者分批处理(比如每生成100万条就写入文件并短暂休眠)。
- 如果需要写入文件,不要每次循环都调用
file_put_contents,建议提前用fopen打开文件句柄,每次循环用fwrite写入,最后关闭句柄,能大幅提升效率。
内容的提问来源于stack exchange,提问作者pacionet
相关产品推荐
相关产品推荐

