Board logo

标题: [文本处理] 【已解决】批处理查找并替换字符串 [打印本页]

作者: yearharvest    时间: 2013-10-30 23:43     标题: 【已解决】批处理查找并替换字符串

本帖最后由 yearharvest 于 2013-11-8 21:59 编辑

把当前文件夹中指定后缀名的文件中的所有类似\pos(x,y)的字符串(x和y都是数字)替换成\pos(m*x,n*y),m和n也是数字。也就是字符串\pos(x,y)中的x和y乘上一个倍数。能支持各种文件编码

比如说a.txt里
  1. \pos(100,200)\pos(100,200)\pos(100,200)
  2. \pos(100,200)\pos(100,200)
  3. \pos(100,200)
复制代码
x乘1.5,y乘2的话变成
  1. \pos(150,400)\pos(150,400)\pos(150,400)
  2. \pos(150,400)\pos(150,400)
  3. \pos(150,400)
复制代码

作者: terse    时间: 2013-10-31 01:52

  1. @echo off
  2. set n=2
  3. for /f "delims=" %%F in ('dir /b /a-d *.ini') do (
  4.     (for /f "usebackq delims=" %%i in ("%%F") do (
  5.          set "str=%%i"
  6.          setlocal enabledelayedexpansion
  7.          if "!str:\pos=(!" neq "%%i" (
  8.             for /f "tokens=1,2 delims=,)" %%a in ("!str:*\pos(=!") do (
  9.                 set /a "i=%%a*n,j=%%b*n" 2>nul&&(
  10.                     for /f %%j in ("\pos(!i!,!j!)") do (
  11.                         set "str=!str:\pos(%%a,%%b)=%%j!"
  12.                     )   
  13.                 )
  14.             )
  15.         )
  16.     for /f "delims=" %%i in ("!str!") do endlocal&echo %%i
  17.     ))>$
  18.     move $ "%%F"
  19. )
  20. pause
复制代码

作者: apang    时间: 2013-10-31 15:41

本帖最后由 apang 于 2013-10-31 18:43 编辑

纯练习
  1. Set fso = CreateObject("Scripting.FileSystemObject")
  2. text = fso.OpenTextFile("a.txt").Readall
  3. Set re = New RegExp
  4. re.Pattern = "([\s\S]*?\\pos\()(\d+),(\d+)\)|([\s\S]+)$"
  5. re.IgnoreCase = True
  6. re.Global = True
  7. For Each a In re.Execute(text)
  8.     If a.SubMatches(3) = "" Then
  9.         str = str & a.SubMatches(0) & _
  10.         a.SubMatches(1) * 2 & "," & _
  11.         a.SubMatches(2) * 2 & ")"
  12.     Else str = str & a.SubMatches(3)
  13.     End If
  14. Next
  15. fso.OpenTextFile("b.txt",2,True).Write str
复制代码

作者: yearharvest    时间: 2013-10-31 21:26

两个方法处理下面这个文件都有问题,用2楼的处理后变成空文件,用3楼的报错“无效的过程调用或参数”,好像是因为编码的原因,然后我把编码转换成UTF-8,但是用2楼和3楼处理后都会乱码,请问这要怎么解决?
还有3楼的有没有办法像2楼可以处理同一后缀名的多个文件?
作者: apang    时间: 2013-10-31 21:50

回复 4# yearharvest


    附件是unicode编码,第2行改成 text = fso.OpenTextFile("a.txt",1,,-1).Readall
作者: terse    时间: 2013-11-1 02:16

回复 4# yearharvest
  1. @echo off
  2. set n=2
  3. for /f "delims=" %%F in ('dir /b /a-d *.txt') do (
  4.     (for /f "delims=" %%i in ('type "%%F"^|findstr /n .*') do (
  5.         set "str=%%i"
  6.         setlocal enabledelayedexpansion
  7.         if "!str:\pos=(!" neq "%%i" (
  8.            for /f "tokens=1,2 delims=,)" %%a in ("!str:*\pos(=!") do (
  9.                set /a "i=%%a*n,j=%%b*n" 2>nul&&(
  10.                    for /f %%j in ("\pos(!i!,!j!)") do (
  11.                        set "str=!str:\pos(%%a,%%b)=%%j!"
  12.                    )
  13.                )
  14.            )
  15.         )
  16.           echo;!str:*:=!
  17.           endlocal
  18.      ))>$
  19.           move $ "%%F"
  20. )
  21. pause
复制代码

作者: yearharvest    时间: 2013-11-1 23:04

回复 5# apang


  编码是UTF-8的话又乱码了
作者: yearharvest    时间: 2013-11-1 23:34

回复 6# terse


    不支持小数,如果我要乘1.5的话就不行了,不过这是批处理本身不支持小数的原因,有没有其他办法支持小数?
作者: terse    时间: 2013-11-1 23:46

回复 8# yearharvest
没什么好办法 如你所说 CMD不支持浮点,要么这样,1.5 你当作 15 去乘 然后除以10
1.5*32= 15 *32/10 = 48 这样近似了
作者: wangx    时间: 2013-11-2 17:49

帖子内容很好,学习了。
作者: Batcher    时间: 2013-11-2 19:41

回复 8# yearharvest


    论坛搜索浮点数,有现成的代码。
作者: apang    时间: 2013-11-2 20:48

回复 7# yearharvest


    你的文件夹里到底有几种编码类型的文件需要修改?不说清楚要别人去猜呀?

你如果是真心求助的话,把你最终的需求更新到顶楼,我可以尝试一下,帮你写一段支持utf-8的代码。
作者: powerbat    时间: 2013-11-2 23:09

  1. @set @n=0//& dir /b *.txt | cscript.exe -nologo -e:jscript "%~f0" &pause&exit/b
  2. while (!WSH.StdIn.AtEndOfStream) {
  3.     f = WSH.StdIn.ReadLine();
  4.     WSH.StdOut.Write("\r处理:\t"+f);
  5.     WSH.Sleep(300); //Delete this line!
  6.     try {enlarge(f, 1.5, 2.5); WSH.StdOut.Write("\r成功:\n");}
  7.     catch(e) {WSH.StdOut.Write("\r失败:\n");}
  8. }
  9. function enlarge(file, m, n)
  10. {
  11.     var aso, txt;
  12.     aso = new ActiveXObject("ADODB.Stream");
  13.     aso.Mode = 3;
  14.     aso.Type = 2;
  15.     aso.Charset = "cp437";
  16.     aso.Open();
  17.     aso.LoadFromFile(file);
  18.     txt = aso.ReadText(-1);
  19.     if (txt.indexOf('\x00') > -1) {
  20.         aso.Position = 0;
  21.         aso.Charset = "unicode";
  22.         txt = aso.ReadText(-1);
  23.     }
  24.     txt = txt.replace(/\\pos\((\d+),(\d+)(?=\))/g,
  25.         function(s0,s1,s2){return "\\pos(" + s1*m + ',' + s2*n});
  26.     aso.Position = 0;
  27.     aso.WriteText(txt);
  28.     aso.SetEOS();
  29.     aso.SaveToFile(file + ".log", 2);
  30.     aso.Close();
  31.     aso = null;
  32.     return txt;
  33. }
复制代码

作者: terse    时间: 2013-11-3 12:48

本帖最后由 terse 于 2013-11-4 15:28 编辑

搞个PS练手
XP系统需安装有POWERSHELL win7自带无需另装
代码第一行 2.89 为设定数 自己修改
路径为 c:\test
对于编码的判断准确与否 没测试 运行请前先备份
  1. $n=2.89
  2. function Get-Encoding ($ph)
  3. {
  4. $ByteStr = Get-Content $Ph -Encoding Byte -TotalCount 3
  5. $BOM = "{0:X}{1:X}{2:X}" -f $ByteStr
  6. if ($BOM -eq "EFBBBF") { "UTF8" }
  7. Else {
  8.        $BOM = "{0:X}{1:X}" -f $ByteStr
  9.        if ($BOM -eq "FFFE") { "Unicode" }
  10.            Elseif ($BOM -eq "FEFF") {"BigEndianUnicode"}
  11.            Else {"Ascii"}
  12.        }
  13. }
  14. get-childitem "c:\te st\*" -include *.txt | ?{
  15. $Encoding = Get-Encoding($_)
  16. (Get-Content $_ | % {
  17.     if ($_ -cmatch '(.+\\pos\()(\d+),(\d+)(.*)') {
  18.        "$($matches[1])$([int]($n * $matches[2])),$([int]($n * $matches[3]))$($matches[4])"
  19.     } else {"$_"}
  20. }) | Set-Content  -Encoding $Encoding $_
  21. }
复制代码

作者: terse    时间: 2013-11-4 16:57

路径和文件扩展名 统一在前面定义
楼主没回复 浪费脑细胞
  1. $n = 2.89
  2. $Ph = "c:\test"
  3. $Ext = "txt"
  4. function Get-Encoding ($ph)
  5. {
  6. $ByteStr = Get-Content $Ph -Encoding Byte -TotalCount 3
  7. $BOM = "{0:X}{1:X}{2:X}" -f $ByteStr
  8. if ($BOM -eq "EFBBBF") { "UTF8" }
  9. Else {
  10.        $BOM = "{0:X}{1:X}" -f $ByteStr
  11.        if ($BOM -eq "FFFE") { "Unicode" }
  12.            Elseif ($BOM -eq "FEFF") {"BigEndianUnicode"}
  13.            Else {"Ascii"}
  14.        }
  15. }
  16. get-childitem "$Ph\*" -include *.$Ext | ?{
  17. $Encoding = Get-Encoding($_)
  18. (Get-Content $_ | % {
  19.     if ($_ -cmatch '(.+\\pos\()(\d+),(\d+)(.*)') {
  20.        "$($matches[1])$([int]($n * $matches[2])),$([int]($n * $matches[3]))$($matches[4])"
  21.     } else {"$_"}
  22. }) | Set-Content  -Encoding $Encoding $_
  23. }
复制代码

作者: yearharvest    时间: 2013-11-4 22:36

回复 12# apang


    只是刚好我拿来测试的几个文件编码都不相同,能解决的话最好,不能或者解决起来麻烦的话就算了
作者: yearharvest    时间: 2013-11-4 22:45

回复 15# terse


    昨天忘了看,今天又有事现在才回来,多谢了,还有楼上的几位也是
作者: yearharvest    时间: 2013-11-5 00:10

回复 15# terse


    试了一下,发现文件名里有中括号的就会报一大堆错,不过这倒没什么关系,改下文件名就是了
作者: terse    时间: 2013-11-5 01:52

回复 18# yearharvest
新建 ! % ^ & 文件夹 (2)).txt
新建 ! % ^ & 文件夹 (2).txt
将你的附件 另存为上面两个文件 没提示错误
我再看看
作者: yearharvest    时间: 2013-11-5 21:40

本帖最后由 yearharvest 于 2013-11-5 21:43 编辑

是中括号,比如把文件命名成  [a].txt
作者: terse    时间: 2013-11-6 23:00

回复 20# yearharvest
如此含中括号文件名还真不知道怎么处理 我发去PS版看下
不知还存在其他问题不  比如编码
作者: DAIC    时间: 2013-11-7 08:22

回复 16# yearharvest


    13楼的代码有问题吗?
作者: yearharvest    时间: 2013-11-7 23:20

回复 21# terse


    编码没什么问题,也没发现其他问题
作者: yearharvest    时间: 2013-11-7 23:21

回复 22# DAIC


    测试一下没发现什么问题
作者: yearharvest    时间: 2013-11-7 23:41

本帖最后由 yearharvest 于 2013-11-7 23:42 编辑

回复 21# terse


    刚刚又发现一个问题,就是一行匹配多个的话只会处理最后一个。看代码是通过捕获组修改值然后字符串拼接起来,这样的话确实只能一行处理一个,像13的用replace函数的话就没问题。

    比如文件内容下面这种情况:
  1. \pos(100,200)\pos(100,200)\pos(100,200)
  2. \pos(300,400)\pos(300,400)
  3. \pos(500,600)
复制代码

作者: apang    时间: 2013-11-8 00:08

回复 25# yearharvest


    你这个人还真是奇葩,把你最终的要求更新到顶楼,很难吗?
像你这样没完没了地提要求,是对回复者的不尊重,说严重点,就是无理取闹
作者: PowerShell    时间: 2013-11-8 09:50

本帖最后由 PowerShell 于 2013-11-8 11:00 编辑

1 楼主的提问,是有点【一次问一点问题,每次都不问全了】的意思
2 楼主每次加问的都是比较难的,比较关键的关键点.
3 正如各位用powershell回答的,powershell这种牛x语言处理之不再话下:
3.1 不管你啥编码,编写一小段函数 【Get-Encoding 】都能转换,识别,打开------powershell这盘菜大家逐渐吃出好味道来了么?我很欣慰呀呵呵.
3.2 带有中括号的文件,如 [a].txt 就用 -LiteralPath
3.3 powershell计算带小数点的数值,也不用多说了吧.
3.4 powershell 内置.net正则,查找替换无忧.

4 我不会答问题,也不会编码,只会吹,哈哈~~
作者: yearharvest    时间: 2013-11-8 21:51

这确实是我的不对,麻烦各位了,这贴就这样结了吧,后面的我自己试着改改
作者: terse    时间: 2013-11-9 02:31

回复 28# yearharvest
http://bbs.bathome.net/thread-27238-1-1.html
虽然结贴了 还是PS 写了个 就不再这里贴了 链接里看下吧
作者: PowerShell    时间: 2013-11-9 10:38

本帖最后由 PowerShell 于 2013-11-9 11:40 编辑

我也凑热闹来了,
  1. <#
  2. 把当前文件夹中指定后缀名的文件中的所有类似\pos(x,y)的字符串(x和y都是数字)替换成\pos(m*x,n*y),m和n也是数字。也就是字符串\pos(x,y)中的x和y乘上一个倍数。能支持各种文件编码
  3. 比如说a.txt里
  4. 01.\pos(100,200)\pos(100,200)\pos(100,200)
  5. 02.\pos(100,200)\pos(100,200)
  6. 03.\pos(100,200)
  7. 复制代码x乘1.5,y乘2的话变成
  8. 01.\pos(150,400)\pos(150,400)\pos(150,400)
  9. 02.\pos(150,400)\pos(150,400)
  10. 03.\pos(150,400)
  11. 复制代码
  12. #>
  13. $所有要处理的文件 =  Get-ChildItem -Path z:\pstemp\坛友yearharvest\*.txt   # -Recurse
  14. # 这里指定目录名,和文件类型
  15. [system.reflection.assembly]::loadwithpartialname("System.Text") | Out-Null
  16. [int32]$long = 1024 * 1024 * 128 #128MB
  17. $大字符串 = New-Object System.Text.StringBuilder($long)
  18. foreach   ($aaa   in   $所有要处理的文件)
  19. {
  20. # 正常情况下,无需编写 GetEncoding 函数。因为Get-Content将自动判断编码, 参见:
  21. #  powershell文件编码处理之妙~]
  22. #  http://www.bathome.net/thread-26673-1-3.html
  23. #  如果有不带bom头的utf8格式文档,需要指定编码utf8;如果有不带bom头的unicode格式文档,需要指定unicode。不指定的话讲被【默认地】认为是ansi格式文档。
  24. foreach   ($bbb   in  $(Get-Content -LiteralPath $aaa)  )
  25. {
  26. #这题并不难,难在麻烦,不停地分行,分列,计算数值,然后再组合,不过代码不长。
  27. $切割数组 =  $bbb -split '\\pos\('
  28. $连成字串 = $切割数组   -join   ""
  29. $切割数组2 =  $连成字串   -split  '\)'
  30. $连成字串4 = ""
  31. foreach ($ccc  in  $切割数组2)
  32. {
  33. $切割数组3 =  $ccc  -split ','
  34. if  ($切割数组3.Length -gt 1)
  35. {
  36. $连成字串3 =  "" + ($切割数组3[0] -as [Int64]) * 1.5 +  ',' + ($切割数组3[1] -as [Int64]) * 2
  37. $连成字串4 =  $连成字串4 + '\pos(' + $连成字串3 + ')'
  38. }
  39. }
  40. #$连成字串4
  41. $大字符串.AppendLine($连成字串4) | Out-Null
  42. }
  43. $目标文件名 = $aaa.Name + $aaa.Extension
  44. Add-Content  -Path $目标文件名  -value $大字符串 -Encoding Unicode
  45. }
  46. #测试通过
复制代码
假设你的文件名是 aaa。txt 则生成aaa。txt。txt ,内含处理结果。


层层分解,每层都很简单,powershell有强大的调试工具。 powershell python都这样。
比 搜索 替换 正则 + 那些绕脑袋的古怪的单行公式 来的容易, bash awk sed 三犯a罪b团c伙 都这样。
作者: wscript    时间: 2013-11-9 15:25

13楼的代码好像可以完美解决问题吧,楼主还在纠结什么呢?
作者: yearharvest    时间: 2013-11-10 12:39

回复 31# wscript


    是可以完美解决,不过毕竟别人也回复了,我也只是把他们代码里发现的问题告诉他们
作者: wscript    时间: 2013-11-10 12:56

回复 32# yearharvest


    这样的话你应该早点说清楚,并重点指出是他们的ps解法有不完善的地方。提问者可能没注意到若干细节,测试代码时才能慢慢发现。而很多回答者往往也不考虑诸如编码、特殊字符之类的问题,就是他们自己应该提高的地方了。
作者: terse    时间: 2013-11-10 13:23

回复 32# yearharvest
关于PS的解 在29楼链接里有改进的
如方便的话 可再测试看有无其他问题,不便的话或其他原因也就算了
作者: zhanglei1371    时间: 2013-12-1 23:13

本帖最后由 zhanglei1371 于 2013-12-2 10:07 编辑

感谢lz的帖子,学习了!
作者: wendyluo    时间: 2014-12-1 19:17

mark以后好好学习学习,现在很多还看不懂




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