标题: [文本处理] 批处理如何将txt文本里的所有重复行排到文本前端? [打印本页]
作者: a4620269 时间: 2009-2-27 19:07 标题: 批处理如何将txt文本里的所有重复行排到文本前端?
本帖最后由 pcl_test 于 2016-9-6 19:47 编辑
txt 文本排版批处理求救(上万行的)
例如文本内容是:
1111
2222
3333
3333
4444
5555
4444
我想把重复的文本排在所有文本的前面,得到新的文本文件如下(不用做排序,乱的就行,只要在前面):
3333
3333
4444
4444
1111
2222
5555
求教,感激不尽万行
[ 本帖最后由 a4620269 于 2009-2-27 20:13 编辑 ]
作者: batman 时间: 2009-2-27 19:33
本代码可适用于多次重复的情况- @echo off&setlocal enabledelayedexpansion
- for /f "delims=" %%a in (a.txt) do set /a _%%a+=1
- for /f "delims=_=" %%a in ('set _') do (
- if !_%%a! neq 1 (
- for /l %%b in (1,1,!_%%a!) do echo %%a
- ) else (
- set /a n+=1&set "_!n!=%%a"
- )
- )
- for /l %%a in (1,1,!n!) do echo !_%%a!
- pause>nul
复制代码
[ 本帖最后由 batman 于 2009-2-27 20:25 编辑 ]
作者: a4620269 时间: 2009-2-27 19:38 标题: 回复 2楼 的帖子
太厉害了,但是我得不到bat 里的文本,怎么办
作者: batman 时间: 2009-2-27 19:40
原帖由 a4620269 于 2009-2-27 19:38 发表
太厉害了,但是我得不到bat 里的文本,怎么办
把 echo *改成echo *>>b.txt
作者: a4620269 时间: 2009-2-27 19:47 标题: 回复 4楼 的帖子
有三个 echo 我不知改哪个
能不能来个全的
作者: lhjoanna 时间: 2009-2-27 19:53
除了@echo off中的echo,都改为echo *>>tmp.txt
作者: terse 时间: 2009-2-27 20:02
Re: batman兄
一个 set/a "_%%a+=1 就够了哦
作者: a4620269 时间: 2009-2-27 20:09
处理几十行没问题,我这上万行的文件一开bat 就没反映了,有什么好的办法,我电脑配置也不低,3G内存
作者: Batcher 时间: 2009-2-27 20:11 标题: 回复 8楼 的帖子
建议在顶楼更新帖子,说明需要处理“万行的文件”,以便他人针对你的具体情况给出合适的方案。
作者: batman 时间: 2009-2-27 20:26
原帖由 terse 于 2009-2-27 20:02 发表
Re: batman兄
一个 set/a "_%%a+=1 就够了哦
兄所言即是,已修改,写代码时未及细作,惭愧。。。。
作者: a4620269 时间: 2009-2-27 20:31 标题: 回复 10楼 的帖子
那么新的代码是什么呢
作者: namejm 时间: 2009-2-27 23:03
思路:先用sort把文本排序,这样,重复的行就前后相连,然后,用for来读取文本,判断上下句是否一致即可。
作者: Batcher 时间: 2009-2-28 00:16
- @echo off
- echo 一万行文本的测试结果
- echo 开始时间%time%
- sort a.txt>b.txt
- (for /f "delims=" %%a in (b.txt) do (
- if not defined %%a (
- set "%%a=1"
- ) else (
- echo.%%a
- )
- ))>c.txt
- findstr /x /g:c.txt a.txt>d.txt
- findstr /x /v /g:c.txt a.txt>>d.txt
- echo 结束时间%time%
- pause
复制代码
一万行文本的测试结果
开始时间 0:16:46.42
结束时间 0:16:55.21
Press any key to continue . . .
|
作者: terse 时间: 2009-2-28 00:37
假设要处理的文件为a.txt 运行前备份复制代码
另:
是否加个判断c.txt的生成呢 空就跳过FINDSTR 不然报错
[ 本帖最后由 terse 于 2009-2-28 00:47 编辑 ]
作者: Batcher 时间: 2009-2-28 10:40 标题: 回复 14楼 的帖子
感谢提醒。
没有重复行的时候,c.txt依然会生成,只不过为空而已。
干脆屏蔽算了。- @echo off
- echo 一万行文本的测试结果
- echo 开始时间%time%
- sort a.txt>b.txt
- (for /f "delims=" %%a in (b.txt) do (
- if not defined %%a (
- set "%%a=1"
- ) else (
- echo.%%a
- )
- ))>c.txt
- findstr /x /g:c.txt a.txt>d.txt 2>nul
- findstr /x /v /g:c.txt a.txt>>d.txt 2>nul
- echo 结束时间%time%
- pause
复制代码
作者: namejm 时间: 2009-2-28 12:20
把重复的行内容作为变量名不失为一种思路,但是会有如下缺陷:
1、如果重复内容过多,势必会有大量的变量产生,占用的内存将飙升——虽然目前上G的内存已成主流,但是,这上G的内存不应该只被自己的程序使用,而应该留出足够的内存给其他程序运行,大量命名变量乃编程大忌,当然,如果你只求结果而不管过程,或者并没有做程序员的想法,则可以忽略这一条;
2、变量名有自己的一套规则,有些字符是不能作为变量名的,比如&、|之类的特殊字符;如果要处理的文本中含有这些字符,则batcher的代码会出现问题——虽然在设置变量的时候用引号把 set 语句的部分内容括起来了,但是在用 if defined 语句判断变量名是否已经赋值的时候仍然会出错;(备注:此条表述有误,请看下一楼层zqz0012005的描述)
用顶楼的数据测试batcher的代码,发现4444这两行内容并没有在一起,原因有二:
1、findstr /x 做整句匹配的时候,是以行尾是否带回车换行符号作为判断依据的,而最后一行内容没有带回车换行符号,所以,findstr /x 不认为它是完整的一行内容,从而被忽略掉——我们常用 findstr /v $ 来提取最后一行的内容,也是基于这个原理;
2、findstr /g:c.txt a.txt 的时候,获取到的内容将以后一个文本内容的顺序提取,而不是第一个文本内容的顺序;也就是说,假如111、222分别位于c.txt的第一、二行,分别位于a.txt的第二、一行,那么,提取到的内容将是先222后111。这会产生什么后果呢?如果在顶楼给出的数据中,第一行之前插入5555,得出的结果中,5555并没有在一起。
要怎么解决这两个问题呢?一个简洁的办法是:先用sort对原始数据排序,然后,用for来读取文本,判断上下句是否一致,从而提取出重复的行内容;findstr /x 的时候,以排序后的内容作为查找对象,而不是以原始文本作为对象。代码如下(此代码的执行结果会对数据进行排序,出于效率考虑,没有兼容感叹号):- @echo off
- echo 一万行文本的测试结果
- echo 开始时间%time%
- sort a.txt>b.txt
- cd.>c.txt
- setlocal enabledelayedexpansion
- for /f "delims=" %%i in (b.txt) do (
- if "!str!"=="%%i" (echo !str!)>>c.txt
- set "str=%%i"
- )
-
- for %%i in (c.txt) do if "%%~zi"=="0" goto end
-
- findstr /x /g:c.txt b.txt>d.txt
- findstr /x /v /g:c.txt b.txt>>d.txt
- start d.txt
-
- :end
- echo 结束时间%time%
- pause
复制代码
作者: zqz0012005 时间: 2009-2-28 14:47 标题: 回复 16楼 的帖子
把重复的行内容作为变量名,第二个缺陷其实不存在。
特殊字符在设置变量的时候用引号把 set 语句的部分内容括起来了,固然应该这样做;而在用 if defined 检测变量时,利用for的中间变量:if defined %%i,同样不会因为特殊字符而出错。
作者: namejm 时间: 2009-2-28 14:59
嗯,用 if defined %%i 的格式确实不会因为特殊字符而出错,看来是我搞错了。
作者: Batcher 时间: 2009-2-28 15:13 标题: 回复 16楼 的帖子
1、如果重复内容过多,势必会有大量的变量产生,占用的内存将飙升——虽然目前上G的内存已成主流,但是,这上G的内存不应该只被自己的程序使用,而应该留出足够的内存给其他程序运行,大量命名变量乃编程大忌,当然,如果你只求结果而不管过程,或者并没有做程序员的想法,则可以忽略这一条;
这一条是不能忽略的,因为批处理是不允许无限制地定义变量的。
http://technet.microsoft.com/en-us/library/bb490954.aspx
The maximum individual environment variable size is 8192bytes.
The maximum total environment variable size for all variables, which includes variable names and the equal sign, is 65,536KB.
用顶楼的数据测试batcher的代码,发现4444这两行内容并没有在一起,原因有二:
感谢提醒,代码更改如下:- @echo off
- echo 一万行文本的测试结果
- echo 开始时间%time%
- cd.>>a.txt
- sort a.txt>b.txt
- (for /f "delims=" %%a in (b.txt) do (
- if not defined %%a (
- set "%%a=1"
- ) else (
- echo.%%a
- )
- ))>c.txt
- findstr /x /g:c.txt b.txt>d.txt 2>nul
- findstr /x /v /g:c.txt b.txt>>d.txt 2>nul
- echo 结束时间%time%
- pause
复制代码
作者: zqz0012005 时间: 2009-2-28 15:24
jm的代码应该是最合适的。
关于最后一行不是以回车换行符结束的问题,可以用more读文本内容再用管道传递给findstr(虽然用管道会降低速度)。
以前用more时无意中发现它会自动在最后加一个回车换行符。开始不知道more的这一特点,导致我当时的一个代码测试很久都不成功,所以对这一点印象很深刻。
2、findstr /g:c.txt a.txt 的时候,获取到的内容将以后一个文本内容的顺序提取,而不是第一个文本内容的顺序。
的确,如果不先给a.txt排序的话,findstr /g:c.txt a.txt 这一句虽然提取出重复行排在文本前面,但还是无法让它们相邻(它们仍是按原来的次序排列)。
[ 本帖最后由 zqz0012005 于 2009-2-28 15:26 编辑 ]
作者: pcl_test 时间: 2016-9-6 22:22
- //&cls&cscript -nologo -e:jscript "%~f0"&pause&exit
-
- var fso = new ActiveXObject('Scripting.FileSystemObject');
- var file = '文本.txt';
- var a={};
- var f = fso.OpenTextFile(file, 1);
- while(!f.AtEndOfStream){
- var str = f.ReadLine();
- a[str]?a[str]++:a[str]=1;
- }
- f.Close();
- var c={}, e=[];
- for(var b in a){
- if(!c[a[b]]){
- c[a[b]]=[];
- e.push(a[b]);
- }
- c[a[b]].push(b);
- }
- e.sort(function(a,b){return b-a});
- var f = fso.CreateTextFile('New_'+file, 2);
- for(var i=0;i<e.length;i++){
- for(var j=0;j<c[e[i]].length;j++){
- for(var k=0;k<e[i];k++)f.WriteLine(c[e[i]][j]);
- }
- }
- WSH.echo('Done');
复制代码
作者: pcl_test 时间: 2016-9-7 00:05
第三方http://www.bathome.net/s/tool/index.html?key=gawk- #*&cls&gawk -f "%~f0"&pause&exit
-
- BEGIN{
- file="文本.txt";
- while(getline<file>0)a[$0]++;
- for(b in a){c[a[b]]=c[a[b]]"\n"b;if(!d[a[b]])d[a[b]]=a[b]}
- for(i=asort(d);i>0;i--){
- split(substr(c[d[i]], 2), list, "\n");
- for(j=1;j<=length(list);j++){
- for(k=1;k<=d[i];k++)print list[j]>"New_"file;
- }
- delete list;
- }
- print "Done";
- }
复制代码
欢迎光临 批处理之家 (http://www.bathome.net/) |
Powered by Discuz! 7.2 |