这个问题有一个内在的复杂性:字符集对于每个所需的子集(大写、小写、数字和特殊)都有不同的频率,因此出现特殊字符的可能性较小,而出现字母的可能性更大。然而,即使频率被均衡化(重复特殊字符和数字,直到所有四个子集具有相同数量的字符),这也不能保证所有四个集合都至少出现一次。
下面的解决方案使用了一种不同的方法:它分别管理每个子集,并创建一个包含 10 个数字的列表来指示每个子集。这样,可以计算每个子集在列表中出现的次数,并轻松强制要求的条件。
@echo off
setlocal
set "set[1]=ABCDEFGHIJKLMNOPQRSTUVWXYZ" & set "len[1]=26" & set "num[1]=0"
set "set[2]=abcdefghijklmnopqrstuvwxyz" & set "len[2]=26" & set "num[2]=0"
set "set[3]=0123456789" & set "len[3]=10" & set "num[3]=0"
set "set[4]=~!@#$%%" & set "len[4]=6" & set "num[4]=0"
setlocal EnableDelayedExpansion
rem Create a list of 10 random numbers between 1 and 4;
rem the condition is that it must be at least one digit of each one
rem Initialize the list with 10 numbers
set "list="
for /L %%i in (1,1,10) do (
set /A rnd=!random! %% 4 + 1
set "list=!list!!rnd! "
set /A num[!rnd!]+=1
)
:checkList
rem Check that all digits appear in the list at least one time
set /A mul=num[1]*num[2]*num[3]*num[4]
if %mul% neq 0 goto listOK
rem Change elements in the list until fulfill the condition
rem Remove first element from list
set /A num[%list:~0,1%]-=1
set "list=%list:~2%"
rem Insert new element at end of list
set /A rnd=%random% %% 4 + 1
set "list=%list%%rnd% "
set /A num[%rnd%]+=1
goto checkList
:listOK
rem Generate the password with the sets indicated by the numbers in the list
set "RndAlphaNum="
for %%a in (%list%) do (
set /A rnd=!random! %% len[%%a]
for %%r in (!rnd!) do set "RndAlphaNum=!RndAlphaNum!!set[%%a]:~%%r,1!"
)
echo !RndAlphaNum!
可以轻松修改此代码,以便生成 10 个字符的密码,每个子集中具有给定数量的元素;为此,只需使用所需的数字(必须总和为 10)初始化“num”数组,每次在列表中插入新元素时递减这些数字,并更改所有元素之和为零的条件。