标题: [文本处理] [已解决]如何给文本添加行及删除位置不确定的字符串所在的行? [打印本页]
作者: stance 时间: 2011-1-10 00:07 标题: [已解决]如何给文本添加行及删除位置不确定的字符串所在的行?
要处理INTL.INF文件中的若干个行:
1、将E00E0804改为E0860804
2、将pintlgnt.ime改为sun86.ime
3、删除simsun.ttc,,,65536一行
4、在[SourceDisksFiles]段的末尾追加3行内容:
Sun86.IME = 107,,,,,,,0,0
Sun86.mb = 107,,,,,,,0,0
Sun86.chm = 107,,,,,,,0,0
5、删除其它所有的含有pintlgnt字符串的行(但不能把含有pintlgnt.ime字符串的行删掉,因为它要改成sun86.ime),pintlgnt字符串在各行中的位置不确定。
目前,已经实现1、2、3项,但无法实现4、5两项需求。当前代码如下:- type INTL.INF>INTL.TMP@echo off&setlocal enabledelayedexpansion
- (for /f "tokens=1* delims=:" %%a in ('findstr /n .* "INTL.TMP"') do if "%%b"=="" (echo/) else (
- set "hy=%%b"
- set hy=!hy:E00E0804=E0860804!
- set hy=!hy:pintlgnt.ime=sun86.ime!
- if /i not "!hy:~0,18!"=="simsun.ttc,,,65536" echo !hy!
- ))>"INTL.INF"
复制代码
这里对添加行还有一个要求,即首先要找到[SourceDisksFiles]段,然后在它的下一个段开始前添加行,因此不能用人工定位该段最后一行字符串的办法添加。
实际上还需要修改txtsetup.sif和 DOSNET.INF两个文件,情况类似。只是想通过修改这个文件,自己学会利用段名来确定位置,在指定位置添加含有特殊字符的行,以及删改含有某个位置不确定的字符串所在的行。
在论坛搜索到了一些添加行的方法,一时无从下手,又急着用,就直接问了。
附:INTL.INF文件压缩件(UNCODE编码)
[ 本帖最后由 stance 于 2011-1-10 16:27 编辑 ]
作者: stance 时间: 2011-1-10 00:14
奇怪!一加CODE代码就乱,只好这么发了。批处理的格式也改不过来,麻烦版主帮助弄一下吧。
[ 本帖最后由 stance 于 2011-1-10 00:19 编辑 ]
作者: 随风 时间: 2011-1-10 01:43
以下代码会修改INTL.INF,先备份INTL.INF文件。。。- @echo off
- (for /f "delims=" %%i in ('findstr /iv "simsun.ttc,,,65536" INTL.INF') do (
- set "str=%%i"
- setlocal enabledelayedexpansion
- set str=!str:e00e0804=e0860804!
- set str=!str:pintlgnt.ime=sun86.ime!
- set num=!str:pintlgnt=!
- if "!num!"=="!str!" echo;!str!
- if /i "!str!"=="[sourcedisksfiles]" (
- echo Sun86.IME = 107,,,,,,,0,0
- echo Sun86.mb = 107,,,,,,,0,0
- echo Sun86.chm = 107,,,,,,,0,0
- )
- endlocal
- ))>tem
- move tem INTL.INF
- start "" "INTL.INF"
复制代码
作者: hanyeguxing 时间: 2011-1-10 06:36
1,楼主提供的inf文件中,包含大量UNICODE编码字符,这些字符在输出为ANSI编码时会错误。
2,要把内容加到[SourceDisksFiles]节的最下面,但楼主提供的文件中包含2个[SourceDisksFiles]节,加在哪个最下面?
[ 本帖最后由 hanyeguxing 于 2011-1-10 14:22 编辑 ]
作者: stance 时间: 2011-1-10 11:25 标题: 回复 3楼 的帖子
感谢随风老大给出的批处理,甚合我意。
代码实在高超,一个DO()>tem就把文本内容输出来了——还在琢磨是怎么回事,是不是隐含的ELSE语句起了作用?
括号内的语句平实易懂,移植性强,真是大道至简,叹为观止!
作者: stance 时间: 2011-1-10 11:37 标题: 回复 4楼 的帖子
回 寒夜版主:
1、UNICODE码的问题确实存在,文本中的所有韩文和部分日文字符被显示为??号。我用“另存为”测试,也是这样,因此认为这是UNCODE转码的问题。
我看到您的头像里有韩文字符,正想专门问这个问题。
表面上看,这个问题不影响安装和使用,所以没急着问,但不知是否存在隐蔽的系统缺陷。如果能解决,最好不过了。
2、[SourceDisksFiles]问题:应该加在第一个后面。我也是刚刚发现这个问题,琢磨该怎么处理。
作者: hanyeguxing 时间: 2011-1-10 12:09
1,如果要保证编码不出问题,推荐使用第三方或 vbs
2:- @echo off&setlocal enabledelayedexpansion
- type "INTL.INF">temp
- set c==
- (for /f "tokens=1* delims=:" %%a in ('findstr /nivx "simsun.ttc,,,65536" "temp"') do if "%%b"=="" (echo/) else (
- set "b=%%b"
- if "!c!!d!"=="==" if "!b:~0,1!!b:~-1!"=="[]" (
- echo Sun86.IME = 107,,,,,,,0,0
- echo Sun86.mb = 107,,,,,,,0,0
- echo Sun86.chm = 107,,,,,,,0,0
- set c=&set d=
- )
- if /i "!b!"=="[sourcedisksfiles]" set d==
- set b=!b:e00e0804=e0860804!
- set b=!b:pintlgnt.ime=sun86.ime!
- set a=!b:pintlgnt=!
- if "!a!"=="!b!" echo/!b!
- ))>"INTL.INF"
- del temp
复制代码
[ 本帖最后由 hanyeguxing 于 2011-1-10 14:35 编辑 ]
作者: stance 时间: 2011-1-10 12:56 标题: 回复 7楼 的帖子
这个方案不错!谢谢寒夜版主。
不过,运行后输出一个空文本——您的代码中findb,应该是findstr吧,我是改后又测试过的。
作者: hanyeguxing 时间: 2011-1-10 13:26 标题: 回复 8楼 的帖子
打字总马马虎虎的,不好意思,已经改正
作者: stance 时间: 2011-1-10 13:54
奇怪的现象,生成过一次新文本,以后再运行,又出空文本。以前也遇到过这类情况,找不到原因。
另外,在生成的那次查看,好像第二个[sourcedisksfiles]段中也被加入了新的字符串。
作者: 随风 时间: 2011-1-10 13:59
把内容加到第一个[sourcedisksfiles]后面
:- @echo off
- (for /f "delims=" %%i in ('findstr /iv "simsun.ttc,,,65536" INTL.INF') do (
- set "str=%%i"
- if /i "%%i"=="[sourcedisksfiles]" set /a flag+=1
- setlocal enabledelayedexpansion
- set str=!str:e00e0804=e0860804!
- set str=!str:pintlgnt.ime=sun86.ime!
- set num=!str:pintlgnt=!
- if "!num!"=="!str!" echo;!str!
- if !flag! equ 1 (
- echo Sun86.IME = 107,,,,,,,0,0
- echo Sun86.mb = 107,,,,,,,0,0
- echo Sun86.chm = 107,,,,,,,0,0
- )
- endlocal
- ))>tem
- move tem INTL.INF
- start "" "INTL.INF"
复制代码
作者: hanyeguxing 时间: 2011-1-10 14:01 标题: 回复 10楼 的帖子
实际测试,使用 UltraCompare 二进制完全比较,未发现任何差异。
作者: hanyeguxing 时间: 2011-1-10 14:04 标题: 回复 11楼 的帖子
楼主是要把内容加的此节的最下面,不是节名的下一行,呵呵,而且文件为源UNICODE编码
顺便再说7楼的代码要求先将源文件的只读属性去掉,否则:- @echo off&setlocal enabledelayedexpansion
- type "INTL.INF">temp
- set c==
- (for /f "tokens=1* delims=:" %%a in ('findstr /nivx "simsun.ttc,,,65536" "temp"') do if "%%b"=="" (echo/) else (
- set "b=%%b"
- if "!c!!d!"=="==" if "!b:~0,1!!b:~-1!"=="[]" (
- echo Sun86.IME = 107,,,,,,,0,0
- echo Sun86.mb = 107,,,,,,,0,0
- echo Sun86.chm = 107,,,,,,,0,0
- set c=&set d=
- )
- if /i "!b!"=="[sourcedisksfiles]" set d==
- set b=!b:e00e0804=e0860804!
- set b=!b:pintlgnt.ime=sun86.ime!
- set a=!b:pintlgnt=!
- if "!a!"=="!b!" echo/!b!
- ))>temp2
- move temp2 "INTL.INF"
- del /q temp
复制代码
[ 本帖最后由 hanyeguxing 于 2011-1-10 15:38 编辑 ]
作者: stance 时间: 2011-1-10 14:24 标题: 回复 11楼 的帖子
谢谢随风老大再出手!
这个代码的意思我大概读懂了,但我自己做不出来,也不会改。
测试结果有点问题:从第一个[sourcedisksfiles]段开始,每一行后面都被加入了三行这样的内容:
Sun86.IME = 107,,,,,,,0,0
Sun86.mb = 107,,,,,,,0,0
Sun86.chm = 107,,,,,,,0,0
批处理在接到[sourcedisksfiles]指示后,就从这一行开始,给每行都加这三行内容。
似乎应该再加点条件限制,防止它给以后各行都加新三行。
作者: stance 时间: 2011-1-10 14:30 标题: 回复 12楼的帖子
回寒夜版主:
1、大概是我的系统环境有问题,以前你给我代码时也遇到过。
刚才换了台机器测试,还是空文本。如果你测试没问题,相信就能通过。我再换个办法试试。
2、如果代码太复杂,只加到节名下面也行。
3、不要求非得UNICODE编码。
另外,我用TOTAL COMMAND自带的”比较文件内容“功能,也很强大,而且非常方便、体贴。这个软件有很多强大的功能,支持正则表达式,尤其适合常玩DOS的人,建议试试。
[ 本帖最后由 stance 于 2011-1-10 15:07 编辑 ]
作者: stance 时间: 2011-1-10 15:03
想到了另一种解决办法:
查找[sourcedisksfiles]段名,如果它的下一个段名是[Locales],就在[Locales]上方添加行。
INF源文件中的段名称和位置都是固定的,如果用上下两个段名称来确定插入位置,一般就不会有重复的了。
作者: 随风 时间: 2011-1-10 15:34
11楼代码确实会导致在[sourcedisksfiles]之后,下一个[sourcedisksfiles]之前的每一行都插入内容,代码未测试,大意了 ^_^
还真没主意,是要加在[sourcedisksfiles]段的最后面,一直以为是加在它下面呢
如果要加在[sourcedisksfiles]段的最后,则必须知道它的下一个段名,应该很容易解决
作者: hanyeguxing 时间: 2011-1-10 15:40 标题: 回复 17楼 的帖子
不需要知道下一节的节名,因为节名一定是[XXX]形式的,所以只需要判断行首尾是否为 [] 就可以了(如果没有空格的话)。
作者: stance 时间: 2011-1-10 15:56 标题: 回复 17楼 、18楼的帖子
非常感谢两位版主的大力帮助!没想到一个相同文本中两节同名,处理起来这么麻烦。
我不光要解决眼前问题,也想学会它,因为还有类似文本要处理。
寒夜版主后面的代码一次性通过。但还没搞懂if "!c!!d!"=="==" if "!b:~0,1!!b:~-1!"=="[]"这个语句的语义,以前真没见过这么用的。你的讲解认真读了几遍,仍然没懂这个语句的语义。
对随风版主的代码,主要是测试时必须先TYPE成ANSI码才能用,否则输出为“佛拉克伩那里萨摩斯语ന”。但随风版主的程序思路对于我这初手来说好懂一点,希望再调试一下。我想,把两个代码都读懂了,自己的处理这类文本的能力也会提高不少。
作者: 随风 时间: 2011-1-10 16:01
为了能处理文本中的半角!号,还真费了翻功夫。。。- @echo off
- set wjm=a.txt
- (for /f "delims=" %%i in ('findstr /ivn "simsun.ttc,,,65536" %wjm%') do (
- set "str=%%i"
- if defined h set "h="
- if not defined v (
- for /f "tokens=1* delims=:" %%j in ("%%i") do (
- if /i "%%k"=="[sourcedisksfiles]" set s=1
- if defined s if /i "%%k"=="[Locales]" set h=a&set v=a&set "s="
- )
- )
- setlocal enabledelayedexpansion
- set str=!str:*:=!
- if not defined str (echo;) else (
- set str=!str:e00e0804=e0860804!
- set str=!str:pintlgnt.ime=sun86.ime!
- set num=!str:pintlgnt=!
- if defined h (
- echo Sun86.IME = 107,,,,,,,0,0
- echo Sun86.mb = 107,,,,,,,0,0
- echo Sun86.chm = 107,,,,,,,0,0
- )
- if "!num!"=="!str!" echo;!str!
- )
- endlocal
- ))>tem
- move tem "%wjm%"
- start "" "%wjm%"
复制代码
[ 本帖最后由 随风 于 2011-1-10 16:04 编辑 ]
作者: stance 时间: 2011-1-10 16:25 标题: 回复 20楼 的帖子
测试成功!
批处理之家太好啦!要是没有两位版主帮助,我不知道什么时候才能解决这个问题。
作者: stance 时间: 2011-1-10 19:01
仔细研读二位版主的代码,发现原本简单的核心代码,因为要处理重复r的[sourcedisksfiles]节问题,把整个代码搞得跟天书似的。忍不住再来问问:
1、对寒夜版主的代码比较熟悉,不懂的主要是:if "!c!!d!"=="==" if "!b:~0,1!!b:~-1!"=="[]"中两个IF之间的关系是递进的吗? "!c!!d!"=="==" 中带引号的==号是什么意思?
2、随风版主的前置代码更看不懂了:
if defined h set "h="
if not defined v
这两句之后的括号中set h=a&set v=a,这个a是什么?
作者: hanyeguxing 时间: 2011-1-10 19:21 标题: 回复 22楼 的帖子
以我写的代码为例,先说一下定位到[sourcedisksfiles]节最后一行的思路:
1,首先,要找到[sourcedisksfiles]行,并设置标志d
2,当标志d存在时,检查行的首和尾是否分别为 [] ,为了不包括[sourcedisksfiles]本身,本代码需要在1代码前
3,如果2检查成立,则说明for /f已经解析到了[sourcedisksfiles]节的下一节节名这一行,输出内容
4,同时删除标志c和标志d:这里删除标志d是为了减少对行的判断;删除标志c,则表明已经处理过第一个[sourcedisksfiles]节了,以后再遇到其他同样的[sourcedisksfiles]节,也不处理了
5,因为此时行内容为[sourcedisksfiles]的下一节节名,所以输出要在行输出前
set c==设置变量c为=,即设置标志c
set c=&set d=删除c、d标志
if "!c!!d!"=="=="检查变量c、d是否值都为=,即判断c、d标志是否都存在
if "!b:~0,1!!b:~-1!"=="[]"检查行的首尾是否为 []
if "!c!!d!"=="==" if "!b:~0,1!!b:~-1!"=="[]"两个if是与逻辑关系,即同时都要满足条件
[ 本帖最后由 hanyeguxing 于 2011-1-10 19:23 编辑 ]
作者: stance 时间: 2011-1-10 19:34
谢谢寒夜老师!
这下明白多了。
[ 本帖最后由 stance 于 2011-1-10 20:49 编辑 ]
作者: 随风 时间: 2011-1-10 20:08
也说说我的代码,得到代码后能认真研读的好像真不是很多,赞一个先 ^_^
先说说代码功能:
由于不懂inf文件的特性,所以是把它当作任意文本来处理的,所以就必须考虑某些特殊情况
比如:
1、文本内容含半角!符号
2、[sourcedisksfiles]和[Locales]段名有可能出现在文本的任意位置,且不一定是成对出现。
if defined v 是判断变量名为v的是否被定义过,自然 if not defined 则是判断v是否没被定义过
所以 set h=a&set v=a 只是为了给这两个变量定义,值是什么不重要,重要的是这两个变量被定义了,也就是这两个变量存在,而set "v="则是清空变量v的值,也就是变量v不存在了。
for 循环到[sourcedisksfiles]行时,变量 s 被定义,这相当一个开关,告诉代码在这之后若遇到[Locales]则插入新内容,也就是执行if defined h 里的命令,也就是在此后遇到[Locales]时需给变量h定义,if defined h 里的命令才会执行。
if defined s if /i "%%k"=="[Locales]" set h=a&set v=a&set "s="
当变量s被定义,也就是已经找到[sourcedisksfiles]后,若该行为[Locales]则set h=a&set v=a&set "s="定义h的作用前面已经说了,那定义 v和清空s呢?
定义v是为了配合if not defined v 这句,否则在下次遇到这两个段名时,又会重复执行。清空变量s,这句好像多余了,应该可以不要,因为定义了变量v,里面的代码就不会在执行了。
作者: stance 时间: 2011-1-10 20:34
哦,原来有没有a是用来判断true或false的,这种用法从来没领教过,难怪看不懂了。
还有那个变量s,也是没看懂的,原来是开关,性质跟那个a类似。
这两样对我来说完全是新东西。听懂这个,就更明白了,原来整个程序是由两部分构成的,一部分用来判断第一个[sourcedisksfiles]节,然后才执行核心程序。
谢谢随风老师的新知识。
随风老师说把它当作任意文本来处理,这个出发点对我来说更有利,因为这样的程序应用范围更广,可移植性强。我想要的就是能解决此类问题的方法,而不是只处理这一个文本。所以,您考虑到处理半角!符号的情况,即使这个文本中不存在,对我来说也是有意义的。
作者: stance 时间: 2011-1-10 20:54
看了随风老师的讲解,回过头来又加深了对寒夜老师讲解的理解:
原来set c==就是起一个开关的作用。if "!c!!d!"=="=="里,引号的两个=号分别属于变量C、d,用来判断它们是否都有值。不过这种用法更抽象,没看懂它们是怎样被赋值的。程序体中没看出它们被赋值的过程,就直接检测有无=号,觉得不可思议。
- 哦,经过一番仔细琢磨,终于想明白了:
-
- 原来寒夜老师的开关是无值开关,它只是用来控制到处理完第一个[sourcedisksfiles]节之后关闭用的,是一个进程时间控制器。由此理解了寒夜老师的讲解:
- 1,首先,要找到[sourcedisksfiles]行,并设置标志d
- 2,当标志d存在时,检查行的首和尾是否分别为 [],为了不包括[sourcedisksfiles]本身,本代码需要在1代码前
- 4,同时删除标志c和标志d:这里删除标志d是为了减少对行的判断;
-
- ——这就是说,[]包括前后两节的[]号在内,用来控制程序处理范围。 if /i "!b!"=="[sourcedisksfiles]" set d==表示如果触发[sourcedisksfiles],变量d处于=状态,再触发[]号,就处于不等于状态。
- ——所以随风老师说:“所以 set h=a&set v=a 只是为了给这两个变量定义,值是什么不重要,重要的是这两个变量被定义了,也就是这两个变量存在”!
-
- 真是太奥妙了!!!=号也能当开关用……
复制代码
[ 本帖最后由 stance 于 2011-1-10 22:31 编辑 ]
作者: tmplinshi 时间: 2011-1-10 21:40
来一段啰嗦的、效果低的:
内容会添加到段的末尾- @echo off
- SetLocal EnableDelayedExpansion
-
- echo 请稍等...
-
- rem =============== 设置 ===============
- rem 设置文件名
- set "INF_File=INTL.INF"
-
- rem 设置要删除的行
- set "Delete_Line=simsun.ttc,,,65536"
-
- rem 设置哪一段下面要添加内容
- set Section=[SourceDisksFiles]
-
- rem --------- 段下面要添加的内容 ---------
- rem 必须用双引号括起来
- for %%a in (
- "Sun86.IME = 107,,,,,,,0,0"
- "Sun86.mb = 107,,,,,,,0,0"
- "Sun86.chm = 107,,,,,,,0,0"
- ) do set Append_Lines=!Append_Lines! %%a
- rem --------- /段下面要添加的内容 ---------
-
- rem --------- 替换字符串 ---------
- rem 必须用双引号括起来
- for %%a in (
- "E00E0804=E0860804"
- "pintlgnt.ime=sun86.ime"
- ) do set Old-New=!Old-New! %%a
- rem --------- /替换字符串 ---------
-
- rem 删除含有某字符串的行
- set "ContainStr=pintlgnt"
- rem =============== /设置 ===============
-
- type "%INF_File%" | findstr /nivc:"%Delete_Line%" >.findstr
-
- rem 去除 INF_File 文件的“只读”属性
- attrib -r "%INF_File%"
-
- (for /f "tokens=*" %%a in (.findstr) do (
- set var=%%a
- for %%a in (%Old-New%) do set var=!var:%%~a!
- if "!var:%ContainStr%=!" equ "!var!" (
- if defined Monitor_Section_End (
- set var2=!var: =!
- set var2=!var:*:=!
- if "!var2:~0,1!!var2:~-1!"=="[]" (
- for %%a in (%Append_Lines% !Above_Lines! "!var:*:=!") do (
- echo,%%~a
- )
- set Monitor_Section_End=
- set Above_Lines=
- set Append_Finish=#
- ) else if "!var2!"=="" (
- set Above_Lines=!Above_Lines! "!var:*:=!"
- ) else if "!var2:~0,1!"==";" (
- set Above_Lines=!Above_Lines! "!var:*:=!"
- ) else (
- for %%a in (!Above_Lines! "!var:*:=!") do echo,%%~a
- set Above_Lines=
- )
- ) else (
- if "!var:*:=!"=="%Section%" (
- if not defined Append_Finish set Monitor_Section_End=#
- )
- echo,!var:*:=!
- )
- )
- )) >"%INF_File%"
-
- del .findstr
-
- rem 为了防止要添加内容的段为最后一段。
- if defined Monitor_Section_End (
- for %%a in (%Append_Lines% %Above_Lines%) do echo,%%~a
- ) >>"%INF_File%"
复制代码
[ 本帖最后由 tmplinshi 于 2011-1-10 22:29 编辑 ]
作者: stance 时间: 2011-1-10 21:48 标题: 回复 28楼 的帖子
感谢tmplinshi版主的关心和帮助!
我已经从理论上弄明白是怎么回事了,复制您的代码回去好好实际地练一练,加深体会。你发帖时,我正在编辑27楼的帖子的后半部分,当时没看到,非常感谢您的劳动!
批处理之家太好了,有这么多热心的高人,幸福!
[ 本帖最后由 stance 于 2011-1-10 22:06 编辑 ]
作者: stance 时间: 2011-1-10 22:13
tmplinshi版主太好啦,又重新编辑了代码,我把两次代码都复制下来,回去对比着练习。
这么长的代码花费了您不少时间。
欢迎光临 批处理之家 (http://www.bathome.net/) |
Powered by Discuz! 7.2 |