5

我编写了一个批处理文件,我想用另一个 .txt 文件中的字符串覆盖键字符串。

目前它完美地复制了新的 File.txt 文件,但不会用 OldFile.txt 文件中的字符串替换字符串。

File.txt 文件中的字符串示例:

...

# 密码密码
=

# AccountName
帐户=

# TownName
城镇=

# 邮编
邮编=

# LocationChangedDate
LocationChanged=

我要替换的 OldFile.txt 文件中的字符串示例:

...

#密码
Pword=ABC

#AccountName
帐户=123

# TownName
Town=LDN

# 邮编
邮编=WS77TP

# LocationChangedDate
LocationChanged=01/01/2015

有人可以指出我正确的方向或解释我在哪里犯了错误吗?

@echo off

setlocal disableDelayedExpansion

::Variables
set InputFile=F:\EXCHANGE\3\Machine\File.txt
set OutputFile=F:\EXCHANGE\3\File-New.txt
set CopyFile=F:\EXCHANGE\3\OldMachine\OldFile.txt

set _strFindPword=Pword=.*
for /F "delims=" %%A in ('findstr /x "Pword=.*" %CopyFile%') do set _strInsertPword=%%A

echo.%_strInsertPword%

set _strFindAccount=Account=.*
for /F "delims=" %%B in ('findstr /x "Account=.*" %CopyFile%') do set _strInsertAccount=%%B

echo.%_strInsertAccount%

set _strFindTown=Town=.*
for /F "delims=" %%C in ('findstr /x "Town=.*" %CopyFile%') do set _strInsertTown=%%C

echo.%_strInsertTown%

set _strFindLocationChanged=LocationChanged=.*
for /F "delims=" %%D in ('findstr /x "LocationChanged=.*" %CopyFile%') do set _strInsertLocationChanged=%%D

echo.%_strInsertLocationChanged%

set _strFindPostcode=Postcode=.*
for /F "delims=" %%E in ('findstr /x "Postcode=.*" %CopyFile%') do set _strInsertPostcode=%%E

echo.%_strInsertPostcode%


(
  for /F "delims=" %%L in ('findstr /n "^" "%InputFile%"') do (
    set "line=%%L"
    setlocal EnableDelayedExpansion
    set "line=!line:*:=!"
    if "%%L" equ "_strFindPword" (echo.!_strInsertPword!) else (
       if "%%L" equ "%_strFindAccount%" (echo.!_strInsertAccount!) else (
          if "%%L" equ "%_strFindTown%" (echo.!_strInsertTown!) else (
             if "%%L" equ "%_strFindLocationChanged%" (echo.!_strInsertLocationChanged!) else (
                if "%%L" equ "%_strFindPostcode%" (echo.!_strInsertPostcode!) else (echo.!line!)
             )
          )
       )
    )
    endlocal
  )
) > "%OutputFile%"

del %InputFile% 

ren %OutputFile% File.txt



pause
4

4 回答 4

2

我想我终于明白了...

它能做什么:

  • 它遍历OldFile.txt内容,搜索标记,如果发现它们被存储到环境变量中以在嵌套步骤中使用(例如,对于_PWD值为 的标记(变量)Pword=,它将创建一个_PWDCONTENTS内容为Pword=ABC)。
  • 它遍历File.txt内容,搜索相同的标记,如果找到一个标记,则将相应的CONTENTS变量转储到OutFile.txt中,否则转储到原始行。因为这发生在内部for循环中,所以我不得不添加一些额外的逻辑(_WROTEvar)以避免多次编写相同的行。

备注

  • 它应该(好吧,除了做它应该做的)是“可配置的”(代码很复杂,如果你愿意的话,它会走向:)),这意味着如果标记之间有变化,代码不应该改变(好吧会有代码更改,但不会在功能部分仅在变量定义中)。让我详细说明:

    • 如果您不再需要替换Town=字符串,那么您所要做的就是_TOWN_ALL:中删除set _ALL=_PWD _ACCT _POST _LOC
    • 反过来:如果你想添加一些其他标签(我们称之为Name),你必须创建一个新的环境变量:set _NAME=Name=并将其添加到_ALL: set _ALL=_PWD _ACCT _TOWN _POST _LOC _NAME
  • 作为间接结果,我没有关注性能,因此它可能运行缓慢。无论如何,我试图将磁盘访问(非常缓慢)保持在最低限度(一个例子是当有 2 个for循环时,一个迭代文件内容的循环 - 假设每次迭代都需要一个磁盘访问;这可能不是真的,并且Win有 IO 缓冲——它是外部的)。

  • 我“注释掉”了文件的最后一行,以避免覆盖原始文件。如果需要该行为,只需删除rem开头的 。

这是批处理代码:

@echo off
setlocal enabledelayedexpansion

set _INFILE="File.txt"
set _OUTFILE="NewFile.txt"
set _OLDFILE="OldFile.txt"


set _PWD=Pword=
set _ACCT=Account=
set _TOWN=Town=
set _POST=Postcode=
set _LOC=LocationChanged=
set _ALL=_PWD _ACCT _TOWN _POST _LOC

echo Parsing old file contents...

for /f "tokens=*" %%f in ('type !_OLDFILE!') do (
    for %%g in (!_ALL!) do (
        echo %%f | findstr /b /c:!%%g! 1>nul
        if "!errorlevel!" equ "0" (
            set %%gCONTENTS=%%f
        )
    )
)

copy nul %_OUTFILE%
echo Merging the old file contents into the new file...
set _WROTE=0

for /f "tokens=*" %%f in ('findstr /n "^^" !_INFILE!') do (
    set _TMPVAR0=%%f
    set _TMPVAR0=!_TMPVAR0:*:=!
    for %%g in (!_ALL!) do (
        echo !_TMPVAR0! | findstr /b /c:!%%g! 1>nul
        if "!errorlevel!" equ "0" (
            echo.!%%gCONTENTS!>>!_OUTFILE!
            set _WROTE=1
        )
    )
    if "!_WROTE!" equ "0" (
        echo.!_TMPVAR0!>>!_OUTFILE!
    ) else (
        set _WROTE=0
    )
)

rem copy /-y %_OUTFILE% %_INFILE%

@EDIT0:使用@StevoStephenson 建议(作为问题片段的一部分),我将(第二个)外部for循环替换('findstr /n "^^" !_INFILE!')为以包含空行,因此第三个注释不再适用(删除)。还做了一些小的更改以允许在其路径中包含SPACE的文件。

于 2016-09-13T16:45:10.690 回答
0

也许它像这样工作

set CopyFile=oldfile.txt
set InputFile=newfile.txt

set str_search="Pword"
for /f "delims=" %%i in ('findstr %str_search% %copyfile%') do set str_replace=%%i
set str_replace="%str_replace%"
echo %str_search%
echo %str_replace%
pause

CALL :far %InputFile% %str_search% %str_replace%
EXIT /B 0

:far
setlocal enableextensions disabledelayedexpansion

set "search=%2"
set "replace=%3"
::remove quotes
set search=%search:"=%
set replace=%replace:"=%
echo %search%
echo %replace%

set "textFile=%1"

for /f "delims=" %%i in ('type "%textFile%" ^& break ^> "%textFile%" ') do (
    set "line=%%i"
    setlocal enabledelayedexpansion
    set "line=!line:%search%=%replace%!"
    >>"%textFile%" echo(!line!
    endlocal
)
EXIT /B 0

for /f "delims=" %%i in ('findstr %str_search% %copyfile%') do set str_replace=%%i您将具有所需信息的变量写入 str_replace 行。之后,您的程序调用了一个嵌入的查找和替换函数(:far),我从批处理脚本中无耻地窃取来查找和替换文本文件中的字符串,而无需创建额外的输出文件来存储修改后的文件 此函数查找字符串“ Pword”并将其替换为旧文件中的 find 行。

注意:这并不能完全解决您的问题,因为您的新文件必须像这样。

#Password
Pword

因此,如果您松开=它,它会起作用,否则它不会起作用。我希望这可以帮助您解决问题。

于 2016-09-13T15:52:58.103 回答
0

它并不完美,但这对你来说可能没问题:

@Echo Off
Setlocal EnableExtensions DisableDelayedExpansion

(Set InputFile=F:\EXCHANGE\3\Machine\File.txt)
(Set OutputFile=F:\EXCHANGE\3\File-New.txt)
(Set CopyFile=F:\EXCHANGE\3\OldMachine\OldFile.txt)

For /F "Delims=" %%I In (
    'FindStr/B "Pword= Account= Town= LocationChanged= Postcode=" "%CopyFile%"'
    ) Do Set %%I

(For /F "Tokens=1-2* Delims=]=" %%I In ('Find /V /N ""^<"%InputFile%"') Do (
    Echo(%%J|FindStr/B # || (If Defined %%J (Call Echo=%%J=%%%%J%%) Else (
            If "%%J" NEq "" (Echo=%%J=%%K) Else (Echo=)))))>%OutputFile%
Timeout -1
EndLocal
Exit/B

我把删除和重命名留给你在最后添加。

于 2016-09-13T18:09:00.393 回答
0

此解决方案应该比其他解决方案快得多。
它还将保留空行和包含!and的行^

它只需要一次findstr调用即可收集所有单词的旧值。
第二个确定需要更新 findstr的所有行(按行号) 。infile

@echo off
setlocal EnableDelayedExpansion

set "_INFILE=File.txt"
set "_OUTFILE=NewFile.txt"
set "_OLDFILE="OldFile.txt"

set "_WORDS=Pword= Account= Town= Postcode= LocationChanged="

REM *** get all values for the key words
for /F "tokens=1,* delims==" %%L in ('findstr "!_WORDS!" "!_OLDFILE!"') do (
    for /F %%S in ("%%L") do (
        set "word[%%S]=%%M"
    )
)

REM *** Find all lines which needs an update
set wordIdx=0
for /F "tokens=1,2,* delims=:= " %%1 in ('findstr /n "!_WORDS!" "!_INFILE!"') do (
    set "lines[!wordIdx!].line=%%1"
    set "lines[!wordIdx!].word=%%2"
    set "replace=!word[%%2]!"
    set "lines[!wordIdx!].replace=!replace!"
    set /a wordIdx+=1
)

REM *** copy the infile to the outfile
REM *** Replace only the lines which are marked by line numbers
echo Parsing old file contents...
set nextWordIdx=0
set /a searchLine=lines[!nextWordIdx!].line
set lineNo=0
setlocal DisableDelayedExpansion
(
    for /f "tokens=*" %%L in ('findstr /n "^" "%_INFILE%"') do (
        set "line=%%L"
        set /a lineNo+=1
        setlocal EnableDelayedExpansion
        set "line=!line:*:=!"
        if !lineNo! equ !searchLine! (
            (echo(!line!!lines[0].replace!)
            set /a nextWordIdx+=1
            for /F %%R in ("!nextWordIdx!") do (
                endlocal
                set /a nextWordIdx=%%R
                set /a searchLine=lines[%%R].line
            )
        ) ELSE (
            (echo(!line!)
            endlocal
        )
    )
) > "!_OUTFILE!"
于 2016-09-19T09:22:28.787 回答