vscode regex sub match evaluate instead of concatenate? - regex

Test 300
Test 301
Test 302
I can use regex find to loop through these:
Test (3[0-9]*)
When I try replace with math it concatenates instead of evaluates?
Test $1-100
So, it becomes:
Test 300-100
Is it possible to evaluate instead of concatenate, so it becomes:
Test 200
Thanks.

You can use the VS Code Super Replace extension to achieve this.
Find field is the regular expression
Replace is the replace expression. Sub match with $$index syntax will be resolved using the function in Processing function field
Here is an example of use that answers your question :

There are more extensions that can do this now, including one I wrote Find and Transform.
With this keybinding:
{
"key": "alt+m", // whatever keybinding you want
"command": "findInCurrentFile",
"args": {
"find": "(?<=Test\\s)(3\\d\\d)", // get 300+ in capture group 1
"replace": "$${ return $1 - 100 }", // subtract 100 from capture group 1
"isRegex": true
}
}

Related

Finding and replacing key: value pairs

I'm in the process of porting over a Python library to JavaScript / TypeScript. To help myself out, I'm trying to develop various regex rules that I can apply to files that will automatically convert a lot of the syntax and at least get me close, cleaning up where needed.
I've got the following example:
https://regex101.com/r/mIr0pl/1
this.mk(attrs={keyCollection.key: 40}))
this.mk(attrs={keyCollection.key: 50, override.key: override.value})
this.mk(attrs={keyCollection.key: 60,
override.key: override.value})
I am trying to do a Find/Replace in my editor, to find all key: value pairs associated with attrs dictionaries. Here's the regex I've got:
/attrs={(.+?):\s*(.+?)}/gms
I want to convert it to this:
this.mk(attrs=[[keyCollection.key, 40]]))
this.mk(attrs=[[keyCollection.key, 50], [override.key, override.value]])
this.mk(attrs=[[keyCollection.key, 60],
[override.key, override.value]])
I'm having trouble first nailing down the regex to get the repeated key: value groups, and then also how I would go about utilizing those repeated groups in a replace.
(my editor is VSCode, but I'm using this nifty extension to run these modifications: https://marketplace.visualstudio.com/items?itemName=bhughes339.replacerules)
Any help would be appreciated :)
Since VS Code already supports infinite-width lookbehind construct you may use
"replacerules.rules": {
"Wrap the attrs with square brackets first": {
"find": "(attrs=){([^:{]+:*[^}]*)}",
"replace": "$1[[$2]]"
},
"Format attributes inside attrs": {
"find": "(?<=attrs=\\[\\[[^\\]]*(?:](?!])[^\\]]*)*),(\\s*)",
"replace": "],$1["
},
"Replace colons with commas inside attrs": {
"find": "(?<=attrs=\\[\\[[^\\]]*(?:](?!])[^\\]]*)*):",
"replace": ","
}
}
"replacerules.rulesets": {
"Revamp attrs": {
"rules": [
"Wrap the attrs with square brackets first",
"Format attributes inside attrs",
"Replace colons with commas inside attrs"
]
}
}
Step #1 regex demo
Step #2 regex demo
Step #3 regex demo
Output:
this.mk(attrs=[[keyCollection.key, 40]]))
this.mk(attrs=[[keyCollection.key, 50], [override.key, override.value]])
this.mk(attrs=[[keyCollection.key, 60],
[override.key, override.value]])
Maybe,
(?<=attrs={|,)([^:}]*):([^:},]*)(?=}|,)
might be somehow closer.
If you might have had other attrs, you might want to initially filter out those others.
If you wish to explore/simplify/modify the expression, it's been
explained on the top right panel of
regex101.com. If you'd like, you
can also watch in this
link, how it would match
against some sample inputs.

Find number and replace + 1

I have a large file with a list of objects that have an incrementing page # ie
[
{page: 1},
{page: 2},
{page: 3}
]
I can find each instance of page: # with page: (\d) in vscode's ctrl+f finder. How would I replace each of these numbers with # + 1?
It can be done rather easily in vscode using one of emmet's built-in commands:
Emmet: Increment by 1
Use your regex to find all the page: \d+ in your file.
Ctrl-Shift-L to select all those occurrences.
Trigger the Emmet: Increment by 1 command.
Here is a demo:
It's not possible to perform arithmetic with regex. I use LINQPad to execute these small kind of scripts. An example of how I would do it is in the c# program below.
void Main()
{
var basePath = #"C:\";
// Get all files with extension .cs in the directory and all its subdirectories.
foreach (var filePath in Directory.GetFiles(basePath, "*.cs", SearchOption.AllDirectories))
{
// Read the content of the file.
var fileContent = File.ReadAllText(filePath);
// Replace the content by using a named capture group.
// The named capture group allows one to work with only a part of the regex match.
var replacedContent = Regex.Replace(fileContent, #"page: (?<number>[0-9]+)", match => $"page: {int.Parse(match.Groups["number"].Value) + 1}");
// Write the replaced content back to the file.
File.WriteAllText(filePath, replacedContent);
}
}
I also took the liberty of changing your regex to the one below.
page: (?<number>[0-9]+)
page: matches with "page: " literally.
(?<number> is the start of a named capture group called number. We can then use this group during replacement.
[0-9]+ matches a number between 0 and 9 one to infinite times. This is more specific than using \d as \d also matches other number characters.
The + makes it match more than on digit allowing for the number 10 and onwards.
) is the end of a named capture group.
You could do that in Ruby as follows.
FileIn = "in"
FileOut = "out"
File let's construct a sample file (containing 37 characters).
File.write FileIn, "[\n{page: 1},\n{page: 2},\n{page: 33}\n]\n"
#=> 37
We may now read the input file FileIn, convert it and write it to a new file FileOut.
File.write(FileOut, File.read(FileIn).
gsub(/\{page: (\d+)\}/) { "{page: #{$1.next}}" })
Let's look at what's be written.
puts File.read(FileOut)
[
{page: 2},
{page: 3},
{page: 34}
]
I've gulped the entire file, made the changes in memory and spit out the modified file. If the original file were large this could be easily modified to read from and write to the files line-by-line.
Adding another answer as it is significantly different than the other. I wrote an extension Find and Transform which makes it easy to do math in a find in a file.
In this case with this keybinding (in your keybindings.json file):
{
"key": "alt+r", // whatever keybinding you want
"command": "findInCurrentFile",
"args": {
"find": "page: (\\d)",
"replace": "page: $${ return $1 + 1 }$$",
"isRegex": true
}
[That could also be a setting in your settings.json file if you wish with slightly different syntax of course.]
The $${ return $1 + 1 }$$ represents a javascript operation. Here 1 will be added to capture group 1 from the find regex.
Within the $${ ... }$$ almost any javascript operation can be inserted. There are many examples in the repo.

Regex to capture between two words, and then within that result

I have the following text:
"BOONS": ["Debarrier+Rainbow Shift"
},
"CLUTCH_BOONS": [
"Boost+Wall"
],
Regex:
(?<=[A-Z a-z])(\+)(?=[A-Z a-z])/g
Using That I am capable of capturing all of the +'s which is great, but I only want to capture the + signs inside of "CLUTCH_BOONS", I have tried really hard with little success.
I also want to close the "BOONS" bracket, I managed to get the left side going properly but cannot get the right quote
(?<=.*)(\")(?=.*\})
end result should look like this
"BOONS": ["Debarrier","Rainbow Shift"]
},
"CLUTCH_BOONS": [
"Boost","Wall"
],
(I was trying to use Atom / regexr to fix problematic json)
For the plus signs, you can use this regex:
"\w+": \[\s*"\w+\K\+
see here:
https://regex101.com/r/fJSl37/1
and for the second one:
"(\s*)},
see here:
https://regex101.com/r/Oy0CiJ/1

Sublime Workflow for replacing quotes

I use text editor Sublime Text 3 to edit code, and very often I'll have a string literal wrapped in double quotes, that I want to change to single quotes, or vise versa. Right now I scroll to each quotation mark, and replace it with the one I want. Is there a faster workflow for this? Say, highlighting the word or a hotkey or something? I would find it super useful.
If you have a large number of such strings in a file and you want to convert all of them at once, you could use a regex find/replace operation to find and replace them all. You would use Find > Replace... or Find > Find in files... to search for a matching regex that captures the text in the quotes.
For example you could use \"([^"\n]*)\" as a search term and '\1' as the replacement text to swap all double quoted strings for single quotes.
You can't bind something like that to a key directly because Find/Replace can't be used in a Macro, but you could use the RegReplace package to do this if you want to go that route.
You can potentially speed up the workflow that you're currently using by taking advantage of multiple cursors, if you're not already doing that.
You could for example select the first quote, then press Ctrl+D or Option+D to select the other one. Now that you have two cursors, press Backspace to delete both quotes and press the new quote character to insert the new ones.
This can't be macro-ized and bound to a key because the find_under_expand command can't be used in a macro, though.
For a full key press solution, as far as I'm aware you would need a plugin of some sort to do this for you. One such example appears to be ChangeQuotes, although I've never personally used it.
It's also possible to write your own small plugin such as the following:
import sublime
import sublime_plugin
class SwapQuotesCommand(sublime_plugin.TextCommand):
pairs = ["'", '"']
def run(self, edit):
self.view.run_command("expand_selection", {"to": "scope"})
for sel in self.view.sel():
self.toggle(edit, sel)
def toggle(self, edit, region):
begin = self.view.substr(region.begin())
end = self.view.substr(region.end() - 1)
if begin == end and begin in self.pairs:
index = self.pairs.index(begin) + 1
new = self.pairs[index % len(self.pairs)]
for point in (region.begin(), region.end() - 1):
self.view.replace(edit, sublime.Region(point, point+1), new)
This expands the selection in all of the cursors out by the current scope, and then if both ends of the selection are a matching quote, the quote in use is swapped.
In use, you would use a key binding such as the following, which includes a context to make the key only trigger while the cursor is inside of a string so that it doesn't mess up your selection in cases where it definitely won't work.
{
"keys": ["ctrl+shift+'"], "command": "swap_quotes",
"context": [
{ "key": "selector", "operator": "equal", "operand": "string.quoted", "match_all": true }
]
},

JMeter: How to use Regular Expression to extract the value of a duplicate field?

I have the following Response Body JSON:
{
"address": [
{
"id": "1234"
}
],
"id": "d1a4f010-48d9-434b-9b3a-2d2b12f5e38c"
}
I am trying to extract the value of the the second "id" field, i.e.
"id": "d1a4f010-48d9-434b-9b3a-2d2b12f5e38c"
I use this Regular Expression in JMeter:
Regular Expression: "id":"(.+?)"
When I run my test, it returns "1234" instead of the guid. How can I change my Regular Expression so that it returns the guid?
Using JMeter, you can use Regular Expression Extractor ...
Reference Name: myid
Regular Expression: "id": "(.+?)"
Template: $1$
Match No.: 2
If you specify using a Match No:...
0 = Random Match
1 = First Match
2 = Second Match
etc....
Or use corresponding variable to access the match. ${myid_2}
The variables are set as follows:
myid_matchNr - Number of matches found, possibly 0
myid_n - (n = 1, 2, etc..) Generated by the template
myid_n_gm - (m = 0, 1, 2) Groups for the match (n)
myid - By itself it is always set to the default value
myid_gn - Not set at all
Or judging by this case, if you prefer just regex and your strings are exactly as stated. You could do..
],\s+"id": "(.+?)"
You can use a lazy regex to find the guid directly instead of finding "id"
Something like this: ([0-9a-z-]{36}).*?
If you are not sure how to create the regex, just use an online regex maker.
I don't know jmeter but to get the value of second id this expression
"id"\s*:.+?"id"\s*:\s*"([^"]*)"
It will return what you want on the $1 variable in a some languages. I suppose in jmeter you can have something similar to this in order to get the first group.
Maybe ${MYREF_g1} according this page ?
The given response values
{
"address": [
{
"id": "1234"
}
],
"id": "d1a4f010-48d9-434b-9b3a-2d2b12f5e38c"
}
Regular Expression to extract the second id values
Regular Expression formats
],\s\s\s\s\s"id": "(.+)"
Note
The above regex extract the following id values
d1a4f010-48d9-434b-9b3a-2d2b12f5e38c
I tried with this:
"id":\s*"([0-9a-f\-]*)"
try with below expression
"id": "([0-9a-z-])*+"
step 1:
id:"1234";
id:(.+?)
"1234"
But we need only the value. So try this,
Step 2:
id:"1234";
id:('(.+?)')
1234