Batch: How to store values encountered during a regular expression search & replace (repl.bat)

て烟熏妆下的殇ゞ 提交于 2019-12-25 01:37:01

问题


Using Batch, I'm looking for a way to (1) search for a regular expression pattern and (2) store variables within that pattern... so I can use those variables while doing a search and replace.

I've been using REPL.BAT, which was created by @dbenham (original REPL.BAT post and earliest StackOverflow post). Here's an example of the scenario.

I search a document for the occurence of the following code:

driver.find_element_by_id("username").send_keys("rwbyrd")
driver.find_element_by_id("password").send_keys("password")

And replace it with...

login("rwbyrd","password")

Using the following Batch code:

type %filename% | repl "\sdriver\.find_element_by_id\(\x22username\x22\)\.send_keys\(\x22rwbyrd\x22\)\s*driver\.find_element_by_id\(\x22password\x22\)\.send_keys\(\x22password\x22\)"       "login(\x22rwbyrd\x22,\x22password\x22)" MX >%filename%.new

NOTE: \x22 = Hex for double quotes

What I am looking for is a way to store the [username] 'rwbyrd' and [password] 'password' values from the code I'm searching for & use those values when doing a replace. I'd like to find a way to achieve this within the REPL.BAT command, but I will take what I can get :). Does anyone know how to achieve this? Thanks ahead of time!


回答1:


If you haven't done this already, I strongly recommend you execute the following commands from the command prompt:

To get help specific to REPL.BAT:

repl /?

To get help about the JScript regular expressions used by REPL.BAT (opens up MicroSoft documentation in your web browser)

repl /?regex

To get help about the replace submatch features - the "variables" you are looking for (opens up MicroSoft documentation in your web browser)

repl /?replace

I replaced the leading \s with \b (word boundry) in your search regex. I also use un-escaped parentheses to capture the username and password values so that I can use them in the replacement string. The .*? matches the content within the parentheses literals (non-greedy match). One cosmetic change was to use \q instead of \x22.

type %filename% | repl "\bdriver\.find_element_by_id\(\qusername\q\)\.send_keys\((.*?)\)\s*driver\.find_element_by_id\(\qpassword\q\)\.send_keys\((.*?)\)" "login($1,$2)" MX >%filename%.new

Update

Based on OP's comment, and Aacini's answer, I've updated REPL.BAT to accept a J option to specify the replacement value as a JScript expression.

The following example will convert the username to upper case:

type %filename% | repl "\bdriver\.find_element_by_id\(\qusername\q\)\.send_keys\((.*?)\)\s*driver\.find_element_by_id\(\qpassword\q\)\.send_keys\((.*?)\)" "'login('+$[1].toUpperCase()+','+$[2]+')'" MXJ >%filename%.new

See http://www.dostips.com/forum/viewtopic.php?p=37855#p37855 for details and examples.




回答2:


When you use regular expressions you must note that \s metacharacter matches "Any white-space character. This includes space, tab, and form feed.", but NOT a CR+LF pair end-of-line characters, so you must include they in the regular expression.

Exist another program similar to dbenham's REPL.BAT; it is called FindRepl.bat and you may download it from this site. In FindRepl replacement string you may include $1, $2, etc. to get the value of matched "sub-expressions" enclosed in parentheses. For example, this input file:

Any previous line
    driver.find_element_by_id("username").send_keys("rwbyrd")
    driver.find_element_by_id("password").send_keys("password")
any posterior line

... processed with FindRepl.bat via this line:

type filename.txt | findrepl /Q:' "\sdriver\.find_element_by_id\('username'\)\.send_keys\('(.*)'\)\r\n\s*driver\.find_element_by_id\('password'\)\.send_keys\('(.*)'\)" "login('$1','$2')"

... produce this output:

Any previous line
   login("rwbyrd","password")
any posterior line

You may test if the same regular expression produce the same output in REPL.BAT.

PS - I strongly encourage you to see the regular expression documentation suggested by FindRepl /?.


EDIT: I borrowed the idea stated on dbenham's answer comments and used it to implement the processing of the matched substrings via a JScript expression placed in the replacement text in my FindRepl.bat program; the only requirement to do that is to include the new /J (JScript expression) switch and correctly write the replacement expression.

The modification in the program was relatively simple and required just 5 new lines, that included 2 new lines of documentation; I used the example at this site as base to complete the modification. The listing below is the result of comparing the original and new versions of FindRepl.bat program via fc /N FindRepl.bat "FindRepl Modified.bat" command:

Comparing files FindRepl.bat and FINDREPL MODIFIED.BAT
***** FindRepl.bat
   28:  FINDREPL [/I] [/V] [/N] rSearch [/E:rEndBlk] [/O:s:e] [/B:rBlock] [/$:s1...]
   29:           [[/R] [/A] sReplace] [/Q:c] [/S:sSource]
   30:  
***** FINDREPL MODIFIED.BAT
   28:  FINDREPL [/I] [/V] [/N] rSearch [/E:rEndBlk] [/O:s:e] [/B:rBlock] [/$:s1...]
   29:           [[/R] [{/J|/A}] sReplace] [/Q:c] [/S:sSource]
   30:  
*****

***** FindRepl.bat
   39:    /R         Prints only replaced lines, instead of all file lines.
   40:    /A         Specifies that sReplace has alternative values matching rSearch.
***** FINDREPL MODIFIED.BAT
   39:    /R         Prints only replaced lines, instead of all file lines.
   40:    /J         Specifies that sReplace is a JScript expression, not a string.
   41:    /A         Specifies that sReplace has alternative values matching rSearch.
*****

***** FindRepl.bat
   48:  The replacement string may use $ to retrieve saved submatched substrings. See:
   49:  http://msdn.microsoft.com/en-us/library/t0kbytzc(v=vs.84).aspx
   50:  Use /A switch to insert several values separated by pipe in rSearch/sReplace.
***** FINDREPL MODIFIED.BAT
   49:  The replacement string may use $ to retrieve saved submatched substrings. See:
   50:  http://msdn.microsoft.com/en-us/library/t0kbytzc(v=vs.84).aspx   If /J switch
   51:  is given, the replacement text is an expression that must use submatched $.
   52:  Use /A switch to insert several values separated by pipe in rSearch/sReplace.
*****

***** FindRepl.bat
   89:  // FINDREPL [/I] [/V] [/N] rSearch [/E:rEndBlk] [/O:s:e] [/B:rBlock] [/$:s1...]
   90:  //          [[/R] [/A] sReplace] [/Q:c] [/S:source]
   91:  
***** FINDREPL MODIFIED.BAT
   91:  // FINDREPL [/I] [/V] [/N] rSearch [/E:rEndBlk] [/O:s:e] [/B:rBlock] [/$:s1...]
   92:  //          [[/R] [{/J|/A}] sReplace] [/Q:c] [/S:source]
   93:  
*****

***** FindRepl.bat
  105:      justReplaced = options.Exists("R"),
  106:      replace      = undefined,
***** FINDREPL MODIFIED.BAT
  107:      justReplaced = options.Exists("R"),
  108:      JSexpr       = false,
  109:      replace      = undefined,
*****

***** FindRepl.bat
  159:     if ( quote != undefined ) replace = replace.replace(eval("/"+quote+"/g"),'"');
  160:     if ( options.Exists("A") ) {  // Enable alternation replacements from "Se|ar|ch" to "Re|pla|ce"
  161:        var Asearch = search.split("|"),
***** FINDREPL MODIFIED.BAT
  162:     if ( quote != undefined ) replace = replace.replace(eval("/"+quote+"/g"),'"');
  163:     if ( options.Exists("J") ) {  // Replacement text is a JScript expression with the return value of function($0,$1,$2)
  164:        JSexpr = true;
  165:     } else if ( options.Exists("A") ) {  // Enable alternation replacements from "Se|ar|ch" to "Re|pla|ce"
  166:        var Asearch = search.split("|"),
*****

***** FindRepl.bat
  335:           if ( match(fileContents[lineNumber-1],search) ) {
  336:              WScript.Stdout.WriteLine(fileContents[lineNumber-1].replace(search,replace));
  337:              result++;
***** FINDREPL MODIFIED.BAT
  340:           if ( match(fileContents[lineNumber-1],search) ) {
  341:              WScript.Stdout.WriteLine(fileContents[lineNumber-1].replace(search,JSexpr?function($0,$1,$2){return(eval(replace))}:replace));
  342:              result++;
*****

***** FindRepl.bat
  345:     } else {  // Replace on entire file
  346:        WScript.Stdout.Write(fileContents.replace(search,replace));
  347:     }
***** FINDREPL MODIFIED.BAT
  350:     } else {  // Replace on entire file
  351:        WScript.Stdout.Write(fileContents.replace(search,JSexpr?function($0,$1,$2){return(eval(replace))}:replace));
  352:     }
*****

Previous listing should be enough to obtain the modified version of FindRepl.bat. This way, in order to replace the first matched subexpression to uppercase letters, just use:

type filename | findrepl "(.*)" /J "$1.toUpperCase()"

This feature is very powerful, because the replacement text may be any valid JScript expression that may use any character processing method. For example:

type filename | findrepl "before (.*) after" /J "'before'+$1.substr(0,4).toUpperCase()+'after'"

You may even introduce a much more complex JScript replacement expression that include several assignments (to auxiliary variables) via comma JScript operator.



来源:https://stackoverflow.com/questions/26746983/batch-how-to-store-values-encountered-during-a-regular-expression-search-repl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!