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

[文本处理] 文本去重批处理程序,不知道哪里错了,请大家帮助看一下

[复制链接]
发表于 2025-10-8 09:49:07 | 显示全部楼层 |阅读模式
做一个练习,用多种方法去重,其中有一个认为没有问题的程序,不知为何一直运行不能成功,而自己却找不出问题。请大佬帮助看一下。
一个简单的文本,名字为1.txt,其内容如下:
bbs
bathome
net
bathome
bbs

所编写的练习程序如下:
  1. setlocal enabledelayedexpansion
  2. echo. >chk.txt

  3. for /f "delims=" %%a in (1.txt) do (
  4.     set "!value!="
  5.     for /f "delims=" %%b in (chk.txt) do (
  6.         if "%%a"=="%%b" (
  7.         set "!value!=1"
  8.         goto skip
  9.                       )
  10.                                 )
  11. :skip
  12.     if not defined !aa! echo %%a >>chk.txt
  13.    )
  14. chk.txt
复制代码
上述程序运行完后根本没有去除重复,而自己觉得思路与处理没有问题,找不出哪里错了,可能我对循环跳出的理解不对。请大佬指点一下

chk.txt
 楼主| 发表于 2025-10-8 10:48:48 | 显示全部楼层
做一个练习,用多种方法去重,其中有一个认为没有问题的程序,不知为何一直运行不能成功,而自己却找不出问题。请大佬帮助看一下。
一个简单的文本,名字为1.txt,其内容如下:
bbs
bathome
net
bathome
bbs

所编写的练习程序如下:
setlocal enabledelayedexpansion
echo. >chk.txt

for /f "delims=" %%a in (1.txt) do (
    set "!value!="
    for /f "delims=" %%b in (chk.txt) do (
        if "%%a"=="%%b" (
        set "!value!=1"
        goto skip
                      )
                                )
:skip
    if not defined !value! echo %%a >>chk.txt
   )
chk.txt

上述程序运行完后根本没有去除重复,而自己觉得思路与处理没有问题,找不出哪里错了,可能我对循环跳出的理解不对。请大佬指点一下

chk.txt
 楼主| 发表于 2025-10-8 10:49:22 | 显示全部楼层
刚才程序上传的不对,是这个。这个也运行不成功的
 楼主| 发表于 2025-10-8 11:05:10 | 显示全部楼层
问题诊断​
​换行符干扰比较​

for /f默认会保留行尾的换行符(\r\n),导致 %%a和 %%b的比较失败(例如 bbs与 bbs\r不匹配)。
更新的程序如下:
--------------------------------------------------------------------------------------------------
@echo off
setlocal enabledelayedexpansion
echo. > chk.txt

for /f "delims=" %%a in (1.txt) do (
    set "value=0"
    for /f "delims=" %%b in (chk.txt) do (
        set "line=%%b"
        set "line=!line:~0,-1!"  :: 去除行尾换行符
        if "%%a"=="!line!" (
            set "value=1"
            goto :skip
        )
    )
    :skip
    if !value! == 0 (
        echo %%a >> chk.txt
    )
)

endlocal

chk.txt
发表于 2025-10-8 11:07:00 | 显示全部楼层
本帖最后由 aloha20200628 于 2025-10-8 11:11 编辑

回复 3# delab-1

试试以下这个版本,不采用变量延迟可以兼容源文件包含的 ! 等特殊字符 ...

  1. @echo off &cd.>chk.txt
  2. for /f "delims=" %%a in (1.txt) do (
  3.     set "x="
  4.     for /f "delims=" %%b in (chk.txt) do if not defined x if "%%a"=="%%b" (set "x=1")
  5.     if not defined x (echo,%%a)>>chk.txt )
  6. pause&exit/b
复制代码
 楼主| 发表于 2025-10-8 11:07:11 | 显示全部楼层
各位,上面询问了DEEPSEEK,给出的答案,问题可能是:
for /f默认会保留行尾的换行符(\r\n),导致 %%a和 %%b的比较失败(例如 bbs与 bbs\r不匹配)。
然后在程序中加入:
  set "line=!line:~0,-1!"  :: 去除行尾换行符
问题就解决了。
的确这个地方之前不知道,所以挑战了自我认知!感谢大家。另外,如果大家有建议也可以提出来交流。
发表于 2025-10-8 11:21:01 | 显示全部楼层
回复 6# delab-1

你的代码出错至少有一个关键,并非是换行符问题,而是输出行尾多出了空格,采用5楼第5行代码中的用法可解》(echo,%%a)>>chk.txt
 楼主| 发表于 2025-10-8 11:53:35 | 显示全部楼层
另外发现一个重要的问题,在for循环中,必须加入“delims="或者"tokens=*",否则程序也运行不对。
在此基础上,对循环进一步简化,更符合我们运行去重的理念。大家看一下下面的程序。
setlocal enabledelayedexpansion
echo. > chk.txt

for /f "delims=" %%a in (1.txt) do (
    for /f "delims=" %%b in (chk.txt) do (
        set "line=%%b"
        set "line=!line:~0,-1!"  :: 去除行尾换行符
        if "%%a"=="!line!" (
            goto :skip
        )
    )
echo %%a >> chk.txt
    :skip
echo >nul
)
chk.txt
---------------------------------------------------------
上述程序不做任何判断,如果发现重复,直接跳出循环;没有重复的才echo。但是有一点需要主要注意:
:skip不能写在最后一行(即:)之前)。
必须加入一行,所以加入echo>nul,这个没有任何含义的语句,以保持运行。

在这个简单的练习中,发现很多注意事项,也希望高手能给与指点,看看我的理解(都是来自实践,没有理论支撑)是否正确。多谢指点
 楼主| 发表于 2025-10-8 12:26:45 | 显示全部楼层
回复 7# aloha20200628
是的,刚才做了多个测试,发现问题果然出现在输出上。
setlocal enabledelayedexpansion
echo.> chk.txt

for /f "delims=*" %%a in (1.txt) do (
    for /f "tokens=*" %%b in (chk.txt) do (
            if "%%a"=="%%b" (
            goto :skip
        )
    )
(echo %%a)>>chk.txt
    :skip
echo >nul
)
chk.txt

----------------------------------------------------
上面的结果是正确的,下面三种都可以。
1.(echo %%a)
2. 加入过渡,set value=%%a & echo !value!>>chk.txt
3.echo %%a>>chk.txt,(>>之前没有空格)
 楼主| 发表于 2025-10-8 12:28:53 | 显示全部楼层
最后的简化程序,如下:
echo.> chk.txt
for /f  %%a in (1.txt) do (
    for /f  %%b in (chk.txt) do (
        if "%%a"=="%%b" (
            goto :skip
        )
    )
echo %%a>>chk.txt
:skip
echo >nul
)
chk.txt
达到了预期结果,总结一下:
1)>>输出前不能有空格
2):skip不能出现在最后循环最后一行
发表于 2025-10-8 14:25:05 | 显示全部楼层
在for中用goto和标签, 真的没问题???
发表于 2025-10-8 15:10:39 | 显示全部楼层
本帖最后由 aloha20200628 于 2025-10-8 15:12 编辑

回复 10# delab-1

很多老帖都毙掉了在循环体内用标签玩goto的戏法,肯定他们是在多种玩法中踩雷了。
在后来的很多高级语言中也都没有了goto语句,算是证明了一种业界共识...
若用批处中比较规范的call方法复现你的代码逻辑,可参考以下这个示例版本。

  1. @echo off &cd.>chk.txt
  2. for /f "delims=" %%a in (1.txt) do (call :[q] "%%a")
  3. pause&exit/b
  4. :[q]
  5.    for /f "delims=" %%b in (chk.txt) do if "%~1"=="%%b" exit/b
  6.    (echo,%~1)>>chk.txt
  7.    exit/b
复制代码
发表于 2025-10-8 18:30:19 | 显示全部楼层
回复 9# delab-1


  
加入过渡,set value=%%a & echo !value!>>chk.txt
&前存在一个空格,value的值是%%a+空格



  1. set "value=%%a"
  2. >> "chk.txt" echo !value!
复制代码
 楼主| 发表于 2025-10-9 09:23:15 | 显示全部楼层
回复 12# aloha20200628


   这个很赞,的确用在循环中用goto有很多问题,耽误时间。
发表于 2025-10-9 10:53:35 | 显示全部楼层
本帖最后由 aloha20200628 于 2025-10-9 11:02 编辑

回复 14# delab-1

call 方法在批处代码中有特殊价值,如12楼代码中,call 应用于主循环中使得子过程(循环体)有 break 效果...
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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