[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[文本处理] [已解决]批处理如何删除前几个字符相同的行?

本帖最后由 lsxq 于 2013-5-12 20:56 编辑

323.456.789.561
323.456.789.542
323.456.789.798
323.456.789.256

981.651.654.681
981.651.654.682

593.658.651.658

能否利用SED或者文本编辑器(类似EditPlus)删除“前几个字符相同的行”,行很多,前几个字符相同的行也很多。这里比如要删除前11个字符相同的所有行,

结果只剩下593.658.651.658这一行。
1

评分人数

    • Batcher: 感谢给帖子标题标注[已解决]字样PB + 2

sed不会,vbs练习中
  1. Set fso = CreateObject("Scripting.FileSystemObject")
  2. Set dic = CreateObject("Scripting.Dictionary")
  3. Set file  = fso.OpenTextFile("a.txt")
  4. Do Until file.AtEndOfStream
  5.    strLine = file.ReadLine
  6.    strKey = Left(strLine,11)
  7.    If Not dic.Exists(strKey) Then
  8.       dic.Add strKey,strLine
  9.    Else
  10.       dic.Item(strKey) = dic.Item(strKey) & vbLf & strLine
  11.    End If
  12. Loop
  13. For Each a in dic.Keys
  14.    If UBound(Split(dic.Item(a),vbLf)) = 0 Then
  15.       str = str & dic.Item(a) & vbCrLf
  16.    End If
  17. Next
  18. fso.CreateTextFile("b.txt",True).Write str
  19. MsgBox "OK"
复制代码

TOP

sed也不会,vbs更不会,bat练习中...
  1. @echo off
  2. (for /f "delims= " %%a in (1.txt) do (
  3.   if not defined %%~na (
  4.     set ok=&set %%~na=a
  5.     call :sc "%%~na" "ok"
  6.     if not defined ok echo %%a
  7. )))>2.txt
  8. start 2.txt&exit /b
  9. :sc
  10. for /f "skip=1 delims=" %%a in ('findstr /b %1 1.txt 2^>nul') do set %~2=.
  11. goto :eof
复制代码
初学BAT,非专业。代码不适当之处还望前辈们多多指点。在此表示感谢!

TOP

高手啊,三楼能解释一下代码吗,没有看懂。

TOP

回复 4# pan528
不敢,新人啊,虽然这账号注册的很早~~
大体意思这样的:这个代码不通用
1、LZ要求11个字符(刚好是去除最后一个.???),所以用%%~na直接取
2、语句if not defined %%~na 和set %%~na=a 中的变量%%~na(即前11位)用来过滤重复行的,这个应该看的懂了,单单这样过滤出来的结果是不存在重复前11位的行
3、但是要求是有出现重复的就要去除,所以用 for /f "skip=1 delims=" %%a in ('findstr /b %1 1.txt 2^>nul') do set %~2=.来判断是否某个前11为字符的行有两行以上的,skip=1后直接取第二行,只要有值则认为有出现两次,则不输出.重复行不多的话:sc可以直接并入到第一个for中去,毕竟CALL比较慢。呃,发现少写了个goto :eof,应该是do set %~2=.&goto :eof,不用循环一遍。
4、delims= 等号后有个空格用来去除空格的行(论坛上好像说tokens=*可以去除首部的空格,按我理解应该也可以去除空格的行,不过我电脑上不行{WIN7},所以用这个),2^>nul则用来去除空行(就一回车换行的行)
5、文本如果超大,就没用了,变量定义有限制的,所以还是2楼的比较通用吧
改成这样应该会快点
  1. @echo off
  2. (for /f "delims= " %%a in (1.txt) do (
  3.   if not defined %%~na (
  4.     set _=&set %%~na=a
  5.     for /f "skip=1 delims=" %%a in ('findstr /b "%%~na" 1.txt 2^>nul') do set "_=_"
  6.     if not defined _ echo %%a
  7. )))>2.txt
复制代码
初学BAT,非专业。代码不适当之处还望前辈们多多指点。在此表示感谢!

TOP

本帖最后由 pan528 于 2013-5-11 11:15 编辑

我觉得你的这段代码适用“删除倒数三个字符前相同的行”的情形,但第一行必须是重复行。
但是,我比较迟钝,还是没有看懂,代码是如何排除“倒数三个字符”的。请指教。
  1. :: 删除倒数三个字符前相同的行
  2. <"%~f0" more +11>1.txt
  3. @echo off
  4. (for /f "delims=-" %%a in (1.txt) do (
  5.   if not defined %%~na (
  6.     set ok=&set %%~na=a
  7.     for /f "skip=1 delims=" %%a in ('findstr /b "%%~na" 1.txt 2^>nul') do set "ok=-"
  8.     if not defined ok echo %%a
  9. )))>2.txt
  10. start 2.txt&exit /b
  11. 323.456.789.781.561
  12. 593.658.651.780.658
  13. 323.456.789.781.542
  14. 323.456.789.781.798
  15. 323.456.789.781.256
  16. 981.651.654.782.681
  17. 981.651.654.782.682
复制代码

TOP

回复 6# pan528
呃,111.222.333.444你把这个设想为一个文件名%%~nxa,%%~na取文件名则为111.222.333(刚好11字符,符合LZ例子).444为扩展名%%~xa
实际上这代码相当于下面的缩减版
  1. @echo off&setlocal enabledelayedexpansion
  2. (for /f "delims= " %%a in (1.txt) do (
  3.   set ".=%%a"&set ".=!.:~,11!"
  4.   if not defined !.! (
  5. set _=&set !.!=a
  6. for /f "skip=1 delims=" %%a in ('findstr /b "!.!" 1.txt 2^>nul') do set "_=_"
  7. if not defined _ echo %%a
  8. )))>2.txt
  9. start 2.txt
复制代码
你那个因为%%~na是取到前15位,而非11位,才会出现你说的第一行必须要重复的。所以我才特意说明那是非通用版的,原因在此。要稍微通用则用这个,想取多少字符自己改数值11
初学BAT,非专业。代码不适当之处还望前辈们多多指点。在此表示感谢!

TOP

截取字符中不能含空格倒是真的,没处理,因为defined空格会出错。所以上面说明为稍微通用~~~~
初学BAT,非专业。代码不适当之处还望前辈们多多指点。在此表示感谢!

TOP

楼主的意思是把有重复项去掉 而不是记录一次

TOP

回复 7# xxpinqz


    可以不用判断重复行的吧?重复行的话前面的11个字符也相同
  1. @echo off
  2. for /f "delims=" %%a in (1.txt) do (
  3.     set /a n=0
  4.     for /f "delims=" %%b in ('findstr /b "%%~na" 1.txt') do set /a n+=1
  5.     set /a "1/(n-1)" 2>nul||echo,%%a
  6. )
  7. pause
复制代码

TOP

回复 10# apang


    sorry,理解错误,if not defined %%~na 是为了减少findstr搜索的次数

TOP

文件大的话 用外部比较好
外部 GAWK
  1. gawk "{t=substr($0,0,11);n[t]++;a[t]=$0} END{for(m in n) if (n[m]<=1) print a[m]}" a.txt
复制代码
如钟情BAT 有点吃力 看文件大小
  1. @echo off&setlocal enabledelayedexpansion
  2. for /f "delims=" %%i in (a.txt) do (
  3.     set str=%%i&set "str=!str:~,11!"
  4.     if not defined #!str! (
  5.        set/a"n+=1"
  6.        set #!str!=#&set "$!n!=%%i"
  7.     ) else set "#!str!=$"
  8. )
  9. for /l %%i in (1 1 !n!) do (
  10.     set str=!$%%i!
  11.     for %%j in ("!str:~,11!") do if !#%%~j!# ==## echo !$%%i!
  12. )
  13. pause
复制代码
  1. @echo off&setlocal enabledelayedexpansion
  2. for /f "delims=" %%i in (a.txt) do (
  3.     set str=%%i&set "str=!str:~,11!"
  4.     set /a "$!str:~,11!+=1"
  5. )
  6. for /f "delims=" %%i in (a.txt) do (
  7.     set str=%%i
  8.     for %%j in ("!str:~,11!") do if "!$%%~j!" == "1" echo %%i
  9. )
  10. pause
复制代码

TOP

回复 11# apang
是那个意思,这个set /a 很好使啊,学习了~
初学BAT,非专业。代码不适当之处还望前辈们多多指点。在此表示感谢!

TOP

12楼这代码,高手啊,快的不是那么一点点。
测了个8000行文本
2楼VBS代码大约在1s23左右,12楼第一个gawk代码5ms(不过会乱序了),第3个代码37s左右
小文本vbs和gawk相差无几.
至于5楼的代码嘛,可以直接忽略了,除非8000行前11位都一样的,这个运行时间才好意思写出来
学到很多~~谢谢2楼12楼
初学BAT,非专业。代码不适当之处还望前辈们多多指点。在此表示感谢!

TOP

回复 14# xxpinqz
难道测试数据不一样 差距这么大?
硬件也不会相差这么多吧
我这里测试 5W行数据都不过 5s 的

TOP

返回列表