用于读取文件并替换字符串

时间:2016-09-12 07:20:24

标签: windows loops batch-file replace find

以下文件包含3个采购订单。每个采购订单的第一行以常量记录标识符开头(我输入 BOLD 字母):

850 00000000000

我需要搜索字符串" MC66F "在每个PO(斜体和BOLD)中。如果找到字符串,那么我需要替换客户ID。但是,客户ID" ABC00"在所有采购订单中。问题是我需要仅在包含字符串" MC66F"的采购订单中更新客户ID。与" ABC04"。

850 00000000000 123ABC45采购订单 ABC00 79 79 1 000056
850 BEG002000009 22123ABC45 20160909
850 CUR004000009欧元
850 REF00400000CR MC66F
850 DTM0170000013720160909
850 DTM0170000063 20160915
850 DTM0170000064 20160909
850 N1 04700000BY 5450534000031
850 N1 04700000SU 0728658000004
850 N1 04700000DP 5450534002370
850 N1 04700000IV 5450534005821
850 PO1083000001 0000000000000002EA200000000000009118 SAB00D9KR6T6
850 PO1083000002 0000000000000012EA200000000000015294 SAB0058FAEAS
850 00000000000 456ABC45 PO ABC00 18132 18132 1 000056
850 BEG002000009 22456ABC45 20160909
850 CUR004000009欧元
850 DTM0170000013720160909
850 DTM0170000063 20160914
850 DTM0170000064 20160909
850 N1 04700000BY 5450534000017
850 N1 04700000SU 608030938
850 N1 04700000DP 0534002349
850 N1 04700000IV 5450534005838
850 PO1083000001 0000000000000001EA200000000000010518 SAB00MYD9UP2
850 00000000000 789ABC45 PO ABC00 18133 18133 1 000056
850 BEG002000009 22789ABC45 20160909
850 CUR004000009欧元
850 DTM0170000013720160909
850 DTM0170000063 20160914
850 DTM0170000064 20160909
850 N1 04700000BY 5450534000017
850 N1 04700000SU 608030938
850 N1 04700000DP 0534002332
850 N1 04700000IV 5450534005838
850 PO1083000001 0000000000000002EA200000000000010518 SAB00MYD9UP2

我根据研究尝试的一些事情(以及我将如何在UNIX中执行)是将行存储在一个数组中,然后执行IF条件搜索数组中的字符串。我所能做的只是获取数组,但无法弄清楚如何利用IF条件。

    @echo off &setlocal enabledelayedexpansion
    for /F "delims=" %%a in (%INPUTFILE%) do (
      set /A count+=1
      set "array[!count!]=%%a"
    )
    for /L %%i in (1,1,%count%) do echo !array[%%i]! >> %OUTPUTFILE%

非常感谢任何帮助!

编辑:

for %%b in (inputfile.*) do (

rem Process all input lines and create output file

(
setlocal EnableDelayedExpansion

for /F "delims=" %%a in (%%~fb) do (
   set "line=%%a"
   rem If new order starts
   if "!line:~0,17!" equ "850   00000000000" (
      rem show the previous one
      if defined firstLine (
         echo !firstLine!
         type thisOrder.txt
         del thisOrder.txt
     )
      rem and start new order
      set "firstLine=%%a"
   ) else (
      rem If the string was found in this order
      if "!line:%search%=!" neq "%%a" (
         rem replace the customer ID in first line
         set "firstLine=!firstLine:%old%=%new%!"
   )    
      rem Save this line in this order
      echo %%a>> thisOrder.txt
   )

)
echo !firstLine!
type thisOrder.txt
del thisOrder.txt

) > output.%RANDOM%.txt

)

我试图在文件中生成一个随机数,因为我认为它只是在每次新迭代时覆盖文件。但这并没有奏效。似乎它正在输出额外的" 850 00000000000"在下一个PO的开头处进行细分。

3 个答案:

答案 0 :(得分:0)

我终于成功了。

步骤:

  • 读取输入文件内容并将其存储为环境变量(就像您所做的那样)。每个变量一行。不同之处在于它使用了一些额外的逻辑:它将文件视为一系列行,而不是一系列订单,每个订单都是一系列记录(记录是一行)。因此,(_ARRAY)env var是 2维(基于 0 的索引):

    • 第一个索引是订单
    • 第二个索引是订单中的记录(行)索引

    _OLENGTHS变量包含每个订单的最后一个索引(长度 - 1)(在我们的例子中 12 10 10 ),并且它将在下一阶段使用。

  • 处理先前创建的环境变量。它将每个订单头(第二个索引 0 )保存到另一个var中,以便稍后更改。然后它通过该订单的其余记录进行迭代,搜索客户。如果找到它,它会在标题中替换它。对于字符串/模式匹配,我使用了findstr /?

    注意:我不得不使用标签,因为有些嵌套变量扩展;这是我能做到的唯一方法。

  • 创建输出文件并将修改过的env vars内容转储到其中。

注意:

  • 代码效率可能非常低。我没有花时间优化它。
  • 它依赖于每个订单以 850 00000000000 开头的事实。
  • 它还依赖于以下事实:客户记录具有以下格式: 850 REF 后跟一系列数字和字母(大写+小写),然后是空格,然后是客户名称
  • 它依赖于订单记录,客户(需要更换)是第四个令牌。

以下是代码:

@echo off
setlocal enabledelayedexpansion
set _INPUTFILE=in.txt
set _OUTPUTFILE=out.txt
set _OIDX=-1
set _RIDX=0
set _OLENGTHS=
set _RECORD=
set _HEADER=
set _IDMARK=850 00000000000
set _REFMARK=850 REF
set _CUSTOMER=MC66F
set _NEWCUSTOMER=ABC04

:: Read the inoput file contents and store it in env vars
for /f "tokens=*" %%f in (%_INPUTFILE%) do (
    echo %%f | findstr /b /c:"%_IDMARK%" 1>nul
    if !errorlevel! equ 0 (
        set /a _OIDX+=1
        if "!_RECORD!" neq "" (
            set _OLENGTHS=!_OLENGTHS! !_RIDX!
        ) else (
            set _RECORD=_
        )
        set /a _RIDX=0
    ) else (
        set /a _RIDX+=1
    )
    set _ARRAY[!_OIDX!][!_RIDX!]=%%f
)
set _OLENGTHS=%_OLENGTHS% %_RIDX%

:: Do some processing on the env vars
set /a _OIDX=-1
for %%f in (%_OLENGTHS%) do (
    set /a _OIDX+=1
    call :set_header_var !_OIDX!
    for /l %%g in (1,1,%%f) do (
        call :process_record !_OIDX! %%g
    )
)

:: Dump all the env vars contents into the output file
copy nul %_OUTPUTFILE%
set /a _OIDX=-1
for %%f in (%_OLENGTHS%) do (
    set /a _OIDX+=1
    call :set_header_var !_OIDX!
    for /l %%g in (0,1,%%f) do (
        call :dump_var !_OIDX! %%g
    )
)

goto :eof

:process_record
    echo !_ARRAY[%1][%2]! | findstr /r /c:"^%_REFMARK%[0-9A-Za-z]* %_CUSTOMER%" 1>nul
    if !errorlevel! equ 0 (
        call :alter_header %1
    )
    goto :eof

:set_header_var
    set _HEADER=!_ARRAY[%1][0]!
    goto :eof

:alter_header
    for /f "tokens=1,2,3,4,*" %%h in ('echo !_HEADER!') do (
        set _ARRAY[%1][0]=%%h %%i %%j %_NEWCUSTOMER% %%l
    )
    goto :eof

:dump_var
    echo !_ARRAY[%1][%2]!>>%_OUTPUTFILE%
    goto :eof

运行后,输出文件看起来像输入文件,但第一行除外:

  

850 00000000000123ABC45采购订单 ABC04 79 79 1 000056

@ EDIT0 :我没有仔细阅读要求,我正在用字符串替换客户( ABC00 )来搜索( MC66F ),而不是新客户( ABC04 )。校正。

答案 1 :(得分:0)

@echo off
setlocal EnableDelayedExpansion

set "firstLine="
del thisOrder.txt 2>NUL

rem Process all input lines and create output file
(
for /F "delims=" %%a in (input.txt) do (
   set "line=%%a"
   rem If new order starts
   if "!line:~0,15!" equ "850 00000000000" (
      rem show the previous one
      if defined firstLine (
         echo !firstLine!
         type thisOrder.txt
         del thisOrder.txt
      )
      rem and start new order
      set "firstLine=%%a"
   ) else (
      rem If the search string was found in this order
      if "!line:MC66F=!" neq "%%a" (
         rem replace the customer ID in first line
         set "firstLine=!firstLine:ABC00=ABC04!"
      )
      rem Save this line in this order
      echo %%a>> thisOrder.txt
   )
)
echo !firstLine!
type thisOrder.txt
del thisOrder.txt
) > output.txt

所有工作参数都是按字面编写的,以使代码更清晰,但您可以在变量或参数中指定它们的值。例如,您可以使用以下行开始代码:

set "search=MC66F"
set "old=ABC00"
set "new=ABC04"

...然后调整代码中的相应行;例如:

rem If the search string was found in this order
if "!line:%search%=!" neq "%%a" (
   rem replace the customer ID in first line
   set "firstLine=!firstLine:%old%=%new%!"
)

答案 2 :(得分:-1)

尝试这样的事情

powershell -command "(gc -Delimiter %delim% %file%)
     -replace %regex0%, %replace0% 
     .....
     -replace %regexn%, %replacen%
     -join %delim% | Set-Content %newfile%"

*换行仅用于显示