标题: [文本处理] 【已解决】批处理查找并替换字符串 [打印本页]
作者: 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里- \pos(100,200)\pos(100,200)\pos(100,200)
- \pos(100,200)\pos(100,200)
- \pos(100,200)
复制代码
x乘1.5,y乘2的话变成- \pos(150,400)\pos(150,400)\pos(150,400)
- \pos(150,400)\pos(150,400)
- \pos(150,400)
复制代码
作者: terse 时间: 2013-10-31 01:52
- @echo off
- set n=2
- for /f "delims=" %%F in ('dir /b /a-d *.ini') do (
- (for /f "usebackq delims=" %%i in ("%%F") do (
- set "str=%%i"
- setlocal enabledelayedexpansion
- if "!str:\pos=(!" neq "%%i" (
- for /f "tokens=1,2 delims=,)" %%a in ("!str:*\pos(=!") do (
- set /a "i=%%a*n,j=%%b*n" 2>nul&&(
- for /f %%j in ("\pos(!i!,!j!)") do (
- set "str=!str:\pos(%%a,%%b)=%%j!"
- )
- )
- )
- )
- for /f "delims=" %%i in ("!str!") do endlocal&echo %%i
- ))>$
- move $ "%%F"
- )
- pause
复制代码
作者: apang 时间: 2013-10-31 15:41
本帖最后由 apang 于 2013-10-31 18:43 编辑
纯练习- Set fso = CreateObject("Scripting.FileSystemObject")
- text = fso.OpenTextFile("a.txt").Readall
-
- Set re = New RegExp
- re.Pattern = "([\s\S]*?\\pos\()(\d+),(\d+)\)|([\s\S]+)$"
- re.IgnoreCase = True
- re.Global = True
- For Each a In re.Execute(text)
- If a.SubMatches(3) = "" Then
- str = str & a.SubMatches(0) & _
- a.SubMatches(1) * 2 & "," & _
- a.SubMatches(2) * 2 & ")"
- Else str = str & a.SubMatches(3)
- End If
- Next
-
- 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 - @echo off
- set n=2
- for /f "delims=" %%F in ('dir /b /a-d *.txt') do (
- (for /f "delims=" %%i in ('type "%%F"^|findstr /n .*') do (
- set "str=%%i"
- setlocal enabledelayedexpansion
- if "!str:\pos=(!" neq "%%i" (
- for /f "tokens=1,2 delims=,)" %%a in ("!str:*\pos(=!") do (
- set /a "i=%%a*n,j=%%b*n" 2>nul&&(
- for /f %%j in ("\pos(!i!,!j!)") do (
- set "str=!str:\pos(%%a,%%b)=%%j!"
- )
- )
- )
- )
- echo;!str:*:=!
- endlocal
- ))>$
- move $ "%%F"
-
- )
- 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
- @set @n=0//& dir /b *.txt | cscript.exe -nologo -e:jscript "%~f0" &pause&exit/b
- while (!WSH.StdIn.AtEndOfStream) {
- f = WSH.StdIn.ReadLine();
- WSH.StdOut.Write("\r处理:\t"+f);
- WSH.Sleep(300); //Delete this line!
- try {enlarge(f, 1.5, 2.5); WSH.StdOut.Write("\r成功:\n");}
- catch(e) {WSH.StdOut.Write("\r失败:\n");}
- }
-
- function enlarge(file, m, n)
- {
- var aso, txt;
- aso = new ActiveXObject("ADODB.Stream");
- aso.Mode = 3;
- aso.Type = 2;
- aso.Charset = "cp437";
- aso.Open();
- aso.LoadFromFile(file);
- txt = aso.ReadText(-1);
- if (txt.indexOf('\x00') > -1) {
- aso.Position = 0;
- aso.Charset = "unicode";
- txt = aso.ReadText(-1);
- }
- txt = txt.replace(/\\pos\((\d+),(\d+)(?=\))/g,
- function(s0,s1,s2){return "\\pos(" + s1*m + ',' + s2*n});
- aso.Position = 0;
- aso.WriteText(txt);
- aso.SetEOS();
- aso.SaveToFile(file + ".log", 2);
- aso.Close();
- aso = null;
- return txt;
- }
复制代码
作者: terse 时间: 2013-11-3 12:48
本帖最后由 terse 于 2013-11-4 15:28 编辑
搞个PS练手
XP系统需安装有POWERSHELL win7自带无需另装
代码第一行 2.89 为设定数 自己修改
路径为 c:\test
对于编码的判断准确与否 没测试 运行请前先备份- $n=2.89
- function Get-Encoding ($ph)
- {
- $ByteStr = Get-Content $Ph -Encoding Byte -TotalCount 3
- $BOM = "{0:X}{1:X}{2:X}" -f $ByteStr
- if ($BOM -eq "EFBBBF") { "UTF8" }
- Else {
- $BOM = "{0:X}{1:X}" -f $ByteStr
- if ($BOM -eq "FFFE") { "Unicode" }
- Elseif ($BOM -eq "FEFF") {"BigEndianUnicode"}
- Else {"Ascii"}
- }
- }
- get-childitem "c:\te st\*" -include *.txt | ?{
- $Encoding = Get-Encoding($_)
- (Get-Content $_ | % {
- if ($_ -cmatch '(.+\\pos\()(\d+),(\d+)(.*)') {
- "$($matches[1])$([int]($n * $matches[2])),$([int]($n * $matches[3]))$($matches[4])"
- } else {"$_"}
- }) | Set-Content -Encoding $Encoding $_
- }
复制代码
作者: terse 时间: 2013-11-4 16:57
路径和文件扩展名 统一在前面定义
楼主没回复 浪费脑细胞- $n = 2.89
- $Ph = "c:\test"
- $Ext = "txt"
- function Get-Encoding ($ph)
- {
- $ByteStr = Get-Content $Ph -Encoding Byte -TotalCount 3
- $BOM = "{0:X}{1:X}{2:X}" -f $ByteStr
- if ($BOM -eq "EFBBBF") { "UTF8" }
- Else {
- $BOM = "{0:X}{1:X}" -f $ByteStr
- if ($BOM -eq "FFFE") { "Unicode" }
- Elseif ($BOM -eq "FEFF") {"BigEndianUnicode"}
- Else {"Ascii"}
- }
- }
- get-childitem "$Ph\*" -include *.$Ext | ?{
- $Encoding = Get-Encoding($_)
- (Get-Content $_ | % {
- if ($_ -cmatch '(.+\\pos\()(\d+),(\d+)(.*)') {
- "$($matches[1])$([int]($n * $matches[2])),$([int]($n * $matches[3]))$($matches[4])"
- } else {"$_"}
- }) | Set-Content -Encoding $Encoding $_
- }
复制代码
作者: 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函数的话就没问题。
比如文件内容下面这种情况:- \pos(100,200)\pos(100,200)\pos(100,200)
- \pos(300,400)\pos(300,400)
- \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 编辑
我也凑热闹来了,- <#
-
- 把当前文件夹中指定后缀名的文件中的所有类似\pos(x,y)的字符串(x和y都是数字)替换成\pos(m*x,n*y),m和n也是数字。也就是字符串\pos(x,y)中的x和y乘上一个倍数。能支持各种文件编码
-
- 比如说a.txt里
-
- 01.\pos(100,200)\pos(100,200)\pos(100,200)
-
- 02.\pos(100,200)\pos(100,200)
-
- 03.\pos(100,200)
- 复制代码x乘1.5,y乘2的话变成
-
- 01.\pos(150,400)\pos(150,400)\pos(150,400)
-
- 02.\pos(150,400)\pos(150,400)
-
- 03.\pos(150,400)
- 复制代码
- #>
-
-
- $所有要处理的文件 = Get-ChildItem -Path z:\pstemp\坛友yearharvest\*.txt # -Recurse
- # 这里指定目录名,和文件类型
-
- [system.reflection.assembly]::loadwithpartialname("System.Text") | Out-Null
- [int32]$long = 1024 * 1024 * 128 #128MB
- $大字符串 = New-Object System.Text.StringBuilder($long)
-
-
- foreach ($aaa in $所有要处理的文件)
- {
- # 正常情况下,无需编写 GetEncoding 函数。因为Get-Content将自动判断编码, 参见:
- # powershell文件编码处理之妙~]
- # http://www.bathome.net/thread-26673-1-3.html
- # 如果有不带bom头的utf8格式文档,需要指定编码utf8;如果有不带bom头的unicode格式文档,需要指定unicode。不指定的话讲被【默认地】认为是ansi格式文档。
- foreach ($bbb in $(Get-Content -LiteralPath $aaa) )
- {
- #这题并不难,难在麻烦,不停地分行,分列,计算数值,然后再组合,不过代码不长。
- $切割数组 = $bbb -split '\\pos\('
- $连成字串 = $切割数组 -join ""
-
- $切割数组2 = $连成字串 -split '\)'
- $连成字串4 = ""
- foreach ($ccc in $切割数组2)
- {
- $切割数组3 = $ccc -split ','
- if ($切割数组3.Length -gt 1)
- {
- $连成字串3 = "" + ($切割数组3[0] -as [Int64]) * 1.5 + ',' + ($切割数组3[1] -as [Int64]) * 2
- $连成字串4 = $连成字串4 + '\pos(' + $连成字串3 + ')'
- }
-
- }
- #$连成字串4
- $大字符串.AppendLine($连成字串4) | Out-Null
- }
-
- $目标文件名 = $aaa.Name + $aaa.Extension
- Add-Content -Path $目标文件名 -value $大字符串 -Encoding Unicode
- }
-
- #测试通过
复制代码
假设你的文件名是 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 |