【练习-001】批处理实现两文本同行交替输出
[color=red]从今天开始,本人将陆续推出文本输出类题目给新手做,并会根据解答思路和解答过程酌情
加分(解题思路为重),希望广大新手放开思路踊跃讨论和解题,本人也会在其中发表自己的
观点,并予以新人以指点的,好了不多说了,下面是第一题:
[/color]
[color=blue]
有两个文本如下(实际中并不知道两文本各有多少行):
文本1.txt[code]aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
ccccccccccccccccccccccccccccccccccccccc
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
ggggggggggggggggggggggggggggggggggggggg
wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz[/code]文本2.txt[code]hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn[/code]要求用批处理输出如下(两文本交替输出):[code]aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
ccccccccccccccccccccccccccccccccccccccc
iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
ggggggggggggggggggggggggggggggggggggggg
nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz[/code]要求:
1 尽量不生成临时文件
2 代码要高效
3 代码尽量简洁
目的:
唯一的目的在于共同提高!
[color=green][/color][color=green]----------------------------------------------------------------------------------------------------------------------------------------------------
[color=#0000ff]到目前为止,已经有了两个较为满意的答案:[/color]
[color=#0000ff]第一种是先判断行数采用变量赋值的方法,[/color][color=#0000ff]见14楼more和15楼本人的代码。[/color]
[color=#0000ff]特点:通用性强,代码简洁且效率较高。[/color]
[color=#0000ff]第二种是不判断行数采用变量控制的方法,见16楼pusofalse版主和18楼本[/color][color=#0000ff]人的代码。[/color]
[color=#0000ff]特点:通用性强,代码简洁且效率最高。[/color][/color][/color]
[color=blue][color=green][color=#0000ff]第三种是生成临时文件的方案,见24楼本人的代码。[/color][/color][/color]
[color=blue][color=green][color=#0000ff]特点:思路较独特[/color]
[color=#0000ff]希望大家充分放开思路,看看还有别的解决方案不,只要是按要求做出来的,一律加分。[/color]
[color=#0000ff][/color][/color][/color]
[[i] 本帖最后由 batman 于 2008-7-27 23:58 编辑 [/i]] @echo off
for /f "tokens=1* delims=:" %%i in ('findstr /n .* 1.txt') do (
echo %%j>>3.txt
for /f "tokens=1* delims=:" %%a in ('findstr /n .* 2.txt') do (
if %%i==%%a echo %%b>>3.txt
)
)
pasle 首先对二楼做为鼓励予以加分,同时对存在的问题予以指出:
二楼的方法存在以下的问题:
1 首先我们不知道两个文本各有多少行,如果1.txt的行数比2.txt少,而你的代码中for循环到
了1.txt最后一行就终止了,那么2.txt多出的行就全部漏掉了。
2 如果1.txt中的行数比2.txt少,二楼的代码也存在效率问题,在上面的代码中调用for的次数
是1.txt行数乘上2.txt的行数,而理论上最少的调用次数是两文本行数的和。
3 if %%i==%%a改为if "%%i"=="%%a"实为妥当些。
4 最后的pause出现了笔误。
[[i] 本帖最后由 batman 于 2008-7-24 15:25 编辑 [/i]] 纠正一点,2楼并没有产生临时文件,他只是输出到文件,不算违规。
此题,说难不难,说简单也不简单,不过以“浅默”的功力似乎不应该只是如此。。。
大家都来试试。。。看谁最先给出完美答案。。
. [quote]原帖由 [i]随风[/i] 于 2008-7-24 13:38 发表 [url=http://bbs.bathome.net/redirect.php?goto=findpost&pid=5868&ptid=1239][img]http://bbs.bathome.net/images/common/back.gif[/img][/url]
纠正一点,2楼并没有产生临时文件,他只是输出到文件,不算违规。
[/quote]
对不起,是我搞错了,已更正。 这题应该是1.txt总是比2.txt多吧? [quote]原帖由 [i]pusofalse[/i] 于 2008-7-25 00:01 发表 [url=http://bathome.net/redirect.php?goto=findpost&pid=5879&ptid=1239][img]http://bathome.net/images/common/back.gif[/img][/url]
这题应该是1.txt总是比2.txt多吧? [/quote]
未必,也有可能是 2.txt 比 1.txt 的行数多。 给个小提示:
可以先判断两个文本哪个的行数多,再把行多的文本放到第一个for中。
同时也可以不判断文本的行数,但思路就要开放点了。
本人暂时想出了三个解决方案,暂不贴出,希望大家能有更好的办法。 这类的交错输出的文本题比较经典,不确定到底那个多,岂不是要先得读出行数多或行数少的那个? 是不是可以换个思路:判断和输出同时进行呢? 也可以根本不必要判断文本的行数。 的确如此 思维定向了。 不过有个疑问就是:效率是不是会非常低呢?特别是遭遇大文件时
根据代码的意思,似乎是查询两个文件行号一样的时候就分别写入到文件里
这样的话,要是第二个文件有1W行岂不是要比对1W次?这样,明显有9999次是没有必要的...
想得头都要破了
[code]@echo offsetlocal enabledelayedexpansion
for /f "delims=" %%a in ('type 11.txt') do (
set /a m+=1
set "home!m!=%%a"
)
for /f "delims=" %%b in ('type 12.txt') do (
set /a n+=1
set "bat!n!=%%b"
)
if %m% gtr %n% (
for /l %%c in (1 1 %m%) do (
if not "!home%%c!"=="" echo !home%%c!
if not "!bat%%c!"=="" echo !bat%%c!
)
) else (
for /l %%d in (1 1 %n%) do (
if not "!home%%d!"=="" echo !home%%d!
if not "!bat%%d!"=="" echo !bat%%d!
)
)
pause[/code]
[[i] 本帖最后由 more 于 2008-7-25 10:44 编辑 [/i]] [quote]原帖由 [i]more[/i] 于 2008-7-25 10:38 发表 [url=http://bbs.bathome.net/redirect.php?goto=findpost&pid=5888&ptid=1239][img]http://bbs.bathome.net/images/common/back.gif[/img][/url]
@echo off
setlocal enabledelayedexpansion
for /f "delims=" %%a in ('type 11.txt') do (
set /a m+=1
set "home!m!=%%a"
)
for /f "delims=" %%b in ('type 12.txt') do (
set /a n+=1
set ... [/quote]
代码可以简化,下面先公布我的第一种方法:[code]@echo off
for /f "delims=" %%i in (1.txt) do set /a n+=1&call,set "_%%n%%=%%i"
for /f "delims=" %%i in (2.txt) do set /a m+=1&call,set ".%%m%%=%%i"
if %n% gtr %m% (set "num=%n%") else (set "num=%m%")
for /l %%i in (1,1,%num%) do (
if defined _%%i call,echo %%_%%i%%
if defined .%%i call,echo %%.%%i%%
)
pause>nul[/code]
[[i] 本帖最后由 batman 于 2008-7-25 17:05 编辑 [/i]] @echo off&setlocal enabledelayedexpansion&set n=-1
for /f "delims=" %%a in (1.txt) do (
set/a n+=1
set flag=
call :lp %%a
if not defined flag echo %%a
)
:lp
if "%1" equ "" set/a n+=1
set m=skip=%n%
if "%m%" equ "skip=0" set "m="
for /f "%m% delims=" %%a in (2.txt) do if "%1" neq "" (echo %1&echo %%a&set flag=a&goto :eof) else echo %%a
if "%1" equ "" pause
[[i] 本帖最后由 pusofalse 于 2008-7-25 16:55 编辑 [/i]] [quote]原帖由 [i]youxi01[/i] 于 2008-7-25 08:23 发表 [url=http://bbs.bathome.net/redirect.php?goto=findpost&pid=5886&ptid=1239][img]http://bbs.bathome.net/images/common/back.gif[/img][/url]
不过有个疑问就是:效率是不是会非常低呢?特别是遭遇大文件时
根据代码的意思,似乎是查询两个文件行号一样的时候就分别写入到文件里
这样的话,要是第二个文件有1W行岂不是要比对1W次?这样,明显有9999次是没 ... [/quote]
我想在这里应该不有去考虑极端情况,比如特殊字符处理什么的。 既然这种最高效的方法也出来了(只可惜是版主级做出来的),下面就贴出本人的第二种方法:[code]@echo off
set "n=-1"&set "flag=a"
:begin
set /a n+=1
if %n% equ 0 (set "m=") else (set "m=skip=%n%")
for /f "%m% delims=" %%i in (1.txt) do echo %%i&if defined flag goto next
set no=a
:next
for /f "%m% delims=" %%i in (2.txt) do echo %%i&goto begin
if not defined no set "flag="&goto begin
pause>nul[/code] 为了减少不必要的调用,修改如下。[code]
@echo off&set n=-1
for /f "delims=" %%a in (1.txt) do (
set/a n+=1
set flag=
if not defined faith call :lp %%a
if not defined flag echo %%a
)
:lp
if "%1" equ "" set/a n+=1
set m=skip=%n%
if "%m%" equ "skip=0" set "m="
for /f "%m% delims=" %%a in (2.txt) do if "%1" neq "" (echo %1&echo %%a&set flag=a&goto :eof) else echo %%a
set faith=faith
if "%1" equ "" pause[/code] 再次提示:
第三种方法可就本题而言来解(不考虑行数太多的情况) @echo off
for /f "tokens=1* delims=:" %%i in ('findstr /n .* 1.txt') do set _%%i=%%j
for /f "tokens=1* delims=:" %%k in ('findstr /n .* 2.txt') do set _%%k.%%k=%%l
for /f "tokens=1* delims==" %%i in ('set _ ') do echo %%j
pause
要是就本题的几行上面的还行 把两个文本的相同行交叉合并,需要考虑以下两种情况:
1、两个文本的行数相同;
2、两个文本的行数不同。
如果两个文本行数相同,则可以省略对文本行数的判断,但考虑到效率高低,需要使用临时文件,则可使用如下代码:[code]@echo off
findstr .* 1.txt>_1.txt
setlocal enabledelayedexpansion
for /f "delims=" %%i in (2.txt) do (
set /a num+=1
echo !num!:%%i
findstr /b /i "!num!:" _1.txt
)
del /q _1.txt
pause[/code] 如果两个文本行数不同,则需要判断行数谁多谁少,从而减少对比次数,演示代码如下:[code]@echo off
:: 生成临时文件,主要是为了获得 行数:行内容 格式的文本
findstr /n .* 1.txt>_1.txt
findstr /n .* 2.txt>_2.txt
:: 获取各自的总行数
for /f "delims=:" %%i in (_1.txt) do set num_1=%%i
for /f "delims=:" %%i in (_2.txt) do set num_2=%%i
:: 比较行数谁多谁少
set num=%num_1%
set file_1=_1.txt&set file_2=_2.txt
if %num_1% geq %num_2% (
set num=%num_2%
set file_1=_2.txt&set file_2=_1.txt
)
:: 以行数少的文本为标准,交叉输出两文本的同行内容
for /f "tokens=1* delims=:" %%i in (%file_1%) do (
echo %%i:%%j
findstr /b /i "%%i:" %file_2%
)
:: 对多出的行内容,一次性输出,减少了对比次数,从而提高效率
more +%num% %file_2%
del /q _1.txt _2.txt
pause[/code] 如果不动用临时文件,要么需要设置大量的变量,严重消耗系统内存;要么需要用 if 语句对行号进行机械对比,严重影响效率;如果使用 set 排序方案,则要求每个文本的总行数不能超过9行,并且不能保证某个文件的行内容总是排在两行中的第一行或第二行。
注:以上代码都没有考虑特殊字符。 jm厉害,考虑这么全面。 最后给出本人的第三个方案,生成临时文件且通用性不很强,
解题思路和上面的完思路不同:[code]@echo off&setlocal enabledelayedexpansion
set "num=0"
for %%a in (1.txt 2.txt) do (
for /f "delims=" %%i in (%%a) do (
set /a n+=1
if !n! gtr !num! set "num=!n!"
set /p=%%i <nul>>temp.txt
)
echo.>>temp.txt&set "n=0"
)
:lp
set /a n+=1
for /f "tokens=%n%" %%i in (temp.txt) do echo %%i
if %n% neq %num% goto lp
del /q temp.txt&pause>nul[/code] 我的,有点晚:[code]@echo off&setlocal enabledelayedexpansion
set m=-1
for /f %%i in (1.txt) do set /a m+=2&set _!m!=%%i
for /f %%j in (2.txt) do set /a n+=2&set _!n!=%%j
if %m% gtr %n% (set max=%m%) else (set max=%n%)
for /l %%k in (1 1 %max%) do (
if defined _%%k call,echo %%_%%k%%
)
pause[/code] batman就是强!
我的跟batman的第一种方法(15楼)基本一样了。
batman的第二种方法(见18楼),更是高手典范。 呵呵,本人最老的一道题也被你们翻出来了,加油,有这股劲就对了! [code]
@echo off&setlocal enabledelayedexpansion
for /f "delims=" %%a in (1.txt) do (set /a n+=1&set #!n!=%%a)
for /f "delims=" %%a in (2.txt) do (
set/a m+=1
echo %%a
if defined #!m! for %%b in (!m!) do echo !#%%b!
)
set/a m+=1
for /l %%a in (!m!,1,!n!) do echo !#%%a!
[/code] 一百行以内[code]@echo off
for /f "tokens=1* delims=[]" %%a in ('find /v /n "" ?.txt^|findstr /b "\[[0-9]\]"^|sort') do echo.%%b >>out.txt
for /f "tokens=1* delims=[]" %%a in ('find /v /n "" ?.txt^|findstr /b "\[[0-9][0-9]\]"^|sort') do echo.%%b >>out.txt
pause[/code] 楼上的不一定会交替的吧?
有可能会这样的
a.txt 行
b.txt 行
b.txt 行
a.txt 行
页:
[1]
2