Board logo

标题: [文本处理] 批处理BAT如何按某字符多少排序? [打印本页]

作者: yhsean    时间: 2014-4-5 15:41     标题: 批处理BAT如何按某字符多少排序?

Toolpath\q\
Toolpath\q\fdf\
Toolpath\q\ewr\
Toolpath\eqwfqf\aff
Toolpath\2

有如上一文档,请问如何按照 \ 字符出现次数排序。排序后成如下:

Toolpath\q\ewr\                               \出现3次
Toolpath\eqwfqf\aff                          \出现2次
Toolpath\q\fdf\                                 \出现2次
Toolpath\q\                                      \出现2次
Toolpath\2                                       \出现1次
作者: xxpinqz    时间: 2014-4-5 16:18

凑合着用
  1. @echo off&setlocal enabledelayedexpansion
  2. %1(for /f "tokens=1*" %%a in ('%0 :^|sort /r^|more /t40')do set/am=%%a%%10000&echo,%%b!m!次)&pause&goto :eof
  3. for /f "delims=U" %%a in ('cmd /u /c echo 唉') do set "tab=%%a"
  4. for /f "delims=" %%a in (1.txt) do (
  5.     set "str=%%a"&set "str=!str:\= a!"&set n=99999
  6.     for %%b in (!str!) do set/an+=1
  7.     echo,!n! %%a%tab%\出现
  8. )
复制代码

作者: yhsean    时间: 2014-4-6 12:06

本帖最后由 yhsean 于 2014-4-6 12:08 编辑
  1. set/a n=-1
  2. set mystr=aa\bb\vv\cc\dd\aaa\
  3. setlocal enabledelayedexpansion
  4.    FOR /L %%i in (0,1,1000) do (                                                   
  5.       if "!mystr:~%%i,1!"=="\" set/a n=!n!+1                                            
  6.       if "!mystr:~%%i,1!"==""  echo !n!-%mystr%>>C:\dcam\before_sort && goto _endbefore_sort
  7.     )
  8. endlocal
  9. :_endbefore_sort
复制代码
谢谢,用自己的办法已经解决,没行前加上统计该字符的数字,然后用 sort/R 排序并去掉统计数字输出
作者: CrLf    时间: 2014-4-7 00:14

一如既往贴简单暴力的另类解...适用于行数不太多的文件,若要兼容特殊字符需改造,偷懒了:
  1. @echo off&setlocal enabledelayedexpansion >结果.txt
  2. (rd tmp&md tmp) >nul
  3. set /a n=10000
  4. for /f "delims=" %%a in (原文件.txt) do set /a n+=1&echo %%a>tmp\!n:~-4!
  5. (for /f "delims=" %%a in ('dir /o-s /b tmp\*) do type tmp\%%a)>结果.txt
  6. rd tmp >nul
复制代码

作者: CrLf    时间: 2014-4-7 00:46

这个用第三方挺爽的,兼容性和效率都没得说:
  1. awk "{print length($0),$0}" a.txt|gnu_sort -knr|sed "s/.....//"
复制代码
length 是 ps 文本对象的自带属性,因为能 sort 所以比 shell 更方便,不过会慢一点:
  1. get-content a.txt|sort-object length|%{$_.length," ",$_}
复制代码

作者: CrLf    时间: 2014-4-7 01:03

本帖最后由 CrLf 于 2014-4-7 02:48 编辑

js 的文本也是对象,相比之下会长一点,好处是很容易内嵌 bat 而且兼容性极佳,速度方面应该介于 5 楼的那两个方案之间。
  1. @set @n=0;/*
  2. @echo off
  3. cscript -nologo -e:javascript %0 <a.txt
  4. pause&exit /b
  5. */
  6. var str=WScript.StdIn.ReadAll().split('\n')
  7. str.sort(function(a,b){return a.length - b.length;})
  8. WScript.Echo(str.join('\n'))
复制代码

作者: CrLf    时间: 2014-4-7 01:52

vbs 略显操蛋,原本想找找有没简单的办法,最后又绕回 ado...
  1. [原文件] = "a.txt"
  2. [最大行长度] = 65535
  3. Set fso = WScript.CreateObject("Scripting.Filesystemobject")
  4. text = fso.OpenTextFile([原文件],1).ReadAll
  5. Set rec=CreateObject("ADODB.Recordset")
  6. rec.Fields.Append "String",200,[最大行长度]
  7. rec.Fields.Append "Length",200,Len([最大行长度])
  8. rec.Open
  9. For Each str In Split(text,vbCrLf)
  10. rec.AddNew
  11. rec.Fields("String") = str
  12. rec.Fields("Length") = Len(str)
  13. Next
  14. rec.Sort = "Length ASC"
  15. Do Until rec.EOF
  16. Wscript.Echo rec.Fields("String")
  17. rec.MoveNext
  18. Loop
复制代码

作者: terse    时间: 2014-4-7 09:56

觉得应该按 字符 "\" 的多少排列  不是字符哦
作者: apang    时间: 2014-4-7 10:53

本帖最后由 apang 于 2014-4-7 11:44 编辑
  1. @set @n=0;/*
  2. @echo off
  3. cscript -nologo -e:javascript %0 <a.txt >b.txt
  4. pause&exit /b
  5. */
  6. var str=WScript.StdIn.ReadAll().split('\n')
  7. str.sort(function(a,b){return b.split('\\').length-a.split('\\').length});
  8. WScript.Echo(str.join('\n'))
复制代码

作者: terse    时间: 2014-4-7 11:40

发个 PS脚本
  1. $Hash = @{}
  2. get-content .\a.txt | ? {
  3.    $Hash.ADD($_,$_.split("\").Count)
  4. }
  5. $hash.GetEnumerator()| Sort -Descending Value | select -ExpandProperty name
复制代码

作者: CrLf    时间: 2014-4-7 19:54

回复 8# terse


    没注意,既然这样...
    不贴另类解简直对不起党中央,简单方便妥妥的,go on:
for /l %%a in ""
  1. @echo off
  2. (rd tmp&md tmp) >结果.txt 2>nul
  3. set "list=\29\28\27\26\25\24\23\22\21\20\19\18\17\16\15\14\13\12\11\10\09\08\07\06\05\04\03\02\01\00"
  4. for /f "delims=" %%a in (原文件.txt) do (
  5. for /f "tokens=31 delims=\" %%b in (".%%a.%list%") do echo %%a>>tmp\%%b.txt
  6. )
  7. type tmp\*.txt>结果.txt 2>nul
  8. pause
复制代码
二号另类解,快速有效:
  1. @echo off&setlocal enabledelayedexpansion
  2. set "原文件=原文件.txt"
  3. set "结果=结果.txt"
  4. set "pattern=[^\\]*"
  5. for %%a in ("%原文件%") do set size=%%~za
  6. (for /l %%a in (1 1 50) do (
  7. for %%b in ("%结果%") do if %%~zb geq %size% exit/b
  8. findstr "^^!pattern!$" "%原文件%"
  9. set "pattern=!pattern!\\[^^\\]*"
  10. ))>"%结果%"
复制代码

作者: CrLf    时间: 2014-4-7 19:56

回复 9# apang


    话说感觉用 match 可能会比 split 快,只是猜测,未测试
作者: CrLf    时间: 2014-4-7 20:25

本帖最后由 CrLf 于 2014-4-7 20:54 编辑

高冷的 linux 舶来品实现起来如此简单,shell 真是文本专家(如需顺序,把  -nrk 1 换成 -nk 1):
  1. gawk -F"\\" "{print NF,$0}" 原文件.txt | gnu_sort.exe -nrk 1 | sed "s/[0-9] //" >结果.txt
复制代码
再来个纯 gawk 的(如需顺序,把 for(i=asort(ar);i;i--) 换成 for(i=1;i<asort(ar);i++)) :
  1. gawk -F "\\" "{ar[NF+100]=ar[NF+100] RS $0}END{for(i=asort(ar);i;i--) print ar[i];}" 原文件.txt
复制代码

作者: xxpinqz    时间: 2014-4-8 11:52

给几位大佬请安问好。。。。
作者: terse    时间: 2014-4-8 12:34

因10楼不能处理重复路径  再发个PS的
话说效率不怎么样
  1. $regex = [RegEx] '\\'
  2. $Filelist = get-content .\a.txt | % {
  3.       New-Object PSObject -Property @{
  4.          Name = $_
  5.          Value = $regex.Matches($_).Count
  6.       }
  7. } | sort -Descending Value
  8. $Filelist | group name|%{$_.Group}|%{$_.Name}|out-file -encoding ASCII "b.txt"
复制代码

作者: CrLf    时间: 2014-4-8 16:28

回复 14# xxpinqz


    不敢,看您老的注册时间,给跪了
作者: CrLf    时间: 2014-4-8 17:03

回复 15# terse


    可以直接用 sort:
  1. $regex = [RegEx] '\\';
  2. get-content a.txt | sort-object -Descending { $regex.Matches($_).Count }>b.txt
复制代码

作者: terse    时间: 2014-4-8 17:37

回复 17# CrLf
这就行了啊 学习了
作者: zhanglei1371    时间: 2014-4-8 22:08

回复 2# xxpinqz


    请教下:for /f "delims=U" %%a in ('cmd /u /c echo 唉') do set "tab=%%a"是何意?有何用处?
作者: CrLf    时间: 2014-4-8 22:51

回复 19# zhanglei1371


    用于取得 tab 制表符,这是 plp626 发明的方法引伸出来的。
    原理是:"唉" 的 unicode 编码为 09 55,所以只要以 0x55(即字母 U) 为分隔符就能取得 tab 制表符
作者: zhanglei1371    时间: 2014-4-9 07:13     标题: 标题

回复 20# CrLf


    谢谢回答,这个问题我知道了。不过我还有些引申的问题:
1.如何快速获取某字符的unicode码?
2.其他的任意特殊字符如回车换行是否也能以这种方式间接得到?
作者: CrLf    时间: 2014-4-9 14:27

回复 21# zhanglei1371


    xp 还是 win7
作者: zhanglei1371    时间: 2014-4-9 15:47

回复 22# CrLf


    xp
作者: CrLf    时间: 2014-4-9 16:31

本帖最后由 CrLf 于 2014-4-9 16:44 编辑

回复 23# zhanglei1371


    NUL、LF 不行,因为 NUL 在变量表里是变量分隔符,而 LF 是 for /f 的行分隔符,其他好像都可以,我是这么获取的(半手工):
  1. const c='\\';
  2. main(){
  3.    int i;
  4.    printf("%c%c",0xff,0xfe);
  5.    for(i=1;i<0x20;i++){
  6.       printf("%c%c",c,i);
  7.       printf("%c%c",i,c);
  8.    }
  9. }
复制代码
  1. tcc -run a.c>a.txt
复制代码
然后用 notepad2 打开 a.txt,将 ? 全文替换为空,就得到 hex 从 2E01~2E09 以及 0A2E~0E1F 的字符串了,以下:
  1. 封専尃射尅将將專尉尊尋尌對導小尐少尒尓尔尕尖尗尘尙尚尛尜尝尞尟尠
复制代码
但 for /f 以换行符分割行,所以其中的“尊”字要换成这个字符串里其他任意一个字,也就是说除了换行符,0x01~0x1F 都能取得
举个栗子:
  1. @echo off
  2. for /f "tokens=0x09 delims=\" %%a in ('cmd /u /c echo 封専尃射尅将將專尉尉尋尌對導小尐少尒尓尔尕尖尗尘尙尚尛尜尝尞尟尠') do echo 制表符:[%%a]
  3. ::上例仅作演示用,其实如果只需要取特定字符,可以只用简化成这样:
  4. for /f "delims=\" %%a in ('cmd /u /c echo 尉') do echo 制表符:[%%a]
  5. pause
复制代码
至于换行符,有更简单的获取方式:
  1. @echo off
  2. set 换行符=^
  3. setlocal enabledelayedexpansion
  4. echo 123!换行符!456
  5. pause
复制代码
如想用 %换行符% 的格式引用,见 http://bbs.bathome.net/viewthread.php?tid=20262

还有一种 chcp 的办法,见 http://bbs.bathome.net/viewthread.php?tid=12347,事实上刚才讨论的 cmd /u /c echo 的方案也出自此贴
两种方案虽然都能得到特殊字符,但原理迥异, chcp 的办法是利用各代码页语言不通的障碍来拆字,而 cmd /u /c 的办法则是用不同编码格式的差异来将字符重组。
前者不受本地语言设置的约束,应可全球通用,但需要将文字事先写入 bat 中,而且需要来回切换代码页,后者则无此限制。
作者: apang    时间: 2014-4-9 16:36

回复 12# CrLf


    简单测试了一下,貌似 split 快?
  1. @echo off
  2. more +4 %0 >a.txt
  3. for /l %%a in (1 1 8) do type a.txt>>$ & type $>>a.txt
  4. del $ & pause & exit /b
  5. Toolpath\q\
  6. Toolpath\q\fdf\
  7. Toolpath\q\ewr\
  8. Toolpath\eqwfqf\aff
  9. Toolpath\2
复制代码
  1. @set @n=0;/*
  2. @echo off
  3. cscript -nologo -e:javascript %0 <a.txt
  4. pause&exit /b
  5. */
  6. var t = new Date().getTime();
  7. var str=WScript.StdIn.ReadAll().split('\n')
  8. str.sort(function(a,b) {return (b+'\\').match(/\\/g).length-(a+'\\').match(/\\/g).length});
  9. WScript.Echo(str.join('\n'))
  10. WScript.Echo(new Date().getTime()-t)
复制代码

作者: CrLf    时间: 2014-4-9 16:51

本帖最后由 CrLf 于 2014-4-9 17:03 编辑

回复 25# apang


    还真是!这是为什么!!why...
作者: zhanglei1371    时间: 2014-4-9 18:34

回复 24# CrLf


    Many Thx!学得了不少东西……




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