问题
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