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

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

要处理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 编辑 ]
1

评分人数

    • hanyeguxing: 感谢给帖子标题标注[已解决]字样PB + 2

tmplinshi版主太好啦,又重新编辑了代码,我把两次代码都复制下来,回去对比着练习。
这么长的代码花费了您不少时间。

TOP

回复 28楼 的帖子

感谢tmplinshi版主的关心和帮助!
我已经从理论上弄明白是怎么回事了,复制您的代码回去好好实际地练一练,加深体会。你发帖时,我正在编辑27楼的帖子的后半部分,当时没看到,非常感谢您的劳动!
批处理之家太好了,有这么多热心的高人,幸福!

[ 本帖最后由 stance 于 2011-1-10 22:06 编辑 ]

TOP

来一段啰嗦的、效果低的:
内容会添加到段的末尾
  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 编辑 ]
2

评分人数

TOP

看了随风老师的讲解,回过头来又加深了对寒夜老师讲解的理解:

原来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 编辑 ]

TOP

哦,原来有没有a是用来判断true或false的,这种用法从来没领教过,难怪看不懂了。
还有那个变量s,也是没看懂的,原来是开关,性质跟那个a类似。
这两样对我来说完全是新东西。听懂这个,就更明白了,原来整个程序是由两部分构成的,一部分用来判断第一个[sourcedisksfiles]节,然后才执行核心程序。
谢谢随风老师的新知识。
随风老师说把它当作任意文本来处理,这个出发点对我来说更有利,因为这样的程序应用范围更广,可移植性强。我想要的就是能解决此类问题的方法,而不是只处理这一个文本。所以,您考虑到处理半角!符号的情况,即使这个文本中不存在,对我来说也是有意义的。

TOP

也说说我的代码,得到代码后能认真研读的好像真不是很多,赞一个先 ^_^
先说说代码功能:
由于不懂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,里面的代码就不会在执行了。
技术问题请到论坛发帖求助!

TOP

谢谢寒夜老师!
这下明白多了。

[ 本帖最后由 stance 于 2011-1-10 20:49 编辑 ]

TOP

回复 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 编辑 ]
寒夜孤星:在没有说明的情况下,本人所有代码均运行在 XP SP3 下 (有问题请发贴,QQ临时会话已关闭)

TOP

仔细研读二位版主的代码,发现原本简单的核心代码,因为要处理重复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是什么?

TOP

回复 20楼 的帖子

测试成功!
批处理之家太好啦!要是没有两位版主帮助,我不知道什么时候才能解决这个问题。

TOP

为了能处理文本中的半角!号,还真费了翻功夫。。。
  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 编辑 ]
1

评分人数

技术问题请到论坛发帖求助!

TOP

回复 17楼 、18楼的帖子

非常感谢两位版主的大力帮助!没想到一个相同文本中两节同名,处理起来这么麻烦。
我不光要解决眼前问题,也想学会它,因为还有类似文本要处理。

寒夜版主后面的代码一次性通过。但还没搞懂if "!c!!d!"=="==" if "!b:~0,1!!b:~-1!"=="[]"这个语句的语义,以前真没见过这么用的。你的讲解认真读了几遍,仍然没懂这个语句的语义。

对随风版主的代码,主要是测试时必须先TYPE成ANSI码才能用,否则输出为“佛拉克伩那里萨摩斯语ന”。但随风版主的程序思路对于我这初手来说好懂一点,希望再调试一下。我想,把两个代码都读懂了,自己的处理这类文本的能力也会提高不少。

TOP

回复 17楼 的帖子

不需要知道下一节的节名,因为节名一定是[XXX]形式的,所以只需要判断行首尾是否为 [] 就可以了(如果没有空格的话)。
寒夜孤星:在没有说明的情况下,本人所有代码均运行在 XP SP3 下 (有问题请发贴,QQ临时会话已关闭)

TOP

11楼代码确实会导致在[sourcedisksfiles]之后,下一个[sourcedisksfiles]之前的每一行都插入内容,代码未测试,大意了 ^_^

还真没主意,是要加在[sourcedisksfiles]段的最后面,一直以为是加在它下面呢
如果要加在[sourcedisksfiles]段的最后,则必须知道它的下一个段名,应该很容易解决
技术问题请到论坛发帖求助!

TOP

返回列表