找回密码
 注册
搜索
[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
查看: 9647|回复: 15

[文本处理] [已解决]求批处理算法:把多行上下级关系转换为树形结构的上下级关系

[复制链接]
发表于 2025-7-19 09:11:22 | 显示全部楼层 |阅读模式
本帖最后由 hnfeng 于 2025-7-20 16:24 编辑

原始的txt文件内容是:左边是上级,右边是下级。有且只有一个最高级(这里就是z_033b7312.txt)
t_9057374.txt ---> t_9057375.txt
z_033b7312.txt ---> c_9060409.txt
z_033b7312.txt ---> c_9c09ff24.txt
c_9060409.txt ---> t_9057374.txt
c_9c09ff24.txt ---> t_c301154f.txt
z_033b7312.txt ---> t_80dba877.txt
t_9057374.txt ---> t_9057376.txt

为了方便,也可以把中间的字符改为TAB,如下(请按TAB分割来处理吧)
  1. t_9057374.txt        t_9057375.txt
  2. z_033b7312.txt        c_9060409.txt
  3. z_033b7312.txt        c_9c09ff24.txt
  4. c_9060409.txt        t_9057374.txt
  5. c_9c09ff24.txt        t_c301154f.txt
  6. z_033b7312.txt        t_80dba877.txt
  7. t_9057374.txt        t_9057376.txt
复制代码
想生成的结果文件内容是:
z_033b7312.txt
    ├ c_9060409.txt
    │    └ t_9057374.txt
    │          ├ t_9057375.txt
    │          └ t_9057376.txt
    ├ c_9c09ff24.txt
    │    └ t_c301154f.txt
    └ t_80dba877.txt

为了简化代码,也可以简单一些
  1. z_033b7312.txt
  2.     c_9060409.txt
  3.         t_9057374.txt
  4.             t_9057375.txt
  5.             t_9057376.txt
  6.     c_9c09ff24.txt
  7.         t_c301154f.txt
  8.     t_80dba877.txt
复制代码
只有一个最高级。下级可能有多个级别

请高手们帮忙,谢谢
发表于 2025-7-19 15:18:28 | 显示全部楼层
本帖最后由 aloha20200628 于 2025-7-19 15:21 编辑

回复 1# hnfeng

楼主能说出不同层级与其上级的隶属规律吗?尤其是当数据行增至过百上千时...此题来自的缘由?
 楼主| 发表于 2025-7-19 15:32:38 | 显示全部楼层
本帖最后由 hnfeng 于 2025-7-19 15:43 编辑

回复 2# aloha20200628


    1、不同层级的关系,都在原文本文件中体现了
   2、不会有很多层,最多先按 4 层或 5 层来处理吧
   3、每行只有一个分隔符(TAB)分割两个文件名。所有文件名,不会重复

我的想法是,先在文本文件中获取所有的分隔符的 前(A1-An) 和后(B1-Bn)的内容,然后逐个找Ax是否在B中出现,如果没有在B中,说明这个就是最高级(根)
然后……,就不知道如何获取其他层级的算法了

补充:  最高级(根)找到后,貌似,所有最高级对应的Bx 都是第二级了……
如例子:
只有 z_033b7312.txt 没有出现在B中,所以 z_033b7312.txt 就是最高级,  然后,由
z_033b7312.txt        c_9060409.txt
z_033b7312.txt        c_9c09ff24.txt
z_033b7312.txt        t_80dba877.txt
可知, 这三个Bx 就是第二级
……
发表于 2025-7-19 16:51:34 | 显示全部楼层
本帖最后由 77七 于 2025-7-19 16:54 编辑
  1. @echo off
  2. cd /d "%~dp0"
  3. setlocal enabledelayedexpansion
  4. for /f "useback tokens=1-2 delims=        " %%a in ("1.txt") do (
  5.         set _%%a=!_%%a! %%b
  6. )
  7. >output.txt echo z_033b7312.txt
  8. set str=   
  9. call :1 z_033b7312.txt
  10. pause
  11. exit

  12.         :1
  13.         for /f "tokens=1-2 delims==" %%a in ('2^>nul set _%~1') do (
  14.                 for %%c in (%%b) do (
  15.                         set str=%str%   
  16.                         >>output.txt echo %str% %%c
  17.                         call :1 %%c
  18.                 )
  19.         )
  20.         exit /b
复制代码

写了个草稿,没有写获得最高级及处理一些细节问题,大概有多个最高级,也是可以实现的,楼主再自行修改吧。
发表于 2025-7-19 19:15:37 | 显示全部楼层

  1. @set @do_not_save_as_utf8=1;/*&echo off

  2. type "1.txt"|cscript //nologo //e:jscript "%~f0"

  3. pause&exit /b 0 */

  4. var str=WScript.StdIn.ReadAll().split(/\r?\n/);
  5. var node=function(v){this.value=v;this.next=[];}
  6. var root=null,root_table=[],node_table={};
  7. var switch_root=function(r){
  8. for(var k=0;k<root_table.length;k++){
  9. if(r==root_table[k][1])return root_table[k][0];}
  10. return 0;
  11. }

  12. for(var  i=0;i<str.length;i++){
  13. var a=str[i].split("\t");

  14. if(node_table["@@"+a[0]]){;}else{
  15. var _node=new node(a[0]);
  16. node_table["@@"+a[0]]=_node;
  17. }

  18. if(node_table["@@"+a[1]]){;}else{
  19. var _node=new node(a[1]);
  20. node_table["@@"+a[1]]=_node;
  21. }

  22. node_table["@@"+a[0]].next.push(node_table["@@"+a[1]]);
  23. root_table.push(["@@"+a[0],"@@"+a[1]]);

  24. if(root){
  25. while(1){
  26. var _root=switch_root(root);
  27. if(_root){root=_root;}else{break;}
  28. }
  29. }else{
  30. root="@@"+node_table["@@"+a[0]].value;
  31. }

  32. }

  33. var print=function (x,y){
  34. for(var i=0;i<x.length;i++){
  35. if(x[i].next.length){
  36. WScript.Echo(y+x[i].value);
  37. print(x[i].next,y+'    ');
  38. }else{WScript.Echo(y+x[i].value);}
  39. }}
  40. WScript.Echo(node_table[root].value);
  41. print(node_table[root].next,'    ');
复制代码
 楼主| 发表于 2025-7-19 20:29:54 | 显示全部楼层
回复 4# 77七


    谢谢,高手啊

虽然需要先指定最高级的文件名,但是也不是多麻烦,很好的得到了结果
算法很精妙,我要细细研究学习。
非常感谢
 楼主| 发表于 2025-7-19 20:31:19 | 显示全部楼层
回复 5# Five66


    谢谢。我不懂JS,输出结果也准确,只是能否输出结果到文件中?目前只是显示在cmd窗口中
发表于 2025-7-19 21:34:40 | 显示全部楼层
本帖最后由 idwma 于 2025-7-19 22:01 编辑
  1. #@&cls&powershell "type '%~0'|out-string|iex"&pause&exit
  2. $a=@{}
  3. $b=@{}
  4. gc a.txt|%{
  5.   $d=$_ -split "`t"
  6.   $a[$d[0]]+=@{$d[1]=''}
  7.   $b[$d[1]]=$d[0]
  8. }

  9. while($a.count -ne 1){
  10.   $a.keys.clone()|%{
  11.     $d=1
  12.     $a[$_].keys|%{
  13.       $c=$_
  14.       if($a[$c] -ne $null){$d=0}
  15.     }
  16.     if($d){$a[$b[$_]][$_]=$a[$_];$a.remove($_)}
  17.   }
  18. }

  19. function z($a,$b){
  20.   $a.keys|sort|%{
  21.     '{0}{1}' -f $b,$_
  22.     if($a[$_] -ne ''){z $a[$_] ('    '+$b)}
  23.   }
  24. }
  25. z $a
  26. #z $a|sc o.txt
复制代码
发表于 2025-7-19 21:47:49 | 显示全部楼层
本帖最后由 77七 于 2025-7-19 21:49 编辑

回复 6# hnfeng


   我模仿的以前terse大佬写的查找空文件夹代码的方法写的。
这个题目像是左边是老板,右边是员工(也可能是下级员工的老板),所以找到最大的老板的方法就是看他是不是也有员工身份,还是很简单的。

以下写了个完整代码,不限制一个最大老板
  1. @echo off
  2. cd /d "%~dp0"
  3. setlocal enabledelayedexpansion
  4. for /f "useback tokens=1-2 delims=        " %%a in ("1.txt") do (
  5.         set #"%%b"=1
  6.         set _"%%a"= !_"%%a"! "%%b"
  7. )
  8. (for /f "useback tokens=1-2 delims=        " %%a in ("1.txt") do (
  9.         if not defined #"%%a" (
  10.                 set #"%%a"=1
  11.                 set "str=        "
  12.                 echo %%a
  13.                 call :1 "%%a"
  14.         )
  15. )) > "output.txt"
  16. endlocal
  17. pause
  18. exit

  19.         :1
  20.         for %%d in (!_"%~1"!) do (
  21.                 set "str=%str%        "
  22.                 echo %str%%%~d
  23.                 call :1 "%%~d"
  24.         )
  25.         exit /b
复制代码
发表于 2025-7-19 23:09:00 | 显示全部楼层
回复 7# hnfeng


    5楼代码第3行末尾加上重定向到文件的代码就能输出到文件了 ,例如加上 >2.txt ,输出结果保存到2.txt文件
 楼主| 发表于 2025-7-20 09:14:01 | 显示全部楼层
回复 9# 77七


    多谢多谢,完美
厉害,高手
 楼主| 发表于 2025-7-20 09:15:11 | 显示全部楼层
回复 10# Five66


        多谢多谢,完美实现。厉害,高手
发表于 2025-7-20 14:34:30 | 显示全部楼层
本帖最后由 aloha20200628 于 2025-7-20 15:03 编辑

回复 3# hnfeng

根据楼主补充说明,如果看作是解析一组相对路径进而构建其完整目录树,则采用其深度递归方法确实比较简捷...
以下的批处代码》
   先读取一楼用跳格作为分隔符的示例文件(1.txt)获取根目录;
   再获取每个节点直属的子节点链表;
   最后用递归输出完整目录树(存为 2.txt),根据递归步进和返回确定每个节点在目录树中的位置...

  1. @echo off &setlocal enabledelayedexpansion &set "st="
  2. for /f "delims=        " %%a in (1.txt) do findstr /irc:"        %%a" 1.txt>nul 2>nul||set "r=%%a"
  3. for /f "tokens=1-2 delims=        " %%a in (1.txt) do (set "_#%%a=!_#%%a! %%b")
  4. (call :xxx "%r%")>"2.txt" &exit/b
  5. :xxx
  6.    if "%~1"=="" (exit/b) else (echo,!st!%~1&set "st=!st!        ")
  7.    for %%x in (!_#%~1!) do (call :xxx "%%~x")
  8.    set "st=!st:~0,-1!" &exit/b
复制代码
发表于 2025-7-20 16:21:07 | 显示全部楼层
本帖最后由 flashercs 于 2025-7-20 16:24 编辑

注意防止 堆栈溢出
例如下面的文本:
  1. t_9057374.txt        t_9057375.txt
  2. z_033b7312.txt        c_9060409.txt
  3. z_033b7312.txt        c_9c09ff24.txt
  4. c_9060409.txt        t_9057374.txt
  5. c_9c09ff24.txt        t_c301154f.txt
  6. z_033b7312.txt        t_80dba877.txt
  7. t_9057374.txt        t_9057376.txt
  8. t_9057375.txt        c_9060409.txt
复制代码
会导致
  1. ******  B A T C H   R E C U R S I O N  exceeds STACK limits ******
  2. Recursion Count=212, Stack Usage=90 percent
  3. ******       B A T C H   PROCESSING IS   A B O R T E D      ******
复制代码
交换机有个重要协议STP:
STP协议(生成树协议)是用于消除二层网络环路的通信协议,由Radia Perlman于1985年设计,后成为IEEE 802.1D标准。该协议通过选举根网桥(基于网桥ID优先级和MAC地址)、根端口(最小根路径成本)及指定端口,逻辑阻断冗余链路构建无环树形拓扑,防止广播风暴和MAC地址表震荡。交换机间通过BPDU报文交互拓扑信息,实现路径故障切换。
 楼主| 发表于 2025-7-20 16:24:09 | 显示全部楼层
回复 13# aloha20200628


    多谢多谢,也很完美。厉害,谢谢上面的各位高手
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|批处理之家 ( 渝ICP备10000708号 )

GMT+8, 2026-3-17 06:26 , Processed in 0.022342 second(s), 8 queries , File On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表