Board logo

标题: [文本处理] [已解决]如何给文本添加行及删除位置不确定的字符串所在的行? [打印本页]

作者: 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两项需求。当前代码如下:
  1. type INTL.INF>INTL.TMP@echo off&setlocal enabledelayedexpansion
  2. (for /f "tokens=1* delims=:" %%a in ('findstr /n .* "INTL.TMP"') do if "%%b"=="" (echo/) else (
  3.     set "hy=%%b"
  4.     set hy=!hy:E00E0804=E0860804!
  5.     set hy=!hy:pintlgnt.ime=sun86.ime!
  6.     if /i not "!hy:~0,18!"=="simsun.ttc,,,65536" echo !hy!
  7. ))>"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文件。。。
  1. @echo off
  2. (for /f "delims=" %%i in ('findstr /iv "simsun.ttc,,,65536" INTL.INF') do (
  3.    set "str=%%i"
  4.    setlocal enabledelayedexpansion
  5.    set str=!str:e00e0804=e0860804!
  6.    set str=!str:pintlgnt.ime=sun86.ime!
  7.    set num=!str:pintlgnt=!
  8.    if "!num!"=="!str!" echo;!str!
  9.    if /i "!str!"=="[sourcedisksfiles]" (
  10.       echo Sun86.IME    = 107,,,,,,,0,0
  11.       echo Sun86.mb     = 107,,,,,,,0,0
  12.       echo Sun86.chm    = 107,,,,,,,0,0
  13.    )
  14.    endlocal
  15. ))>tem
  16. move tem INTL.INF
  17. 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:
  1. @echo off&setlocal enabledelayedexpansion
  2. type "INTL.INF">temp
  3. set c==
  4. (for /f "tokens=1* delims=:" %%a in ('findstr /nivx "simsun.ttc,,,65536" "temp"') do if "%%b"=="" (echo/) else (
  5.    set "b=%%b"
  6.    if "!c!!d!"=="==" if "!b:~0,1!!b:~-1!"=="[]" (
  7.       echo Sun86.IME    = 107,,,,,,,0,0
  8.       echo Sun86.mb     = 107,,,,,,,0,0
  9.       echo Sun86.chm    = 107,,,,,,,0,0
  10.       set c=&set d=
  11.    )
  12.    if /i "!b!"=="[sourcedisksfiles]" set d==
  13.    set b=!b:e00e0804=e0860804!
  14.    set b=!b:pintlgnt.ime=sun86.ime!
  15.    set a=!b:pintlgnt=!
  16.    if "!a!"=="!b!" echo/!b!
  17. ))>"INTL.INF"
  18. 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]后面
:
  1. @echo off
  2. (for /f "delims=" %%i in ('findstr /iv "simsun.ttc,,,65536" INTL.INF') do (
  3.    set "str=%%i"
  4.    if /i "%%i"=="[sourcedisksfiles]" set /a flag+=1
  5.    setlocal enabledelayedexpansion
  6.    set str=!str:e00e0804=e0860804!
  7.    set str=!str:pintlgnt.ime=sun86.ime!
  8.    set num=!str:pintlgnt=!
  9.    if "!num!"=="!str!" echo;!str!
  10.    if !flag! equ 1 (
  11.       echo Sun86.IME    = 107,,,,,,,0,0
  12.       echo Sun86.mb     = 107,,,,,,,0,0
  13.       echo Sun86.chm    = 107,,,,,,,0,0
  14.    )
  15.    endlocal
  16. ))>tem
  17. move tem INTL.INF
  18. start "" "INTL.INF"
复制代码

作者: hanyeguxing    时间: 2011-1-10 14:01     标题: 回复 10楼 的帖子

实际测试,使用 UltraCompare 二进制完全比较,未发现任何差异。
作者: hanyeguxing    时间: 2011-1-10 14:04     标题: 回复 11楼 的帖子

楼主是要把内容加的此节的最下面,不是节名的下一行,呵呵,而且文件为源UNICODE编码

顺便再说7楼的代码要求先将源文件的只读属性去掉,否则:
  1. @echo off&setlocal enabledelayedexpansion
  2. type "INTL.INF">temp
  3. set c==
  4. (for /f "tokens=1* delims=:" %%a in ('findstr /nivx "simsun.ttc,,,65536" "temp"') do if "%%b"=="" (echo/) else (
  5.    set "b=%%b"
  6.    if "!c!!d!"=="==" if "!b:~0,1!!b:~-1!"=="[]" (
  7.       echo Sun86.IME    = 107,,,,,,,0,0
  8.       echo Sun86.mb     = 107,,,,,,,0,0
  9.       echo Sun86.chm    = 107,,,,,,,0,0
  10.       set c=&set d=
  11.    )
  12.    if /i "!b!"=="[sourcedisksfiles]" set d==
  13.    set b=!b:e00e0804=e0860804!
  14.    set b=!b:pintlgnt.ime=sun86.ime!
  15.    set a=!b:pintlgnt=!
  16.    if "!a!"=="!b!" echo/!b!
  17. ))>temp2
  18. move temp2 "INTL.INF"
  19. 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

为了能处理文本中的半角!号,还真费了翻功夫。。。
  1. @echo off
  2. set wjm=a.txt
  3. (for /f "delims=" %%i in ('findstr /ivn "simsun.ttc,,,65536" %wjm%') do (
  4.    set "str=%%i"
  5.    if defined h set "h="
  6.    if not defined v (
  7.       for /f "tokens=1* delims=:" %%j in ("%%i") do (
  8.          if /i "%%k"=="[sourcedisksfiles]" set s=1
  9.          if defined s if /i "%%k"=="[Locales]" set h=a&set v=a&set "s="
  10.        )
  11.     )
  12.    setlocal enabledelayedexpansion
  13.    set str=!str:*:=!
  14.    if not defined str (echo;) else (
  15.       set str=!str:e00e0804=e0860804!
  16.       set str=!str:pintlgnt.ime=sun86.ime!
  17.       set num=!str:pintlgnt=!
  18.       if defined h (
  19.          echo Sun86.IME    = 107,,,,,,,0,0
  20.          echo Sun86.mb     = 107,,,,,,,0,0
  21.          echo Sun86.chm    = 107,,,,,,,0,0
  22.        )
  23.       if "!num!"=="!str!" echo;!str!
  24.    )
  25.    endlocal
  26. ))>tem
  27. move tem "%wjm%"
  28. 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,用来判断它们是否都有值。不过这种用法更抽象,没看懂它们是怎样被赋值的。程序体中没看出它们被赋值的过程,就直接检测有无=号,觉得不可思议。

  1. 哦,经过一番仔细琢磨,终于想明白了:
  2. 原来寒夜老师的开关是无值开关,它只是用来控制到处理完第一个[sourcedisksfiles]节之后关闭用的,是一个进程时间控制器。由此理解了寒夜老师的讲解:
  3. 1,首先,要找到[sourcedisksfiles]行,并设置标志d
  4. 2,当标志d存在时,检查行的首和尾是否分别为 [],为了不包括[sourcedisksfiles]本身,本代码需要在1代码前
  5. 4,同时删除标志c和标志d:这里删除标志d是为了减少对行的判断;
  6. ——这就是说,[]包括前后两节的[]号在内,用来控制程序处理范围。   if /i "!b!"=="[sourcedisksfiles]" set d==表示如果触发[sourcedisksfiles],变量d处于=状态,再触发[]号,就处于不等于状态。
  7. ——所以随风老师说:“所以 set h=a&set v=a 只是为了给这两个变量定义,值是什么不重要,重要的是这两个变量被定义了,也就是这两个变量存在”!
  8. 真是太奥妙了!!!=号也能当开关用……
复制代码

[ 本帖最后由 stance 于 2011-1-10 22:31 编辑 ]
作者: tmplinshi    时间: 2011-1-10 21:40

来一段啰嗦的、效果低的:
内容会添加到段的末尾
  1. @echo off
  2. SetLocal EnableDelayedExpansion
  3. echo 请稍等...
  4. rem =============== 设置 ===============
  5. rem 设置文件名
  6. set "INF_File=INTL.INF"
  7. rem 设置要删除的行
  8. set "Delete_Line=simsun.ttc,,,65536"
  9. rem 设置哪一段下面要添加内容
  10. set Section=[SourceDisksFiles]
  11.     rem --------- 段下面要添加的内容 ---------
  12.     rem 必须用双引号括起来
  13.     for %%a in (
  14.         "Sun86.IME    = 107,,,,,,,0,0"
  15.         "Sun86.mb     = 107,,,,,,,0,0"
  16.         "Sun86.chm    = 107,,,,,,,0,0"
  17.     ) do set Append_Lines=!Append_Lines! %%a
  18.     rem --------- /段下面要添加的内容 ---------
  19. rem --------- 替换字符串 ---------
  20. rem 必须用双引号括起来
  21. for %%a in (
  22.     "E00E0804=E0860804"
  23.     "pintlgnt.ime=sun86.ime"
  24. ) do set Old-New=!Old-New! %%a
  25. rem --------- /替换字符串 ---------
  26. rem 删除含有某字符串的行
  27. set "ContainStr=pintlgnt"
  28. rem =============== /设置 ===============
  29. type "%INF_File%" | findstr /nivc:"%Delete_Line%" >.findstr
  30. rem 去除 INF_File 文件的“只读”属性
  31. attrib -r "%INF_File%"
  32. (for /f "tokens=*" %%a in (.findstr) do (
  33.     set var=%%a
  34.     for %%a in (%Old-New%) do set var=!var:%%~a!
  35.     if "!var:%ContainStr%=!" equ "!var!" (
  36.         if defined Monitor_Section_End (
  37.             set var2=!var: =!
  38.             set var2=!var:*:=!
  39.             if "!var2:~0,1!!var2:~-1!"=="[]" (
  40.                 for %%a in (%Append_Lines% !Above_Lines! "!var:*:=!") do (
  41.                     echo,%%~a
  42.                 )
  43.                 set Monitor_Section_End=
  44.                 set Above_Lines=
  45.                 set Append_Finish=#
  46.             ) else if "!var2!"=="" (
  47.                 set Above_Lines=!Above_Lines! "!var:*:=!"
  48.             ) else if "!var2:~0,1!"==";" (
  49.                 set Above_Lines=!Above_Lines! "!var:*:=!"
  50.             ) else (
  51.                 for %%a in (!Above_Lines! "!var:*:=!") do echo,%%~a
  52.                 set Above_Lines=
  53.             )
  54.         ) else (
  55.             if "!var:*:=!"=="%Section%" (
  56.                 if not defined Append_Finish set Monitor_Section_End=#
  57.             )
  58.             echo,!var:*:=!
  59.         )
  60.     )
  61. )) >"%INF_File%"
  62. del .findstr
  63. rem 为了防止要添加内容的段为最后一段。
  64. if defined Monitor_Section_End (
  65.     for %%a in (%Append_Lines% %Above_Lines%) do echo,%%~a
  66. ) >>"%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://bathome.net./) Powered by Discuz! 7.2