how to search and replace case sensitive string using batch

前端 未结 3 1061
旧时难觅i
旧时难觅i 2021-01-15 15:08

I want to search and replace case sensitive string

like if I have rise Rise RISE in a text file I only want to replace string \"rise\" the code below is replace a

3条回答
  •  花落未央
    2021-01-15 15:57

    This is a subject that has interested me for a long time. My personal criteria is that the solution is a script that utilizes only native Windows commands, and that it be compatible with all Windows versions from XP onward.

    I have developed two solutions: 1) A pure batch solution that I believe is about as efficient as is possible for batch, and 2) a hybrid JScript/batch solution that is extremely powerful and also very fast.

    I have pretty much abandoned the pure batch solution in favor of the JScript/batch hybrid because the hybrid is more powerful with full regex support, and it is MUCH faster.

    1) Pure batch solution: MODFILE.BAT

    I first published this at DOSTIPS: The "ultimate" file search and replace batch utility

    The batch function can be used as a stand-alone utility, or incorporated within a larger batch script.

    Assuming the function is a stand-alone utility in a file named MODFILE.BAT that is either in your current folder, or else somewhere within your PATH, then your script becomes:

    @echo off
    setlocal enableDelayedExpansion
    
    set file="c:\Users\rawal\Desktop\a\file.txt"
    set "OldStr=rise"
    set "NewStr="
    set /p "NewStr=Enter some text: "
    
    call ModFile "%file%" OldStr NewStr
    

    Here is the ModFile function itself. Full documentation is embedded within the script. I've taken great pains to optimize the code, and eliminate limitations that plague most batch solutions. But there are a few remaining limitations that are listed within the documentation.

    @echo off
    :modFile File SearchVar [ReplaceVar] [/I]
    ::
    ::  Perform a search and replace operation on each line within File.
    ::
    ::  SearchVar = A variable containing the search string.
    ::
    ::  ReplaceVar = A variable containing the replacement string.
    ::               If ReplaceVar is missing or is not defined then the
    ::               search string is replaced with an empty string.
    ::
    ::  The /I option specifies a case insensitive search.
    ::
    ::  A backup of the original File is made with an extension of .bak
    ::  prior to making any changes.
    ::
    ::  The number of replacements made is returned as errorlevel.
    ::
    ::  If an error occurs then no changes are made and
    ::  the errorlevel is set to -1.
    ::
    ::  Limitations
    ::    - File must use Windows style line terminators .
    ::    - Trailing control characters will be stripped from each line.
    ::    - The maximum input line length is 1021 characters.
    ::
    setlocal enableDelayedExpansion
    
      ::error checking
      if "%~2"=="" (
        >&2 echo ERROR: Insufficient arguments
        exit /b -1
      )
      if not exist "%~1" (
        >&2 echo ERROR: Input file "%~1" does not exist
        exit /b -1
      )
      2>nul pushd "%~1" && (
        popd
        >&2 echo ERROR: Input file "%~1" does not exist
        exit /b -1
      )
      if not defined %~2 (
        >&2 echo ERROR: searchVar %2 not defined
        exit /b -1
      )
      if /i "%~3"=="/I" (
        >&2 echo ERROR: /I option can only be specified as 4th argument
        exit /b -1
      )
      if "%~4" neq "" if /i "%~4" neq "/I" (
        >&2 echo ERROR: Invalid option %4
        exit /b -1
      )
    
      ::get search and replace strings
      set "_search=!%~2!"
      set "_replace=!%~3!"
    
      ::build list of lines that must be changed, simply exit if none
      set "replaceCnt=0"
      set changes="%temp%\modFileChanges%random%.tmp"
      <"%~1" find /n %~4 "!_search:"=""!^" >%changes% || goto :cleanup
    
      ::compute length of _search
      set "str=A!_search!"
      set searchLen=0
      for /l %%A in (12,-1,0) do (
        set /a "searchLen|=1<<%%A"
        for %%B in (!searchLen!) do if "!str:~%%B,1!"=="" set /a "searchLen&=~1<<%%A"
      )
    
      ::count number of lines + 1
      for /f %%N in ('find /v /c "" ^<"%~1"') do set /a lnCnt=%%N+1
    
      ::backup source file
      if exist "%~1.bak" del "%~1.bak"
      ren "%~1" "%~nx1.bak"
    
      ::initialize
      set "skip=2"
    
      <"%~1.bak" (
    
        %=for each line that needs changing=%
        for %%l in (!searchLen!) do for /f "usebackq delims=[]" %%L in (%changes%) do (
    
          %=read and write preceding lines that don't need changing=%
          for /l %%N in (!skip! 1 %%L) do (
            set "ln="
            set /p "ln="
            if defined ln if "!ln:~1021!" neq "" goto :lineLengthError
            echo(!ln!
          )
    
          %=read the line that needs changing=%
          set /p "ln="
          if defined ln if "!ln:~1021!" neq "" goto :lineLengthError
    
          %=compute length of line=%
          set "str=A!ln!"
          set lnLen=0
          for /l %%A in (12,-1,0) do (
            set /a "lnLen|=1<<%%A"
            for %%B in (!lnLen!) do if "!str:~%%B,1!"=="" set /a "lnLen&=~1<<%%A"
          )
    
          %=perform search and replace on line=%
          set "modLn="
          set /a "end=lnLen-searchLen, beg=0"
          for /l %%o in (0 1 !end!) do (
            if %%o geq !beg! if %~4 "!ln:~%%o,%%l!"=="!_search!" (
              set /a "len=%%o-beg"
              for /f "tokens=1,2" %%a in ("!beg! !len!") do set "modLn=!modLn!!ln:~%%a,%%b!!_replace!"
              set /a "beg=%%o+searchLen, replaceCnt+=1"
            )
          )
          for %%a in (!beg!) do set "modLn=!modLn!!ln:~%%a!"
    
          %=write the modified line=%
          echo(!modLn!
    
          %=prepare for next iteration=%
          set /a skip=%%L+2
        )
    
        %=read and write remaining lines that don't need changing=%
        for /l %%N in (!skip! 1 !lnCnt!) do (
          set "ln="
          set /p "ln="
          if defined ln if "!ln:~1021!" neq "" goto :lineLengthError
          echo(!ln!
        )
    
      ) >"%~1"
    
      :cleanup
      del %changes%
    exit /b %replaceCnt%
    
    :lineLengthError
      del %changes%
      del "%~1"
      ren "%~nx1.bak" "%~1"
      >&2 echo ERROR: Maximum input line length exceeded. Changes aborted.
    exit /b -1
    


    2) Hybrid JScript/batch solution: REPL.BAT

    I first published this at DOSTIPS: regex search and replace for batch - Easily edit files!

    I really love this utility. Most batch scripting I do as a hobby, but I use this utility regularly in my day job. It is extremely powerful and fast, yet requires very little code. It supports regular expression search and replace, but also has an /L literal option. The search is case sensitive by default.

    Assuming REPL.BAT is either in your current folder, or else somewhere within your PATH, then your code becomes:

    @echo off
    setlocal enableDelayedExpansion
    
    set "file=c:\Users\rawal\Desktop\a\file.txt"
    set "OldStr=rise"
    set "NewStr="
    set /p "NewStr=Enter some text: "
    
    type "%file%" | repl OldStr NewStr VL >"%file%.new"
    move /y "%file%.new" "%file%" >nul
    

    I use the L option to force a literal search instead of the default regex search, and the V option to read the search and replace values directly from environment variables instead of passing string literals.

    Here is the actual REPL.BAT utility. Full documentation is embedded within the script.

    @if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment
    
    ::************ Documentation ***********
    :::
    :::REPL  Search  Replace  [Options  [SourceVar]]
    :::REPL  /?
    :::
    :::  Performs a global search and replace operation on each line of input from
    :::  stdin and prints the result to stdout.
    :::
    :::  Each parameter may be optionally enclosed by double quotes. The double
    :::  quotes are not considered part of the argument. The quotes are required
    :::  if the parameter contains a batch token delimiter like space, tab, comma,
    :::  semicolon. The quotes should also be used if the argument contains a
    :::  batch special character like &, |, etc. so that the special character
    :::  does not need to be escaped with ^.
    :::
    :::  If called with a single argument of /? then prints help documentation
    :::  to stdout.
    :::
    :::  Search  - By default this is a case sensitive JScript (ECMA) regular
    :::            expression expressed as a string.
    :::
    :::            JScript regex syntax documentation is available at
    :::            http://msdn.microsoft.com/en-us/library/ae5bf541(v=vs.80).aspx
    :::
    :::  Replace - By default this is the string to be used as a replacement for
    :::            each found search expression. Full support is provided for
    :::            substituion patterns available to the JScript replace method.
    :::            A $ literal can be escaped as $$. An empty replacement string
    :::            must be represented as "".
    :::
    :::            Replace substitution pattern syntax is documented at
    :::            http://msdn.microsoft.com/en-US/library/efy6s3e6(v=vs.80).aspx
    :::
    :::  Options - An optional string of characters used to alter the behavior
    :::            of REPL. The option characters are case insensitive, and may
    :::            appear in any order.
    :::
    :::            I - Makes the search case-insensitive.
    :::
    :::            L - The Search is treated as a string literal instead of a
    :::                regular expression. Also, all $ found in Replace are
    :::                treated as $ literals.
    :::
    :::            B - The Search must match the beginning of a line.
    :::                Mostly used with literal searches.
    :::
    :::            E - The Search must match the end of a line.
    :::                Mostly used with literal searches.
    :::
    :::            V - Search and Replace represent the name of environment
    :::                variables that contain the respective values. An undefined
    :::                variable is treated as an empty string.
    :::
    :::            M - Multi-line mode. The entire contents of stdin is read and
    :::                processed in one pass instead of line by line. ^ anchors
    :::                the beginning of a line and $ anchors the end of a line.
    :::
    :::            X - Enables extended substitution pattern syntax with support
    :::                for the following escape sequences:
    :::
    :::                \\     -  Backslash
    :::                \b     -  Backspace
    :::                \f     -  Formfeed
    :::                \n     -  Newline
    :::                \r     -  Carriage Return
    :::                \t     -  Horizontal Tab
    :::                \v     -  Vertical Tab
    :::                \xnn   -  Ascii (Latin 1) character expressed as 2 hex digits
    :::                \unnnn -  Unicode character expressed as 4 hex digits
    :::
    :::                Escape sequences are supported even when the L option is used.
    :::
    :::            S - The source is read from an environment variable instead of
    :::                from stdin. The name of the source environment variable is
    :::                specified in the next argument after the option string.
    :::
    
    ::************ Batch portion ***********
    @echo off
    if .%2 equ . (
      if "%~1" equ "/?" (
        findstr "^:::" "%~f0" | cscript //E:JScript //nologo "%~f0" "^:::" ""
        exit /b 0
      ) else (
        call :err "Insufficient arguments"
        exit /b 1
      )
    )
    echo(%~3|findstr /i "[^SMILEBVX]" >nul && (
      call :err "Invalid option(s)"
      exit /b 1
    )
    cscript //E:JScript //nologo "%~f0" %*
    exit /b 0
    
    :err
    >&2 echo ERROR: %~1. Use REPL /? to get help.
    exit /b
    
    ************* JScript portion **********/
    var env=WScript.CreateObject("WScript.Shell").Environment("Process");
    var args=WScript.Arguments;
    var search=args.Item(0);
    var replace=args.Item(1);
    var options="g";
    if (args.length>2) {
      options+=args.Item(2).toLowerCase();
    }
    var multi=(options.indexOf("m")>=0);
    var srcVar=(options.indexOf("s")>=0);
    if (srcVar) {
      options=options.replace(/s/g,"");
    }
    if (options.indexOf("v")>=0) {
      options=options.replace(/v/g,"");
      search=env(search);
      replace=env(replace);
    }
    if (options.indexOf("l")>=0) {
      options=options.replace(/l/g,"");
      search=search.replace(/([.^$*+?()[{\\|])/g,"\\$1");
      replace=replace.replace(/\$/g,"$$$$");
    }
    if (options.indexOf("b")>=0) {
      options=options.replace(/b/g,"");
      search="^"+search
    }
    if (options.indexOf("e")>=0) {
      options=options.replace(/e/g,"");
      search=search+"$"
    }
    if (options.indexOf("x")>=0) {
      options=options.replace(/x/g,"");
      replace=replace.replace(/\\\\/g,"\\B");
      replace=replace.replace(/\\b/g,"\b");
      replace=replace.replace(/\\f/g,"\f");
      replace=replace.replace(/\\n/g,"\n");
      replace=replace.replace(/\\r/g,"\r");
      replace=replace.replace(/\\t/g,"\t");
      replace=replace.replace(/\\v/g,"\v");
      replace=replace.replace(/\\x[0-9a-fA-F]{2}|\\u[0-9a-fA-F]{4}/g,
        function($0,$1,$2){
          return String.fromCharCode(parseInt("0x"+$0.substring(2)));
        }
      );
      replace=replace.replace(/\\B/g,"\\");
    }
    var search=new RegExp(search,options);
    
    if (srcVar) {
      WScript.Stdout.Write(env(args.Item(3)).replace(search,replace));
    } else {
      while (!WScript.StdIn.AtEndOfStream) {
        if (multi) {
          WScript.Stdout.Write(WScript.StdIn.ReadAll().replace(search,replace));
        } else {
          WScript.Stdout.WriteLine(WScript.StdIn.ReadLine().replace(search,replace));
        }
      }
    }
    

提交回复
热议问题