How to convert snippet placeholder from CamelCase to snake_case - regex

I would like to create a VS Code snippet where I input a part in CamelCase, and the same string is output in snake_case at some other place in the snippet.
Based on this SO post Here's my attempted snippet, but I have a trailing _ that needs to be removed by hand, not ideal:
"test": {
"prefix": "test",
"body": "${1} -> ${1/([A-Z])+([a-z]+)/${1:/downcase}${2}_/g}"
},

"camelToSnakeCase": {
"prefix": "test",
"body": [
"${1} -> ${1/([A-Z][a-z]+$)|([A-Z][a-z]+)/${1:/downcase}${2:/downcase}${2:+_}/g}"
],
"description": "transform from CamelCase to snake_case"
}
In order to differentiate between some last capture group like Abcd and the preceding capture groups, I used an alternation:
([A-Z][a-z]+$)|([A-Z][a-z]+) must be in this order
so group 1 will be at the end of the input because of the $ indicator and group 2 will not be at the end. And group 2s will always have at least one more group after them. Then, using the conditional ${2:+_} only insert an underscore if there is a group 2 - because there must be a following group 1.
This keybinding version also works if you have a different workflow:
{
"key": "alt+3", // whatever keybinding you wish
"command": "extension.multiCommand.execute",
"args": {
"sequence": [
"cursorWordLeftSelect",
"editor.action.transformToSnakecase",
"editor.action.transformToLowercase",
// "cursorLineEnd" // if you want this
]
},
"when": "editorTextFocus && !editorHasSelection"
}
Type your word and trigger the keybinding. Uses the macro extension multi-command.

Related

How to match a string exactly OR exact substring from beginning using Regular Expression

I'm trying to build a regex query for a database and it's got me stumped. If I have a string with a varying number of elements that has an ordered structure how can I find if it matches another string exactly OR some exact sub string when read from the left?
For example I have these strings
Canada.Ontario.Toronto.Downtown
Canada.Ontario
Canada.EasternCanada.Ontario.Toronto.Downtown
England.London
France.SouthFrance.Nice
They are structured by most general location to specific, left to right. However, the number of elements varies with some specifying a country.region.state and so on, and some just country.town. I need to match not only the words but the order.
So if I want to match "Canada.Ontario.Toronto.Downtown" I would want to both get #1 and #2 and nothing else. How would I do that? Basically running through the string and as soon as a different character comes up it's not a match but still allow a sub string that ends "early" to match like #2.
I've tried making groups and using "?" like (canada)?.?(Ontario)?.? etc but it doesn't seem to work in all situations since it can match nothing as well.
Edit as requested:
Mongodb Database Collection:
[
{
"_id": "doc1",
"context": "Canada.Ontario.Toronto.Downtown",
"useful_data": "Some Data"
},
{
"_id": "doc2",
"context": "Canada.Ontario",
"useful_data": "Some Data"
},
{
"_id": "doc3",
"context": "Canada.EasternCanada.Ontario.Toronto.Downtown",
"useful_data": "Some Data"
},
{
"_id": "doc4",
"context": "England.London",
"useful_data": "Some Data"
},
{
"_id": "doc5",
"context": "France.SouthFrance.Nice",
"useful_data": "Some Data"
},
{
"_id": "doc6",
"context": "",
"useful_data": "Some Data"
}
]
User provides "Canada", "Ontario", "Toronto", and "Downtown" values in that order and I need to use that to query doc1 and doc2 and no others. So I need a regex pattern to put in here: collection.find({"context": {$regex: <pattern here>}) If it's not possible I'll just have to restructure the data and use different methods of finding those docs.
At each dot, start an nested optional group for the next term, and add start and end anchors:
^Canada(\.Ontario(\.Toronto(\.Downtown)?)?)?$
See live demo.

I want to apply the regular expression used in gitleaks in secretlint

I am now trying to migrate from gitleaks to a tool called secretlint.
Originally, there was a warning in the generic-api-key rule when executing gitleaks, but after moving to secretlint, the warning no longer occurs.
Specifically, I wrote the regular expression of gitleaks.toml provided by gitleaks in the secretlint configuration file .secretlintrc.json according to the format of #secretlint-rule-pattern provided by secretlint.
[[rules]]
id = "generic-api-key"
description = "Generic API Key"
regex = '''(?i)((key|api[^Version]|token|secret|password|auth)[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([0-9a-zA-Z\-_=]{8,64})['\"]'''
entropy = 3.7
secretGroup = 4
keywords = [
"key",
"api",
"token",
"secret",
"password",
"auth",
]
to
{
"rules": [
{
"id": "#secretlint/secretlint-rule-pattern",
"options": {
"patterns": [
{
"name": "Generic API key",
"pattern": "/(?i)((key|api[^Version]|token|secret|password|auth)[a-z0-9_ .\\-,]{0,25})(=|>|:=|\\|\\|:|<=|=>|:).{0,5}['\"]([0-9a-zA-Z\\-_=]{8,64})['\"]/"
}
]
}
}
]
}
I'm thinking that perhaps I'm not migrating the regex correctly, but if anyone can tell me where I'm going wrong, I'd like to know.
The main issue is the the inline (?i) modifier is not supported by the JavaScript regex engine. You must use the normal i flag after the second regex delimiter (/.../i).
Also, the api[^Version] is a typical user error. If you meant to say api not followed with Version, you need api(?!Version).
So you can use
"pattern": "/((key|api(?!Version)|token|secret|password|auth)[\\w .,-]{0,25})([=>:]|:=|\\|\\|:|<=|=>).{0,5}['\"]([\\w=-]{8,64})['\"]/i"
Note that I "shrunk" [A-Za-z0-9_] into a single \w, they are equivalent here. Note the - char does not need escaping when used at the end (or start) of a character class.

How do I convert this Sublime snippet into a VS Code snippet?

See below my attempt and result. The Sublime snippet first:
<snippet>
<content>
<![CDATA[<${1:p}>${2:$SELECTION}</${1/([^ ]+).*/$1/}>]]>
</content>
<tabTrigger><</tabTrigger>
<scope>text.xml</scope>
<description>Long Tag</description>
</snippet>
and the keybinding:
{ "keys": ["super+shift+o"], "command": "insert_snippet", "args": { "name": "Packages/XML/long-tag.sublime-snippet" } },
What this does is the following:
Pressing Cmd + Shift + O will create an html tag <p></p> in with the p linked so you can start typing and it updates both sides. Pressing tab will place your cursor in the center of the tags.
Highlighting a section, then pressing cmd + shift + O will surround that section with the tags.
What I've managed to get trying on my own is the following in VS Code:
{
"blank_tag": {
"prefix": "<cmdso>",
"body": [
// "<$1>$2</$1>$3"
"<${1:p}>${2:$SELECTION}</$1/([^ ]+).*}>"
],
"description": "Adds a blank tag to use"
}
}
This almost gets what I want but not quite. I'm not very good with regex but the result of this prints <p></p/([^ ]+).*}> I can remove that last bit of regex and it will get #1 satisfied. The #2 above is extremely helpful and I'd like to figure out what I'm doing wrong. I'm betting that last bit of regex is what allows you to highlight a section and surround it with the tags.
Can you help me fix this to work and satisfy #1 and #2?
Ok these are two different snippets, the first you already did so i'm going to speak about the second:
You want to surround a text in a tag based on a shortcut, you need two thing first to create the snippet, then to add the shortcut
This snippet when inserted will surround your text with a p tag, that changes immediately while you are writing.
"surround_tag": {
"prefix": "<stag>",
"body": [
"<${1:p}>${TM_SELECTED_TEXT}</$1>"
],
"description": "surround text by tag"
}
Notice that we are using a specific variable called TM_SELECTED_TEXT, you can find more about these variables here, https://code.visualstudio.com/docs/editor/userdefinedsnippets
Then add a keyboard shortcut to insert that snippet
{
"key": "cmd+w cmd+t",
"command": "editor.action.insertSnippet",
"when": "editorTextFocus",
"args": {
"name": "surround_tag",
}
}
// in args here you can add a key langId to specify specific languages like
"args": {
"langId": "javascript",
"name": "surround_tag",
}
You can find language identifiers here https://code.visualstudio.com/docs/languages/identifiers
Of course, you can also insert the snippet without the keyboard shortcut by using the insertSnippet command (CMD + Shift + P and then insertSnippet, then pick your one)
You can also use the following site to generate snippets for both vscode and sublime https://snippet-generator.app/
You may fix your code using
"blank_tag": {
"prefix": "<cmdso>",
"body": [
"<${1:p}>${2:$SELECTION}</${1/(\\S+).*/$1/}>"
],
"description": "Adds a blank tag to use"
}
The [^ ] can be written as \\S+ in the code, \S+ matches 1 or more non-whitespace chars. The syntax is ${ID/pattern/replacement/flags}, so you had an incomplete code.
If you're using Sublime Text, you can use the Atomizr package to convert snippets within the editor.
Example:
Install the package using Package Control
Open a Sublime Text snippet
Run the Atomizr: Sublime Text to Visual Studio Code command (or CtrlS, CtrlV on macOS)
To convert many files, it's probably more convenient to install the CLI equivalent (requires NodeJS)
Example:
# Single conversion
atomizr example.sublime-snippet --target vscode
# Batch conversion
atomizr *.sublime-snippet --target vscode
If you want to use the same keybinding for two different actions as it seems you do, then you will have to find a way to differentiate between the then existing conditions so that the appropriate version is triggered properly.
In your case, that involves utilizing that in one situation you will start with selected text. So we can use the when clause editorHasSelection to distinguish between the twp desired actions.
In your keybindings.json:
{
"key": "cmd+shift+O",
"command": "editor.action.insertSnippet",
"args": {
"snippet": "<${1:p}>$0</$1>"
},
"when": "editorTextFocus && !editorHasSelection"
},
{
"key": "cmd+shift+O",
"command": "editor.action.insertSnippet",
"args": {
"snippet": "<${1:p}>${TM_SELECTED_TEXT}</$1>"
},
"when": "editorTextFocus && editorHasSelection"
}
We see that only the second command will be triggered if there is a selection in the editor!!
!editorHasSelection means if there is no selection, trigger this one. Otherwise, we will trigger the other command.
Note that there is already a command also bound to Cmd+Shift+O: workbench.action.gotoSymbol You should disable that command if you want to stick with Cmd+Shift+O as your triggers. This will disable it:
{
"key": "cmd+shift+O",
"command": "-workbench.action.gotoSymbol"
},
Here is a demo of it working:

Visual Studio Code: How to automate a simple regex-find and replace?

I try to create a simple regex-find and replace task in Visual Studio Code.
Currently I copy from the AD some Users to a temporary file in Visual Studio code and remove the "CN=" at the beginning of the line and all the aditional informations after the first "," (regex: ,.*$). This works fine with Find&Replace in VSCode but I have manually to type it in every time I want to remove this.
So the question is, is it possible to automate this kind of task? I know there are some external tools (https://code.visualstudio.com/docs/editor/tasks) but I'm struggling to get it working...
Edit: Example requested (my regex is working, that's not the problem:/. I need an example how to automate this task... )
EXAMPLE
CN=Test User,OU=Benutzer,OU=TEST1,OU=Vert,OU=ES1,OU=HEADQUARTERS,DC=esg,DC=corp
Expected Output
Test User
This extension does the job:
https://marketplace.visualstudio.com/items?itemName=joekon.ssmacro#overview
It seems like the regex adheres to:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
Example
Create a file regex.json:
[{
"command": "ssmacro.replace",
"args": {
"info": "strip out EOL whitespace",
"find": "\\s+$",
"replace": "",
"all": true,
"reg": true,
"flag": "gm"
}
}]
"info" is just a reminder, doesn't do anything.
Set a shortcut in keybindings.json:
"key": "ctrl+9",
"command": "ssmacro.macro", "args": {"path": "C:\\...\\regex.json"}
You can batch multiple commands together [{...},{...}] which is useful for applying a whole set of regex operations in one go.
As of today, it seems it's still not possible without an extension. Here are 2 other extensions than the one proposed in the accepted answer (both are also open-source):
● Batch Replacer (but it doesn't work on the documents open in the editor : "you must have a folder open for editing and all files in it will be updated."*)
● Replace Rules: you simply add some rules in your settings.json (open the palette with F1 or ctrl+shift+p and select Preferences: open settings (JSON)).
"replacerules.rules": {
"Remove trailing and leading whitespace": {
"find": "^\\s*(.*)\\s*$",
"replace": "$1"
},
"Remove blank lines": {
"find": "^\\n",
"replace": "",
"languages": [
"typescript"
]
}
}
Extensions folder is : %USERPROFILE%\.vscode\extensions
And here is an extension I wrote that allows you to save find/replaces in a file or searches across files as a named command and/or as a keybinding: Find and Transform. Using the OP's original question, make this setting (in settings.json):
"findInCurrentFile": { // in settings.json
"reduceUserEntry": {
"title": "Reduce User to ...", // will appear in the Command Palette
"find": "CN=([^,]+).*",
"replace": "$1",
"isRegex": true,
// "restrictFind": "selections", // default is entire document
}
},
You could also make that for searches across files with this setting:
"runInSearchPanel": {
"reduceUserEntry": {
"title": "Reduce User to ...", // will appear in the Command Palette
"find": "CN=([^,]+).*",
"replace": "$1",
"isRegex": true
// "filesToInclude": "${fileDirname}"
// "onlyOpenEditors": true
// and more options
}
}
As a standalone keybinding:
{
"key": "alt+r", // whatever keybinding you want
"command": "findInCurrentFile", // or runInSearchPanel
"args": {
"find": "CN=([^,]+).*",
"replace": "$1",
"isRegex": true
The extension can also run multiple finds/replaces - just put them into an array:
"find": ["<some find term 1>", "<some find term 2>", etc.
and the same with replacements, make an array of them.

Regex: Match Numbers inside a bracket

Ok here is an example of the text I got
"data": [
{
"post_id": "164902600239452_10202071734744222",
"actor_id": 164902600239452,
"target_id": null,
"likes": {
"href": "https://www.facebook.com/browse/likes/?id=10202071734744222",
"count": 2,
"sample": [
678063648,
100000551340876,
100000805495404,
100000905843684,
],
"friends": [
],
"user_likes": false,
"can_like": true
},
"comments": {
"can_remove": false,
"can_post": true,
"count": 0,
"comment_list": [
]
},
"message": "Down to the FINAL 3 SEATS for It Factor LIVE 2013... WHO will snag them before we close registration on October 15th???\n\nLearn more now at http://www.ItFactorLIVE.com/"
}, ]
I want to match only the numbers inside the brackets after the "sample":
"sample": [
678063648,
100000551340876,
100000805495404,
100000905843684,
],
so that I end up with this
678063648
100000551340876
100000805495404
100000905843684
May somebody please help me with the correct regex to make that happen?
OK - I have looked at the solution that #hwnd had suggested, as well as the link you gave to the "real" data, and came up with the following:
\d+(?=,*\s+(?:\d|\]))
You can see at http://regex101.com/r/pL3gW2 that this matches every string of digits in the sample that is inside square brackets.
The key difference with #hwnd's solution was the addition of a * after the ,, making the comma after the digits optional: this allows the expression to match the last set of numbers before the close ]. Without it, the match skipped the last number inside the brackets.
It's been said before: there are powerful JSON parsers available in almost any language / platform. Look into them.
see if this works for you
pattern = (\d+)(?=(?:(?!\[).)*\]) Demo