Windows批处理:49个文件的可逆全范围随机重排方案问询
解决方案
核心思路
采用线性同余伪随机数生成器(LCG),以输入的9/10位数字密钥为种子,生成可复现的全范围排列,同时严格满足所有约束:
- 密钥唯一决定排列逻辑,保证重排与还原的一致性;
- 生成排列时自动过滤不动点(原始序号=目标序号);
- 检查原始相邻文件的新序号是否不相邻;
- 基于全49个元素的随机选择,实现跨范围重排。
重排脚本(shuffle.bat)
@echo off setlocal enabledelayedexpansion :: 检查密钥输入合法性 if "%~1"=="" ( echo 请输入9或10位数字作为密钥 exit /b 1 ) set "key=%~1" echo %key% | findstr /r "^[0-9]\{9,10\}$" >nul if errorlevel 1 ( echo 密钥必须是9或10位数字 exit /b 1 ) :: 将密钥转换为LCG种子(取前9位) set "seed=%key:~0,9%" set /a seed=seed :: LCG参数(保证周期覆盖49个元素的所有排列) set "a=1664525" set "c=1013904223" set "m=4294967296" :: 构建原始序号列表(001-049) set "orig_list=" for /l %%i in (1,1,49) do ( set "num=00%%i" set "num=!num:~-3!" set "orig_list=!orig_list! !num!" ) set "orig_list=!orig_list:~1!" :: 生成符合要求的排列 :generate_perm set "used=" set "perm_list=" set "valid=1" :: 第一步:生成无不动点的排列 for /l %%i in (1,1,49) do ( set "orig_num=00%%i" set "orig_num=!orig_num:~-3!" :find_next :: 生成下一个伪随机数 set /a seed=(a*seed + c) %% m set /a rand=seed %% 49 + 1 set "rand_num=00!rand!" set "rand_num=!rand_num:~-3!" :: 跳过已使用的序号和原始序号(避免不动点) if "!used:!rand_num!=!"=="" if "!rand_num!" neq "!orig_num!" ( set "used=!used! !rand_num!" set "perm_list=!perm_list! !rand_num!" ) else ( goto find_next ) ) :: 第二步:检查原始相邻文件的新序号是否不相邻 for /l %%i in (1,1,48) do ( set "orig_i=00%%i" set "orig_i=!orig_i:~-3!" set "orig_j=00%%i+1" set "orig_j=!orig_j:~-3!" :: 获取两个原始序号对应的新序号 set "new_i=" set "new_j=" set "pos=0" for %%o in (!orig_list!) do ( set /a pos+=1 if "%%o" equ "!orig_i!" ( set "p_pos=!pos!" for %%p in (!perm_list!) do ( if !p_pos! equ 1 ( set "new_i=%%p" goto get_new_i_done ) set /a p_pos-=1 ) ) :get_new_i_done ) set "pos=0" for %%o in (!orig_list!) do ( set /a pos+=1 if "%%o" equ "!orig_j!" ( set "p_pos=!pos!" for %%p in (!perm_list!) do ( if !p_pos! equ 1 ( set "new_j=%%p" goto get_new_j_done ) set /a p_pos-=1 ) ) :get_new_j_done ) :: 检查新序号是否相邻 set /a new_i_num=new_i, new_j_num=new_j set /a diff=new_i_num - new_j_num if !diff! equ 1 if !diff! equ -1 ( set "valid=0" goto reset_perm ) ) :: 排列有效,进入重命名步骤 if !valid! equ 1 goto perm_ok :reset_perm :: 重置种子,重新生成排列 set "seed=%key:~0,9%" set /a seed=seed goto generate_perm :perm_ok :: 临时重命名避免冲突 echo 临时重命名文件... for /l %%i in (1,1,49) do ( set "orig_num=00%%i" set "orig_num=!orig_num:~-3!" ren "testfile.exe.!orig_num!" "testfile.exe.tmp.!orig_num!" ) :: 执行最终重排 echo 执行重排... set "pos=0" for %%o in (!orig_list!) do ( set /a pos+=1 set "p_pos=!pos!" for %%p in (!perm_list!) do ( if !p_pos! equ 1 ( ren "testfile.exe.tmp.%%o" "testfile.exe.%%p" goto next_file ) set /a p_pos-=1 ) :next_file ) echo 重排完成! exit /b 0
还原脚本(restore.bat)
@echo off setlocal enabledelayedexpansion :: 检查密钥输入合法性 if "%~1"=="" ( echo 请输入9或10位数字作为密钥 exit /b 1 ) set "key=%~1" echo %key% | findstr /r "^[0-9]\{9,10\}$" >nul if errorlevel 1 ( echo 密钥必须是9或10位数字 exit /b 1 ) :: 生成与重排脚本完全一致的排列 set "seed=%key:~0,9%" set /a seed=seed set "a=1664525" set "c=1013904223" set "m=4294967296" set "orig_list=" for /l %%i in (1,1,49) do ( set "num=00%%i" set "num=!num:~-3!" set "orig_list=!orig_list! !num!" ) set "orig_list=!orig_list:~1!" :generate_perm set "used=" set "perm_list=" set "valid=1" for /l %%i in (1,1,49) do ( set "orig_num=00%%i" set "orig_num=!orig_num:~-3!" :find_next set /a seed=(a*seed + c) %% m set /a rand=seed %% 49 + 1 set "rand_num=00!rand!" set "rand_num=!rand_num:~-3!" if "!used:!rand_num!=!"=="" if "!rand_num!" neq "!orig_num!" ( set "used=!used! !rand_num!" set "perm_list=!perm_list! !rand_num!" ) else ( goto find_next ) ) :: 检查排列有效性(和重排脚本一致,确保生成相同序列) for /l %%i in (1,1,48) do ( set "orig_i=00%%i" set "orig_i=!orig_i:~-3!" set "orig_j=00%%i+1" set "orig_j=!orig_j:~-3!" set "new_i=" set "new_j=" set "pos=0" for %%o in (!orig_list!) do ( set /a pos+=1 if "%%o" equ "!orig_i!" ( set "p_pos=!pos!" for %%p in (!perm_list!) do ( if !p_pos! equ 1 ( set "new_i=%%p" goto get_new_i_done ) set /a p_pos-=1 ) ) :get_new_i_done ) set "pos=0" for %%o in (!orig_list!) do ( set /a pos+=1 if "%%o" equ "!orig_j!" ( set "p_pos=!pos!" for %%p in (!perm_list!) do ( if !p_pos! equ 1 ( set "new_j=%%p" goto get_new_j_done ) set /a p_pos-=1 ) ) :get_new_j_done ) set /a new_i_num=new_i, new_j_num=new_j set /a diff=new_i_num - new_j_num if !diff! equ 1 if !diff! equ -1 ( set "valid=0" goto reset_perm ) ) if !valid! equ 1 goto perm_ok :reset_perm set "seed=%key:~0,9%" set /a seed=seed goto generate_perm :perm_ok :: 临时重命名避免冲突 echo 临时重命名文件... for /l %%i in (1,1,49) do ( set "orig_num=00%%i" set "orig_num=!orig_num:~-3!" ren "testfile.exe.!orig_num!" "testfile.exe.tmp.!orig_num!" ) :: 反向映射还原原始命名 echo 执行还原... set "pos=0" for %%p in (!perm_list!) do ( set /a pos+=1 set "o_pos=!pos!" for %%o in (!orig_list!) do ( if !o_pos! equ 1 ( ren "testfile.exe.tmp.%%p" "testfile.exe.%%o" goto next_restore_file ) set /a o_pos-=1 ) :next_restore_file ) echo 还原完成! exit /b 0
关键优化说明
- 可复现排列:LCG算法以密钥为种子,确保相同密钥生成完全一致的排列,支持精准还原;
- 全范围重排:直接从49个元素中随机选择目标序号,彻底打破原有的小范围限制;
- 约束满足:
- 自动过滤不动点,确保所有文件序号都被修改;
- 额外检查原始相邻文件的新序号是否不相邻;
- 冲突避免:先将所有文件临时重命名为
.tmp后缀,再执行最终重命名,解决交叉重命名的冲突问题。
使用方法
- 重排:在命令行执行
shuffle.bat 123456789(替换为你的9/10位密钥) - 还原:在命令行执行
restore.bat 123456789(必须使用与重排相同的密钥)
内容的提问来源于stack exchange,提问作者Josh T
相关产品推荐
相关产品推荐

