【问题标题】:Batch or VB script to update (or add) strings in one text file with strings from another批处理或 VB 脚本以使用来自另一个文本文件的字符串更新(或添加)一个文本文件中的字符串
【发布时间】:2014-03-10 01:35:09
【问题描述】:

第一次发帖。

我正在尝试将字符串更新(或添加)到纯文本文件,使用来自另一个文本文件的字符串。

例子:

File1.txt(参考文件)

<add key="1" value="False" />
<add key="2" value="C:\Temp" />
<add key="3" value="True" />
<add key="4" value="True" />
<add key="5" value="False" />
<add key="6" value="False" />
<add key="7" value="False" />
<add key="8" value="False" />
<add key="9" value="False" />
<add key="10" value="newkey" />
<add key="11" value="False" />
<add key="12" value="127.0.0.1" />
<add key="13" value="True" />
<add key="14" value="True" />
<add key="15" value="False" />
<add key="16" value="False" />
<add key="17" value="False" />
<add key="18" value="True" />
<add key="19" value="True" />
<add key="20" value="True" />
<add key="21" value="True" />
<add key="22" value="True" />

File2.txt(目标文件)

  <150 strings>
  </150 strings>

  <appSettings>
    <add key="1" value="False" />
    <add key="2" value="False" />
    <add key="3" value="False" />
    <add key="4" value="False" />
    <add key="5" value="False" />
    <add key="6" value="False" />
    <add key="7" value="False" />
    <add key="8" value="False" />
    <add key="9" value="False" />
    <add key="10" value="False" />
    <add key="11" value="False" />
    <add key="12" value="False" />
    <add key="13" value="False" />
    <add key="14" value="False" />
    <add key="15" value="False" />
    <add key="16" value="False" />
    <add key="17" value="False" />
    <add key="18" value="False" />
    <add key="19" value="False" />
    <add key="20" value="False" />
    <add key="21" value="False" />
    <add key="22" value="False" />
  </appSettings>
    <startup>
        <supportedRuntime/>
    </startup>
</configuration>

要求:

  1. 如果 file2.txt 已经包含一个或所有键(即 1 到 22),我想用 file1.txt 的键替换这些键。

  2. 如果 file2.txt 缺少 file1.txt 中存在的任何键,则需要添加它们。只要它们出现在&lt;AppSettings&gt; 内,顺序无关紧要。

  3. 如果 file2.txt 包含 file1.txt 中不存在的键,则应保留它们。

  4. &lt;AppSettings&gt; 之外的任何内容都应保持不变。

在简要测试了 Dbenham 的最后一个脚本后,它看起来完成了所有工作,但是上面和下面的行被移动了(我的错是没有提供完整的示例)。

这是 Dbenham 脚本的当前输出:

  <150 strings>
  </150 strings>

  <appSettings>
  </appSettings>
    <startup>
        <supportedRuntime/>
    </startup>
</configuration>
    <add key="1" value="False" />
    <add key="2" value="C:\Temp" />
    <add key="3" value="True" />
    <add key="4" value="True" />
    <add key="5" value="False" />
    <add key="6" value="False" />
    <add key="7" value="False" />
    <add key="8" value="False" />
    <add key="9" value="False" />
    <add key="10" value="newkey" />
    <add key="11" value="False" />
    <add key="12" value="127.0.0.1" />
    <add key="13" value="True" />
    <add key="14" value="True" />
    <add key="15" value="False" />
    <add key="16" value="False" />
    <add key="17" value="False" />
    <add key="18" value="True" />
    <add key="19" value="True" />
    <add key="20" value="True" />
    <add key="21" value="True" />
    <add key="22" value="True" />

【问题讨论】:

  • 在此处发帖之前您已经尝试过什么?你能提供例子吗?
  • 我使用 findstr 从其他文件中提取字符串以创建 'file1.txt',但需要一些指导来完成上述操作。作为脚本的新手,我无法理解一些稍微相似的 SO 场景/问题上的脚本。谢谢
  • 如果我正确理解了您的解释,最后 File2.txt 将包含 File1.txt 的相同内容,所以一个简单的copy File1.txt File2.txt /y 就可以解决这个问题!这两个文件的其他行是否与“&lt;add key=... /&gt;”不同?如果是这样,非常重要列出两个文件的真实小片段...
  • 不说,我假设您想保留 file2 中不存在于 file1 中的现有键值。这与@Aacini 提出的观点相同。
  • dbenham,你是对的。 file2 中的某些值在 file1 中不存在,否则副本将起作用......现在正在努力上传一些“真实”样本。

标签: string batch-file replace reference


【解决方案1】:

这是基于更新问题的新答案

您确实应该使用专门用于编辑 XML 的工具。配置文件 (file2.txt) 可以通过多种方式进行修改,但仍然有效,但这会破坏任何纯批处理解决方案。但是,假设布局与您显示的内容没有变化......

如果您只需将file2.txt 中的appSettings 替换为file1.txt 的内容,那么:

@echo off
setlocal enableDelayedExpansion
set "replace="
>file2.txt.new (
  for /f "delims=" %%A in (file2.txt) do (
    set "ln=%%A"
    if "!ln:</appSettings>=!" neq "!ln!" (
      type file1.txt
      set "replace="
    )
    if not defined replace echo(!ln!
    if "!ln:<appSettings>=!" neq "!ln!" set replace=1
  )
)
move /y file2.txt.new file2.txt >nul

以上将保留在 file2.txt 中找到但在 file1.txt 中不存在的任何键。

如果您需要从 file2.txt 中保留 file1.txt 中不存在的密钥,那么修改 Magoo 的答案可能是最简单的解决方案:

@echo off
setlocal enableDelayedExpansion

for /f "delims==" %%A in ('set $ 2^>nul') do set "%%A="
set "replace="
>file2.txt.new (
  for /f "delims=" %%A in (file2.txt) do (
    set "ln=%%A"
    if not defined replace (
      echo(!ln!
      if "!ln:<appSettings>=!" neq "!ln!" set replace=1
    ) else if "!ln:</appSettings>=!" equ "!ln!" (
      for /f tokens^=2^ delims^=^" %%K in ("%%A") do set "$%%K=%%A"
    ) else (
      for /f "delims=" %%B in (file1.txt) do for /f tokens^=2^ delims^=^" %%K in ("%%B") do set "$%%K=%%B"
      for /f "tokens=1* delims==" %%B in ('set $') do echo(%%C
      echo(!ln!
      set "replace="
    )
  )
)
move /y file2.txt.new file2.txt >nul

上述两种解决方案都会损坏包含! 的内容。如果需要支持 !,可以进行一些更改。这些解决方案还假设密钥不区分大小写。

此外,这两种解决方案都会从 file2.txt 中删除空行。但这与 XML 文档无关。可以添加一些额外的代码来保留空行。

更新

这是第二个解决方案的修改版本,它在内容中保留了! 字符:

@echo off
setlocal disableDelayedExpansion

for /f "delims==" %%A in ('set $ 2^>nul') do set "%%A="
set "replace="
set "endReplace="
>file2.txt.new (
  for /f "delims=" %%A in (file2.txt) do (
    set "ln=%%A"
    if not defined replace (
      echo(%%A
      setlocal enableDelayedExpansion
      if "!ln:<appSettings>=!" neq "!ln!" (
        endlocal
        set replace=1
      ) else endlocal
    ) else (
      setlocal enableDelayedExpansion
      if "!ln:</appSettings>=!" equ "!ln!" (
        endlocal
        for /f tokens^=2^ delims^=^" %%K in ("%%A") do set "$%%K=%%A"
      ) else (
        endlocal
        for /f "delims=" %%B in (file1.txt) do for /f tokens^=2^ delims^=^" %%K in ("%%B") do set "$%%K=%%B"
        for /f "tokens=1* delims==" %%B in ('set $') do echo(%%C
        echo(%%A
        set "replace="
      )
    )
  )
)
move /y file2.txt.new file2.txt >nul

以下是基于原始问题中这些 file1.txt 和 file2.txt 规范的原始答案:

File1.txt(参考文件)

<add key="abc" value="123" />
<add key="def" value="456" />
<add key="ghi" value="789" />

File2.txt(目标文件)

<add key="def" value="blank" />
<add key="ghi" value="blank" />

我假设您文件中的所有行都与您显示的模板匹配(除了使用普通双引号而不是智能引号,正如 Magoo 指出的那样)。我还假设最终输出中的行顺序无关紧要,并且键不区分大小写。

假设键不包含空格。制表符或反斜杠,然后:

@echo off
>file1.txt.screen (for /f "tokens=2" %%A in (file1.txt) do echo( %%A )
>file2.txt.new (
  findstr /livg:file1.txt.screen file2.txt
  type file1.txt
)
del file1.txt.screen
move /y file2.txt.new file2.txt >nul

如果键可能包含空格或制表符,但不包含反斜杠,则:

@echo off
>file1.txt.screen (for /f tokens^=2^ delims^=^" %%A in (file1.txt) do echo( key="%%A" )
>file2.txt.new (
  findstr /livg:file1.txt.screen file2.txt
  type file1.txt
)
del file1.txt.screen
move /y file2.txt.new file2.txt >nul

如果键可能包含空格、制表符或反斜杠,则:

@echo off
setlocal disableDelayedExpansion
>file1.txt.screen (
  for /f tokens^=2^ delims^=^" %%A in (file1.txt) do (
    set "key=%%A"
    setlocal enableDelayedExpansion
    (echo( key="!key:\=\\!" )
    endlocal
  )
)
>file2.txt.new (
  findstr /livg:file1.txt.screen file2.txt
  type file1.txt
)
del file1.txt.screen
move /y file2.txt.new file2.txt >nul

由于这个 FINDSTR 错误:Why doesn't this FINDSTR example with multiple literal search strings find a match?

更新

以下是消除所有限制的不区分大小写的解决方案。

@echo off
setlocal disableDelayedExpansion
for /f tokens^=2^ delims^=^" %%A in (file1.txt) do (
  set "search= key="%%A" "
  setlocal enableDelayedExpansion
  (echo !search:\=\\!) >file2.txt.screen
  findstr /vlg:file2.txt.screen file2.txt >file2.txt.new
  move /y file2.txt.new file2.txt >nul
  endlocal
)
type file1.txt >>file2.txt
del file2.txt.screen

【讨论】:

  • Dbenham - 这与所需要的非常接近,只是我没有提到正在修改/添加的键上方和下方有字符串(应该保持不变)。我现在用这些完整的例子更新我的原始帖子。非常感谢!
  • “以上两种解决方案都会损坏包含 ! 的内容。如果需要支持 !,可以进行更改。”我才意识到!字符用于注释 file2.txt 中的行(这些需要保留)。简单的改变?
  • 经过进一步研究后,禁用 DelayedExpansion 会导致 !特点。看起来这是一个相当复杂的脚本更改来适应这个角色......任何建议都非常感谢,谢谢!
  • 没想到cmet不会通知评论过的用户,只是用@来通知;谢谢dbenham
  • 在您的“这是第二个解决方案的修改版本,保留内容中的字符”脚本中,对于行 if "!ln:&lt;appSettings&gt;=!" neq "!ln!" (,有没有办法在我们的字符串中有空格寻找?即if "!ln:&lt;appSettings&gt; workflow=!" neq "!ln!" (。我试过用双引号括起来
【解决方案2】:
@ECHO OFF
SETLOCAL
:: remove variables starting $ or #
For %%b IN ($ #) DO FOR  /F "delims==" %%a In ('set %%b 2^>Nul') DO SET "%%a="

FOR /f "delims=" %%a IN (reference.txt) DO FOR /f "tokens=3delims== " %%h IN ("%%a") DO (
 SET "$%%~h=%%a"
)
FOR /f "delims=" %%a IN (target.txt) DO FOR /f "tokens=3delims== " %%h IN ("%%a") DO (
 SET "#%%~h=%%a"
)
(
 FOR  /F "tokens=1*delims=$=" %%c In ('set $ 2^>Nul') DO (
  ECHO(%%d
  SET "#%%c="
 )
 FOR  /F "tokens=1*delims==" %%c In ('set # 2^>Nul') DO (
  ECHO(%%d
 )
)>newfile.txt

GOTO :EOF

您的源数据包含“智能引号” - 我假设您实际上使用了引号。

基本上,设置$keyname=line from reference;#keyname=line from target

然后输出所有$keyname 并清除所有具有相同键名的#keyname

最后,输出所有剩余的#keynames

结果出现在newfile.txt

【讨论】:

  • +1,有趣的方法。两个限制 - 1) 键值必须不区分大小写。 My answer 遇到同样的问题。 2) 您的密钥不得包含=。如果您首先处理目标文件并让两个文件都定义 $ 变量,则可以消除 # 变量。该引用将覆盖目标 $ 变量。然后你只需要一个 FOR /F 循环来产生输出。
  • 感谢您的回答 Magoo!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-01
  • 1970-01-01
  • 2017-06-01
  • 2013-05-02
  • 2023-04-08
相关资源
最近更新 更多