Board logo

标题: 用批处理也可以简单实现删除文本相同行 [打印本页]

作者: youxi01     时间: 2006-10-31 21:53    标题: 用批处理也可以简单实现删除文本相同行

@echo off
echo 正在查找文本相同行,请等待.....
(echo 清除重复行后的文件内容:& echo.)>str_.txt

setlocal enabledelayedexpansion
for /f "delims=" %%i in (test.txt) do (
    if not defined %%i set %%i=A & echo %%i>>str_.txt)

echo 清理完毕,清理后的文件保存在:str_.txt
pause>nul

经过测试,基本达到删除相同行的目的,但是暂时没有处理空行。
作者: namejm     时间: 2006-10-31 22:25
  用文本行的内容是否已经被定义过来决定是否输出,实现了代码的简洁化,比起常规思路要节省N多代码,楼主的手段确实高明。

  观察你的代码,并没有用到变量延迟,所以 setlocal enabledelayedexpansion 一句可以省略。
作者: 9527     时间: 2006-10-31 23:17
不过对与以下形式的文本好像就无能为力了

A HELLO WORLD
set c=
A YOU
HELLO YOU
set a=
A YOU
set sdfs=
set sdfs=
HEllo you
set c=
you are very good
作者: NaturalJ0     时间: 2006-10-31 23:19
如果有一万行似乎也行不通。
作者: namejm     时间: 2006-10-31 23:27
  看来对不符合变量命名规则的行内容、超过变量个数限制的文本都无法正确处理。
作者: youxi01     时间: 2006-11-1 00:58
至于大小写的问题,倒是比较好处理:添一个开关 /I即可。
if /I not defined %%i set %%i=A & echo %%i>>str_.txt)
但是对于“特殊的文本行”还是没想到好的解决办法,望高手指点。
作者: lxmxn     时间: 2006-11-1 01:30

  小弟愚笨,不明白这一句(if /I not defined %%i set %%i=A & echo %%i>>str_.txt)为什么可以起到"删除文本相同的行"的作用,想了半天没想出来,还请各位大侠不吝赐教,详细的分析一下其机理。

作者: redtek     时间: 2006-11-1 01:52
原理是每从test.txt里取一行就给它赋值为A,
例:如果取了一行“ABC”,那么它就让 ABC=A,这样是不是变量ABC非空值而是被定义了?

然后if not defined会依次检查从这个test.txt文本内取出来的每一行,
它把取出来的这一条当做一个变量来看,判断它是不是没被定义过,即看是否没有被赋值。

如果没有被赋值当然说明这个变量(取出来的这一行)跟本就出现过(没重复过),说明这行是非重复的行。

……
一直到结束,只要取一行就把这行以变量命名来赋个值,
只要将来判断新取的行(早被当做变量了)被赋过值,那一定是重复的,
所以就不往过滤后的文本文件内写东东了:)
作者: youxi01     时间: 2006-11-1 02:03
@echo off
echo 正在查找文本相同行,请等待.....
(echo 清除重复行后的文件内容:& echo.)>str_.txt
setlocal enabledelayedexpansion
for /f "delims=" %%i in (test.txt) do (
    set /a flag=0
    echo %%i | find "=" >nul && set /a flag=1
    for /f "tokens=1* delims==" %%a in ("%%i") do (
           if /i not defined %%a%%b (
           set %%a%%b=A
           if  !flag! equ 1 (echo %%a=%%b>>str_.txt) else echo %%a>>str_.txt
     )   
  )
)
echo 清理完毕,清理后的文件保存在:str_.txt
pause>nul

说明:以上代码成功解决“=”的问题,包括set var=(不含空格) set var=(含空格)
但以上代码仍然不能解决文本内容出现> <等一系列问题。
作者: namejm     时间: 2006-11-1 02:37
  9F的代码虽然能解决一个“=”的问题,但是仍然不能解决多个“=”号的情况,并且速度非常慢,处理3F的文本也需要好几秒,问题出在 echo %%i|find "=" 这一句上。看来还得多费点心思。
作者: electronixtar     时间: 2006-11-1 03:38
看来批处理不适合复杂的文本处理,天生缺陷啊。找找第三方工具试试
作者: vkill     时间: 2006-11-1 05:09
用sed可以轻松实现~ 处理问题时最有效的才是最好的,我是这样认为,用第三方工具又何妨?

http://www.cn-dos.net/forum/view ... 1&highlight=sed


选择性地删除特定行:
--------
# 显示通篇文档,除了两个正则表达式之间的内容
sed '/Iowa/,/Montana/d'
# 删除文件中相邻的重复行(模拟“uniq”)
# 只保留重复行中的第一行,其他行删除
sed '$!N; /^\(.*\)\n\1$/!P; D'
# 删除文件中的重复行,不管有无相邻。注意hold space所能支持的缓存
# 大小,或者使用GNU sed。
sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P'
# 删除除重复行外的所有行(模拟“uniq -d”)
sed '$!N; s/^\(.*\)\n\1$/\1/; t; D'
# 删除文件中开头的10行
sed '1,10d'
# 删除文件中的最后一行
sed '$d'
# 删除文件中的最后两行
sed 'N;$!P;$!D;$d'
# 删除文件中的最后10行
sed -e :a -e '$d;N;2,10ba' -e 'P;D'   # 方法1
sed -n -e :a -e '1,10!{P;N;D;};N;ba'  # 方法2
# 删除8的倍数行
gsed '0~8d'                           # 只对GNU sed有效
sed 'n;n;n;n;n;n;n;d;'                # 其他sed
# 删除匹配式样的行
sed '/pattern/d'                      # 删除含pattern的行。当然pattern
                                       # 可以换成任何有效的正则表达式
# 删除文件中的所有空行(与“grep '.' ”效果相同)
sed '/^$/d'                           # 方法1
sed '/./!d'                           # 方法2
# 只保留多个相邻空行的第一行。并且删除文件顶部和尾部的空行。
# (模拟“cat -s”)
sed '/./,/^$/!d'        #方法1,删除文件顶部的空行,允许尾部保留一空行
sed '/^$/N;/\n$/D'      #方法2,允许顶部保留一空行,尾部不留空行
# 只保留多个相邻空行的前两行。
sed '/^$/N;/\n$/N;//D'
# 删除文件顶部的所有空行
sed '/./,$!d'
# 删除文件尾部的所有空行
sed -e :a -e '/^\n*$/{$d;N;ba' -e '}'  # 对所有sed有效
sed -e :a -e '/^\n*$/N;/\n$/ba'        # 同上,但只对 gsed 3.02.*有效
# 删除每个段落的最后一行
sed -n '/^$/{p;h;};/./{x;/./p;}'
作者: electronixtar     时间: 2006-11-1 05:34
看来得下载一个sed了,哇咔咔
作者: lxmxn     时间: 2006-11-1 09:27

  谢谢 redtek 的指点,明白了。开始还以为如果%%i的值是空值的话,就表示没有定义呢,现在才理解了"defined"的真正含义是要用"set"定义之后才算是"defined",呵呵。

作者: 3742668     时间: 2006-11-5 01:51

@echo off
    set file2=b.txt
    set file1=a.txt 4>%file2%
    set tmpVar=
    for /f "delims=: tokens=1,*" %%i in ('findstr /n .* %file1%') do (
        set tmpVar=%%j
        if not defined tmpVar ( >>%file2% echo.
                              ) else (
                                      findstr /xc:"%%j" %file2% || (echo %%j)>>%file2%
                                     )
    )
楼主所用的方法我也曾经尝试过,不过由于局限太大的原因基本不使用。用批处理来处理文件的确比较麻烦,处理比较特殊的文件的时候提倡还是用vbs或第三方工具。
对于数据量不大的情况,适当地使用批处理还是比较方便的:
@echo off
setlocal enabledelayedexpansion
    set old=xxx.txt
    set new=yyy.txt
    for /f "delims=: tokens=1,*" %%i in ('findstr /n .* %new%') do set "%%i=%%j" && set num=%%i
    call :whatyouwant
goto :eof

rem 反向显示文件
:last2first
    for /l %%i in (%num%,-1,1) do if defined %%i (echo !%%i!) else echo.
goto :eof

rem 过滤空行
:filter
    findstr . %old%
goto :eof

rem 在指定行插入内容,下面的例子是在第3行后插入,内容为%youstr%
rem 如果是要重定向到文件中则应该在%3%后面加上重定向语句
:insert
    set "3=%3%&&echo %youstr%"
    for /l %%i in (1,1,%num%) do echo !%%i!
goto :eof

rem 删除指定行,下面是删除第三行的例子
:delline
    set 3=
    for /l %%i in (1,1,%num%) do echo !%%i!
goto :eof

rem 只显示单数行.要显示双数行,以及先显示单数行,再显示双数行可以用同样的方法
:printOdd
    for /l %%i in (1,2,%num%) do echo !%%i!
goto :eof
时间关系,以上代码均未测试.暂时写这么一点东西,以后再把12F实现的功能全部写出来.
顺便向和俺一样双休日不得休息的同志们致敬!
作者: tongwandou     时间: 2007-4-19 11:43


  Quote:
Originally posted by lxmxn at 2006-10-31 12:30 PM:

  小弟愚笨,不明白这一句(if /I not defined %%i set %%i=A & echo %%i>>str_.txt)为什么可以起到"删除文本相同的行"的作用,想了 ...

楼主在这句里运用了变量的延迟替换这一神奇的功能!我也是菜鸟,研究了半天,查了一堆资料,做了N次测试才领悟到的.具体你可以查看以前的一些关于变量延迟替换的贴子!
作者: bjsh     时间: 2007-4-19 21:41
ls的你可真敢说;
那都是什么时候的事情了;
lxmxn兄可是个大牛人;
作者: bjsh     时间: 2007-4-19 21:43
说不定你看的那些变量延迟的还是lxmxn兄写的呢;

不过;我怎么没觉得那段代码用了
你所谓的 "变量的延迟替换"的??
作者: htysm     时间: 2007-4-20 00:41
这一句看得偶糊涂,太菜了没办法。