Board logo

标题: [文本处理] [已解决]批处理如何查找出文本中字符数最多的行/字符串长度最长的行 [打印本页]

作者: 慕夜蓝化    时间: 2015-3-9 10:29     标题: [已解决]批处理如何查找出文本中字符数最多的行/字符串长度最长的行

本帖最后由 慕夜蓝化 于 2020-9-29 17:35 编辑

BAT如何找出文本最大行?
有一小说文本开头部分:
  1.   文本豪客 [url]www.txt.hk[/url] 〓 [url]www.bbzw.net[/url] 拜拜中文
  2.   作品:堕落血天使
  3.   作者:天龙怒吟
  4.   男主角:楚明
  5.   内容简介:
  6.   堕落血天使,是天龙怒吟写的一部西方奇幻小说,主要讲述的是一个中国小鬼学了一身杂七杂八的武功,把各种西方大神揍的满头是包的故事。
  7.   正文
  8.   背景设定
  9.   天使等级的划分
复制代码
要求:
在批处理窗口中直接显示字数最长的行。
比如这一行:
  1. 堕落血天使,是天龙怒吟写的一部西方奇幻小说,主要讲述的是一个中国小鬼学了一身杂七杂八的武功,把各种西方大神揍的满头是包的故事。
复制代码
若具有相同字数的最大行,则全部显示。
比如这两行:
  1.   首先,在没有形成整个世界的时候,创世之神,生命之神,破灭之神从混沌开始初生,三位大神并称为第一代神,也就是最原始的神。
  2.   我们不能说毁灭就是邪恶的,因为,如果没有毁灭,也就没有了创造的意义,就正如没有生命的死亡,这个世界将无限的堆满了人群。
复制代码
求解。
作者: cobat    时间: 2015-3-9 11:45

本帖最后由 cobat 于 2015-3-14 09:21 编辑

看11楼和19楼
作者: pcl_test    时间: 2015-3-9 12:29

本帖最后由 pcl_test 于 2015-3-9 12:34 编辑

回复 1# 慕夜蓝化
一般思路,逐行读取逐行统计字符数,并在每行标记上字符数(可用变量存储也可导出到临时文件),以标记的字符数进行排序取得最大值,用findstr "最大值" "文本"获得所有字符数最多的行
求字符串长度方法
http://www.bathome.net/viewthread.php?tid=11799
作者: 慕夜蓝化    时间: 2015-3-9 13:07

回复 3# pcl_test

嗯嗯,我去看一下。
主要速度快就成。
作者: pcl_test    时间: 2015-3-9 13:59

回复 4# 慕夜蓝化
另一种思路,先set max=0,逐行读取逐行统计字符数并标记好字符数,同时以辗转比较和赋值max的方式获取到最大值(如第一行字符数为23,23比max初值大,set max=23,第二行字符数为11,比max小,忽略,第三行字符数为40,比max大,set max=40……以此类推),用findstr "最大值" "文本"获得所有字符数最多的行
作者: cobat    时间: 2015-3-9 14:19

回复  慕夜蓝化
一般思路,逐行读取逐行统计字符数,并在每行标记上字符数(可用变量存储也可导出到临时文 ...
pcl_test 发表于 2015-3-9 12:29



    那贴的写法我没看懂,意思差不多对.
作者: CrLf    时间: 2015-3-9 15:36

回复 5# pcl_test


    不用 findstr 也行,设 max 的时候顺便设一个 maxline=%%a 就好
作者: pcl_test    时间: 2015-3-9 16:14

回复 7# CrLf
findstr是考虑max不止一行,而在运行过程中我们都不知道下一行是不是max的一行
作者: CrLf    时间: 2015-3-9 16:15

回复 8# pcl_test


    那可以这样:
maxline=!maxline!!换行!%%a
作者: 慕夜蓝化    时间: 2015-3-9 17:54

如果排除查找相同数的最大行数,第二种应该说最快了。
  1. @echo off&setlocal enabledelayedexpansion
  2. for /f "delims=" %%i in (a.txt) do (
  3.     for /f "delims=:" %%a in ('(echo,%%i^&echo,^)^|findstr /o "."') do set/a len=%%a-3
  4.     if not defined max set max=!len!
  5.     if !len! geq !max! set max=!len!&set "#=%%i"
  6.     )
  7.     echo,%#%
  8. pause
复制代码
  1. @echo off&setlocal enabledelayedexpansion
  2. for /f "delims=" %%i in (堕落血天使.txt) do (
  3.     set/a len=0&set "str=%%i$"
  4.     for %%a in (4096,2048,1024,516,258,126,64,32,16,8,4,2,1) do (
  5.         if not "!str:~%%a!"=="" set/a len+=%%a&set str=!str:~%%a!
  6.     )
  7.     if not defined max set max=!len!
  8.     if !len! geq !max! set max=!len!&set "#=%%i"
  9.     )
  10. echo,%#%
  11. pause
复制代码

作者: apang    时间: 2015-3-9 18:08

本帖最后由 apang 于 2015-3-12 19:51 编辑
  1. @echo off & setlocal enabledelayedexpansion
  2. set Lf=^
  3. for /f "delims=" %%a in (a.txt) do (
  4.         set "s=%%a"
  5.         set "Len=0"
  6.         for %%b in (4096 2048 1024 512 256 128 64 32 16) do (
  7.                 if "!s:~%%b!" NEQ "" set /a Len+=%%b & set "s=!s:~%%b!"
  8.         )
  9.         set "s=!s!fedcba9876543210"
  10.         set /a Len+=0x!s:~16,1!
  11.         if !Len! GEQ !Max! (
  12.                 for %%b in (!Len!) do set "_%%b=!_%%b!%%a!Lf!"
  13.                 set "Max=!Len!"
  14.         )
  15. )
  16. echo,!_%Max%!
  17. pause
复制代码
发现 set /a Len+=0x!s:~15,1! 是错误的,改一下,顺便改一下if判断逻辑
作者: apang    时间: 2015-3-9 18:18

本帖最后由 apang 于 2015-3-9 18:39 编辑

好像也可以这样:
  1. @set @n=0;// & cscript -nologo -e:jscript "%~0" < a.txt & pause & exit
  2. s = WScript.StdIn.ReadAll() + "\r\n";
  3. ar = s.split("\r\n").sort(function(x,y){return y.length-x.length});
  4. for (i=0; i<ar.length-1; i++) {
  5.         WScript.Echo(ar[i]);
  6.         if (ar[i].length != ar[i+1].length) break;
  7. }
复制代码

作者: cobat    时间: 2015-3-9 19:44

本帖最后由 cobat 于 2015-3-9 19:48 编辑

回复 11# apang


    又学到了,换行符好像可以直接赋值?
作者: CrLf    时间: 2015-3-9 19:51

回复 13# cobat


    变量表中除了分隔符 00 字符外,其他字符都可以保存到变量中
作者: cobat    时间: 2015-3-9 19:55

本帖最后由 cobat 于 2015-3-9 20:02 编辑

回复 14# CrLf


    学习了,频繁的用call有没有问题,延迟变量在标签里是什么情况.不懂的太多了.
作者: CrLf    时间: 2015-3-9 20:20

本帖最后由 CrLf 于 2015-3-9 20:21 编辑

回复 15# cobat


环境变量的本质是一张连续的变量表,比如
  1. set 变量1=变量内容1
  2. set 变量2=变量内容2
复制代码
假设当前环境下只有这两个变量的话,那么整张表在内存中的表现是:
  1. 变量1=变量内容1(null)变量2=变量内容2(null)(null)
复制代码
(null) 表示 00 字符,连续两个 (null) 表示变量表结束
读写变量的时候就是不停检索等号前有没有相同的名称,匹配的话就输出后面的内容直到 (null)
这个逻辑在 xp 下很严格,win7 环境中则有诡异的表现,应该是个 bug

setlocal 其实是在当前变量表的基础上复制一张变量表,所有改动都在“分身”上进行,这张新的变量表直到文件末尾或碰到 endlocal 才会销毁
变量表最多同时存在 32 张,每次 call 之后可单独计算

提到变量,这里有几个旧帖值得一看,作者都是牛逼人物...
qzwqzw: [讨论]环境变量的存储(5-18更新)
caruko:批处理变量表机制的猜测及测试
plp626:扩展ASCII码字符集0x00~0xff 批处理获取函数
记得 demon 也有提到过变量,现在找不到帖子了
作者: cobat    时间: 2015-3-9 20:25

回复 16# CrLf


   谢谢,先收藏了慢慢看.
作者: caruko    时间: 2015-3-10 09:06

用 findstr /N /O ,读取字符偏移量,然后取出最大的行,无需计算字符长度。
作者: caruko    时间: 2015-3-10 09:58

  1. @echo off&setlocal enabledelayedexpansion
  2. set /a offset=0,len=0,max=0
  3. for /f "tokens=1,2* delims=:" %%a in ('findstr /N /O .*  文本.txt') do (
  4. set /a len=%%b-offset,offset=%%b
  5. set "#%%a=%%c"
  6. if !len! geq !max! (
  7. set /a max=len,row=%%a-1
  8. for %%K in (!max!) do set "_%%K=!_%%K!,!row!"
  9. )
  10. )
  11. for %%a in (!_%max%!) do echo,行数【%%a】,长度【%max%】,内容【!#%%a!】
  12. pause
复制代码

作者: cobat    时间: 2015-3-10 16:03

回复 19# caruko


    为什么会这么快,不是说findstr很慢?
作者: CrLf    时间: 2015-3-10 16:57

回复 20# cobat


    外部命令的特点是启动慢,执行快…
    话说你在15楼问的是什么意思哦
作者: cobat    时间: 2015-3-10 17:13

回复 21# CrLf

是不是计算单个字符串长度用strlen,文本里就用findstr /o
在看两个讲批处理效率的帖子,不能在for里用call
setlocal没搞懂在子批处理里面是什么情况呢?
作者: CrLf    时间: 2015-3-10 18:49

本帖最后由 CrLf 于 2015-3-10 18:57 编辑

回复 22# cobat


    call 执行起来很慢,其实还是看需求,一般情况下低效率的脚本都是让人难以容忍的
    每次使用外部命令都得尽可能压榨它的潜力,启动慢的命令都要避免频繁调用,但如果调用次数不多就没关系
http://www.bathome.net/viewthread.php?tid=15011
作者: apang    时间: 2015-3-10 18:50

本帖最后由 apang 于 2015-3-10 18:52 编辑

findstr /o 得到的是字节数,不是字符数,难道是我记错了?好像文本最后还需要两个回车换行,否则最后一行获取不到
作者: caruko    时间: 2015-3-12 11:08

回复 20# cobat


    因为代码只执行了 一次 findstr ,慢也超不过半秒。

     而其它代码效率高,足够把效率追回来。
作者: 慕夜蓝化    时间: 2015-3-12 11:33

回复 23# CrLf

call 真的很慢....我之前写的时候经常用它,不过现在也在学着避免使用call
改用for 之类的来替换。
作者: caruko    时间: 2015-3-12 16:18

回复 24# apang


    的确是,这个忘记了。 不过不影响长度判断。 最后一行可以用%%~ta -2 (减去回车换行字节) 再减去最后一行的offset 。
作者: apang    时间: 2015-3-12 20:05

回复 27# caruko


    嗯嗯,%%~za

话说本帖浏览超过1000次,火火的
作者: CrLf    时间: 2015-3-13 00:56

回复 27# caruko


    findstr /o 有个陷阱,对同时存在 \r\n 和 \n 两种换行方式的文本比较难以区分
作者: 无名小卒    时间: 2015-3-14 07:14

本帖最后由 无名小卒 于 2015-3-14 07:40 编辑

@echo off&setlocal enabledelayedexpansion
set ling=0
:⊙﹏⊙ 新人 大神勿喷
md lingmou
for /f "delims=" %%i in (堕落血天使.txt) do (
    set /a ling+=1
    echo %%i
)>.\lingmou\ling!!.txt
cd .\lingmou
for %%i in ('dir /d /o:-s ') do (
set "xy=%%i"
set xie=%%zi
set /a h+=1
if !h!=1 set  " t=%%zi"
if !xie!==!t! call :tong !xy!
)
exit
:tong
type %1
type
作者: tigerpower    时间: 2015-3-16 17:16

Windows Vista以上版本运行以下命令:
  1. powershell -C "$m=$r=$null;gc a.txt|%{$d=$_.length;if($d -gt $m){$r=$_;$m=$d}elseif($d -eq $m){$r+=\"`n\"+$_}};\"/* 一行最多{0}字 */`n\" -f $m;$r"
复制代码

作者: CrLf    时间: 2015-3-16 18:51

回复 31# tigerpower


    用 Object-Group 可能更方便
作者: tigerpower    时间: 2015-3-16 21:59

本帖最后由 tigerpower 于 2015-3-16 22:52 编辑

的确可以用Group-Object:
  1. powershell -C "$r=gc a.txt|group length|sort @{e={$_.name -as [int]}}|select -last 1;\"/* 一行最多{0}字 */`n\" -f $r.name;$r.group"
复制代码
或者
  1. powershell -C "$r=gc a.txt|group length;$r=$r|?{$_.name -eq ($r|measure name -max).maximum};\"/* 一行最多{0}字 */`n\" -f $r.name;$r.group"
复制代码

作者: terse    时间: 2015-3-16 22:26

也来个POWERSHELL 直接SORT
  1. $r = $(gc a.txt | sort { $_.length })[-1]
  2. $r
复制代码

作者: CrLf    时间: 2015-3-17 05:10

回复 34# terse


    改写个支持多行的
  1. (gc a.txt | sort -desc | group length | select -first 1).group
复制代码

作者: tigerpower    时间: 2015-3-17 09:58

本帖最后由 tigerpower 于 2015-7-4 07:15 编辑

sort后需加个length
  1. (gc a.txt | sort -desc length | group length | select -first 1).group
复制代码
或者不用group和sort:
  1. $r=gc a.txt;$m=($r|measure length -max).maximum;$r|?{$_.length -eq $m}
复制代码

作者: terse    时间: 2015-3-17 12:40

回复 35# CrLf
不知改下顺序 有区别不
  1. (gc at.txt | group length| sort Count|select -Last 1).group
复制代码

作者: CrLf    时间: 2015-3-17 14:05

回复 37# terse


    不是 count,是 name。这样写逻辑上更快,但我昨天试了一下发现 name 是字符串,100<2
作者: CrLf    时间: 2015-3-17 14:06

回复 36# tigerpower


    是的,感谢指正
作者: terse    时间: 2015-3-17 15:52

回复 38# CrLf
Count 不是字符串
作者: CrLf    时间: 2015-3-17 18:01

本帖最后由 CrLf 于 2015-3-17 18:05 编辑

回复 40# terse


    但 count 是 group 的长度,不是字符串的长度,用 count 排序得到的是最多匹配的 group
    应该可以在 sort 里处理 name 再排序,就像 ren 正则替换那样
作者: terse    时间: 2015-3-17 22:21

回复 41# CrLf
脑子短路 顺序还是不能调
  1. (gc a.txt |sort length|group length| select -Last 1).group
复制代码

作者: CrLf    时间: 2015-3-17 22:57

回复 42# terse


    试了一下,可以这样:
  1. (gc a.txt | group length| sort {[int32]$_.name}|select -last 1).group
复制代码

作者: pcl_test    时间: 2016-8-15 00:01

第三方http://www.bathome.net/s/tool/index.html?key=gawk
  1. @echo off
  2. gawk "{len=length($0);a[len]=a[len]?a[len]\"\n\"$0:\"\"$0;if(len>max)max=len;}END{print a[max]}" "a.txt"|find /v ""
  3. pause
复制代码





欢迎光临 批处理之家 (http://www.bathome.net/) Powered by Discuz! 7.2