[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖
本帖最后由 aloha20200628 于 2024-5-12 16:16 编辑

回复 1# 娜美

        powershell确实为转换文件编码提供了.net资源中可靠而高效的方法,但未能直接提供准确率较高的文件编码‘推测’方法。目前已被业界广为采用的文件编码‘推测’方法是源自火狐(firefox)提供的开源代码(如python/c#/java等已均有成熟的接口),还可从有关网站下载其专门编译好的命令行实用工具。如果已经安装了python环境及其chardetect应用,即可直接在其安装主目录下找到...\Scripts\chardetect.exe,用其在命令行直接运行即可获取指定文本文件的编码‘推测’结果。另一个便捷方法是从网址》https://github.com/JetDemo/uchardet 下载源自火狐开源代码采用c++编译好的命令行实用工具 uchardet.exe。
        以下给出的批处理代码就是利用uchardet.exe的‘推测’结果,据此调用powershell的[io.file]方法,实现 utf-8/utf-8+BOM/utf-16le/utf-16be 到简中编码(gb2312)的高速转换,顺便修复了源文件中的unix换行符,生成最终结果文件allinOne.txt。代码中另外附加了文件名分隔标注行,如不需要可删除第4行。
  1. @echo off &setlocal &del /q "allinOne.txt" "bug.txt" 2>nul
  2. for /f "delims=" %%F in (b.txt) do if not exist "%%~F" (echo,"badFile -- %%F"&echo,%%F>>"bug.txt") else (
  3. for /f "tokens=1-2 delims=-" %%a in (' uchardet.exe "%%~F" ') do (
  4. if /i "%%a" neq "unknown" (echo, /// %%~F ///>>"allinOne.txt")
  5. if /i "%%a"=="utf" if "%%b"=="8" (
  6. powershell "$s=[io.file]::readalllines('%%~F',[text.encoding]::utf8);[io.file]::appendalllines('allinOne.txt',$s,[text.encoding]::default)"
  7. ) else if /i "%%a"=="utf" if "%%b"=="16" (
  8. powershell "$s=[io.file]::readalllines('%%~F',[text.encoding]::unicode);[io.file]::appendalllines('allinOne.txt',$s,[text.encoding]::default)"
  9. )
  10. if /i "%%a"=="ascii" (
  11. more "%%~F">>"allinOne.txt"
  12. ) else if /i "%%a"=="gb18030" (
  13. more "%%~F">>"allinOne.txt"
  14. ) else if /i "%%a"=="unknown" (
  15. echo,"unknown -- %%F"&echo,%%F>>"bug.txt"
  16. )
  17. )
  18. echo,>>"allinOne.txt"
  19. )
  20. endlocal&pause&exit/b
复制代码
1

评分人数

    • 77七: 感谢分享, uchardet好用!技术 + 1

TOP

本帖最后由 aloha20200628 于 2024-5-12 16:14 编辑

回复 9# 娜美

楼主随便看看有关‘文件编码识别’为何至今未有终解的网页论述即知其中一二了...
好吧再给一个简单版本,就用本坛可下载的coder.exe置换3楼代码中的uchardet.exe,因前者不排查非文本文件类型故可使3楼代码进一步简化...
有劳powershell用.net的[io.file]方法,把utf-8/utf-8+BOM‘兄弟俩’一锅烩了,把utf-16be/utf-16le‘兄弟俩’也一锅烩了,为码农省事了...
  1. @echo off &setlocal &del /q "allinOne.txt" "bug.txt" 2>nul
  2. for /f "delims=" %%F in (b.txt) do if not exist "%%~F" (echo,"badFile -- %%F"&echo,%%F>>"bug.txt") else (
  3. for /f "tokens=1 delims=_" %%a in (' coder.exe -s -a gc -f "%%~F" ') do (
  4. echo, /// %%~F ///>>"allinOne.txt"
  5. if /i "%%a"=="utf-8" (
  6. powershell "$s=[io.file]::readalllines('%%~F',[text.encoding]::utf8);[io.file]::appendalllines('allinOne.txt',$s,[text.encoding]::default)"
  7. ) else if /i "%%a"=="utf-16" (
  8. powershell "$s=[io.file]::readalllines('%%~F',[text.encoding]::unicode);[io.file]::appendalllines('allinOne.txt',$s,[text.encoding]::default)"
  9. ) else if /i "%%a"=="ansi" (more "%%~F">>"allinOne.txt")
  10. )
  11. echo,>>"allinOne.txt"
  12. )
  13. endlocal&pause&exit/b
复制代码

TOP

回复 11# 娜美

8楼代码段 for /r %%a in (*.txt) 只能获取按文件名升序排列的全路径文件名列表,效果与 dir /b/s/a-d *.txt 相同,1楼b.txt中的文件名被人为排序显然与其不符。在命令行运行 dir /? 即可了解》采用 dir 获取文件名列表可通过 文件名或扩展名升降序/文件尺寸/时间属性 来调整排序结果,没有其他更便捷的方法了...

TOP

本帖最后由 aloha20200628 于 2024-5-10 13:24 编辑


文件编码转换方法在c/c++/c#/vbs/js/powershell/...都有成熟的功能实现,其中亦可采用非常高效的选项,但在文件编码检测方面目前仍是一个近似解,因此业界称其为‘推测’方法。
已经用过几款专用的文件编码推测工具:
   chardetect.exe 基于Mozilla(火狐浏览器出品商)开源代码,可在python的chardet应用资源中获取
   uchardet.exe 基于Mozilla开源代码,可在 https://github.com/JetDemo/uchardet 下载
   file.exe 属于GNU资源,可在本论坛第三方下载
使用中有一些区别简报如下》
chardetect / file / uchardet 均可排查非文本文件;
chardetect / file 可返回细分信息;
chardetect 对多种常用编码误判率最低,但反应也最慢尤其是对大数据;
file 对中文编码误判率明显。

TOP


不仅系统命令more,而且powershell的gc/sc方法和[io:file]readAlllines/writeAlllines方法亦可修复源文件中的unix换行符,故重新订正了3楼和10楼代码,不必用more出手马后炮了。以前须烦劳正则替换来用'\r\n'规整文件中的多种换行符,其实极简之道是在命令行上跑一遍more就齐活了...

TOP

本帖最后由 aloha20200628 于 2024-5-13 12:46 编辑

回复 19# 娜美

网论有说硬件性能 ‘足够’ 即可令ps一口吞下1G大小的文件。
过去议论纯P的用法时,也常说不要碰其大(64M)小(8K)天花板。
小车超载,只能取 ‘细分多次’ 之策了,简单之举,或者改 ‘一次读取’ 为 ‘分行读取’,或者先将大文件按行数切成多个小文件,或者移步国内外专门的ps论坛求经盘道...
总之,都是 ‘时间换空间’ 的不同把戏而已...

TOP

本帖最后由 aloha20200628 于 2024-5-13 18:53 编辑

回复 22# 娜美

非也
如果1.txt采用utf-8编码+unix换行符,试试下式吧...
  1. powershell "$s=[io.file]::readalltext('1.txt',[text.encoding]::'utf8');[io.file]::writeAlltext('2.txt',$s,[text.encoding]::'default')"
复制代码
至少用powershell v4是不行滴 ...

TOP

本帖最后由 aloha20200628 于 2024-5-13 22:32 编辑

回复 20# 娜美

‘一次性读写’ 改为 ‘逐行读写’ 方案》以便应付超大数据文件,不过还是采用了powershell中相当高效的[io.file]readLines/streamWriter
基于3楼代码改写如下,再试试吧...
  1. @echo off &setlocal &del /q "allinOne.txt" "bug.txt" 2>nul
  2. for /f "delims=" %%F in (b.txt) do if not exist "%%~F" (echo,"badFile -- %%F"&echo,%%F>>"bug.txt") else (
  3. for /f "tokens=1-2 delims=-" %%a in (' uchardet.exe "%%~F" ') do (
  4. if /i "%%a" neq "unknown" (echo, /// %%~F ///>>"allinOne.txt")
  5. if /i "%%a"=="utf" if "%%b"=="8" (
  6. powershell "$g=[text.encoding]::getEncoding('gb2312');$m=new-object io.streamWriter('allinOne.txt',$true,$g);foreach($l in [io.file]::readLines('%%~F',[text.encoding]::'utf8')){$m.writeLine($l)};$m.close()"
  7. ) else if /i "%%a"=="utf" if "%%b"=="16" (
  8. powershell "$g=[text.encoding]::getEncoding('gb2312');$m=new-object io.streamWriter('allinOne.txt',$true,$g);foreach($l in [io.file]::readLines('%%~F',[text.encoding]::'unicode')){$m.writeLine($l)};$m.close()"
  9. )
  10. if /i "%%a"=="ascii" (
  11. more "%%~F">>"allinOne.txt"
  12. ) else if /i "%%a"=="gb18030" (
  13. more "%%~F">>"allinOne.txt"
  14. ) else if /i "%%a"=="unknown" (
  15. echo,"unknown -- %%F"&echo,%%F>>"bug.txt"
  16. )
  17. )
  18. echo,>>"allinOne.txt"
  19. )
  20. endlocal&pause&exit/b
复制代码

TOP

回复 27# 娜美

用你的各种实例测试比对,即可一目了然了 也许老东家对很容易拖后腿的 ‘逐行读取’ 给予了 ‘特别关照’...

TOP

回复 29# 娜美

顺便提一句》有人实测过,设置 -readcount 1000 的效果极佳
  1. powershell "gc *.txt -readcount 1000 -enc 'utf8'|ac 'all.tmp'"
复制代码

TOP

本帖最后由 aloha20200628 于 2024-5-15 17:28 编辑

回复 31# 娜美

管道是效率大杀器尤其是对大数据,尽量不用...
  1. @echo off &setlocal &del /q "allinOne.txt" "bug.txt" 2>nul
  2. for /f "delims=" %%F in (b.txt) do if not exist "%%~F" (echo,"badFile -- %%F"&echo,%%F>>"bug.txt") else (
  3. for /f "tokens=1 delims=_" %%a in (' coder.exe -s -a gc -f "%%~F" ') do (
  4. echo, /// %%~F ///>>"allinOne.txt"
  5. if /i "%%a"=="utf-8" (
  6. powershell "$s=gc '%%~F' readcount 1000 -enc 'utf8';ac 'allinOne.txt' $s"
  7. ) else if /i "%%a"=="utf-16" (
  8. powershell "$s=gc '%%~F' readcount 1000 -enc 'unicode';ac 'allinOne.txt' $s"
  9. ) else if /i "%%a"=="ansi" (more "%%~F">>"allinOne.txt")
  10. )
  11. echo,>>"allinOne.txt"
  12. )
  13. endlocal&pause&exit/b
复制代码

TOP

回复 33# 娜美

为何从[io:file]高效方法回退管道模式呢

TOP

回复 35# 娜美

用以下5行代码替换32楼代码中的5-9行,再试吧...
  1. if /i "%%a"=="utf-8" (
  2. powershell " gc '%%~F' readcount 1000 -enc 'utf8'|ac 'allinOne.txt' "
  3. ) else if /i "%%a"=="utf-16" (
  4. powershell " gc '%%~F' readcount 1000 -enc 'unicode'|ac 'allinOne.txt' "
  5. ) else if /i "%%a"=="ansi" (powershell " gc '%%~F' readcount 1000|ac 'allinOne.txt' ")
复制代码

TOP

回复 37# 娜美

37楼代码第8行改为下行即可...
  1. powershell " gc '%%~F' -readcount 1000 -enc 'unicode'|ac 'allinOne.txt' "
复制代码

TOP

返回列表