Creating a specific Sublime Text's snippet, using Regular Expressions - regex

Context
I have a process that envolves creating similar file/filename structures that have inside of it the name of itself, and things like that, i do this every day, and i see that is repetitive and have a pattern, then i got the idea of creating a Sublime Text's Snippet to generate the code for me, adding a significant improvement on my performance.
Example
There is a example of a complete "model" using the structure that i said:
Ext.define('App.model.geral.layouts.Layouts', {
extend: 'App.ux.model.base',
fields: [
{ name: 'Foo', type: 'string', fieldLabel: 'Foo' },
{ name: 'Bar', type: 'int', fieldLabel: 'Bar' },
{ name: 'FooTwo', type: 'boolean', fieldLabel: 'FooTwo' },
{ name: 'Date', type: 'date', fieldLabel: 'Date' },
],
proxy: Use.util.Model.getProxy({
controller: 'Layouts'
})
});
This is a simple and small sample of a file using mine structure. So that file, following the patterns will be placed at C:/Dev/Com/app/model/geral/layouts/Layouts.js, because models, are inside the folder model and geral is the module that the entity layouts belong to.
What i've tried
I tried various things and the most far i did go was that snippet file:
<snippet>
<content><![CDATA[
Ext.define('App.model.${TM_FILEPATH/.+(?:model\/)(.+)\.\w+/\l$1/}', {
extend: '',
fields: [ ],
proxy: ''
});
]]></content>
<tabTrigger>mitem</tabTrigger>
</snippet>
When i trigger that snippet on a empty file named and located in: C:/Dev/Com/app/model/geral/layouts/Layouts.js (as the pattern), it results:
Ext.define('App.model.geral/layouts/Layouts', {
extend: '',
fields: [ ],
proxy: ''
});
As you can see, i got 'App.model.geral/layouts/Layouts' instead of 'App.model.geral.layouts.Layouts' that is what i want. I am close to the final result that i want, as you can see on the complete model example, by the way i cannot go far than that, i dont have any knowledge of RegExp what i did was only researching and trying different things.
If helpful, there is a more complete info about Sublime Snippets that i found is:
$PARAM1 .. $PARAMn Arguments passed to the insert_snippet command. (Not covered here.)
$SELECTION The text that was selected when the snippet was triggered.
$TM_CURRENT_LINE Content of the cursor’s line when the snippet was triggered.
$TM_CURRENT_WORD Word under the cursor when the snippet was triggered.
$TM_FILENAME Name of the file being edited, including extension.
$TM_FILEPATH Path to the file being edited.
$TM_FULLNAME User’s user name.
$TM_LINE_INDEX Column where the snippet is being inserted, 0 based.
$TM_LINE_NUMBER Row where the snippet is being inserted, 1 based.
$TM_SELECTED_TEXT An alias for $SELECTION.
$TM_SOFT_TABS YES if translate_tabs_to_spaces is true, otherwise NO.
$TM_TAB_SIZE Spaces per-tab (controlled by the tab_size option).
I used that info to get the filepath, i tried using another variables like filename but did not get that far.
That will be very useful if someone can help me to get to the final result.

You can achieve what you want with the following:
<snippet>
<content><![CDATA[
Ext.define('App.model.${TM_FILEPATH/(^.+\/model\/)|(\w+)|(\.\w+$)|(\/)/(?2$2)(?4.)/g}', {
extend: '',
fields: [ ],
proxy: ''
});
]]></content>
<tabTrigger>mitem</tabTrigger>
</snippet>
Btw, I highly recommend installing the PackageDev package if you haven't already, to get some syntax highlighting on the snippet and regular expression/replacement.
How it works:
Match:
(^.+\/model\/) match from the beginning of the file path up to and including /model/, and store in capture group 1
| or
(\w+) match any sequence of word characters and store in capture group 2
| or
(\.\w+$) match the file extension and store in capture group 3
| or
(\/) match a / and store in capture group 4
Replacement:
(?2$2) if capture group 2 participated in the match, replace it with itself - i.e. keep it
(?4.) if capture group 4 participated in the match, replace it with a dot
Flags:
g global modifier to match as many times as possible
Arguably you don't need the capture groups 1 and 3, but I included them to make it easier to tell what is being matched.

Related

vscode snippet - multiple regex transformation filepath+filename

after 1 week of searching and try&error I'm creating this question in the hope of someone willing to help me out on this one:
My VsCode Snippet should transform the following:
D:\FolderX\FolderY\src\Folder1\Folder2\Folder3
into:
FOLDER1_FOLDER2_FOLDER3_FILENAMEBASE
Folder3 could be optional
what if come up so far is:
"body": [
"${TM_DIRECTORY/^.+(src\\\\)(.*)$/${2:/upcase}${3:/upcase}/g}_${TM_FILENAME_BASE/(.*)/${1:/upcase}/}",
],
and the result so far is:
FOLDER1\FODLER2\FOLDER3_FILENAMEBASE
so all I need to do now is change the \ to _ but I want that in one transformation if it's possible..
Anyone have an idea or better solution for my problem?
Thanks alot
You can use
"body": [
"${TM_DIRECTORY/^(?:.*\\\\)?src\\\\|([^\\\\]+)|(\\\\)/${1:/upcase}${2:+_}/g}_${TM_FILENAME_BASE/.+/${0:/upcase}/}",
],
Details:
^ - start of string
(?:.*\\\\)? - an optional sequence of any zero or more chars other than line break chars as many as possible and then
src\\\\ - src\ string
| - or
([^\\\\]+) - Group 2: one or more chars other than \
| - or
(\\\\) - Group 3: a \ char.
The ${1:/upcase}${2:+_} replacement means that Group 1 is always returned uppercased, and if Group 2 matches (a \ char), it is replaced with a _ char.
The ${TM_FILENAME_BASE/.+/${0:/upcase}/} is simplified as there is a $0 backreference to the whole match, no need to wrap the whole pattern with a capturing group.
This answer is not directly related to question, however, it is because of the answer from #Wiktor Stribiżew, that I managed to make my snippet work, after a couple of hours on this.
I am modifying the standard rfce snippet from dsznajder - ES7+ React/Redux/React-Native snippets.
I work with the following structure in my react dev:
src
|--components
|----NavBar
|------index.css
|------index.jsx
So, when creating the functional components, I need to create them with the actual name of the folder, and not the file name. Therefore, below is the full snippet, and I created this in the custom javascriptReact snippets:
{
"reactFunctionalExportComponent": {
"prefix": "rfce_",
"body": [
"import './index.css';",
"",
"function ${1:${TM_DIRECTORY/^(?:.*\\\\)/$1/g}}() {",
" return(",
" <div>",
" <h1>${1:${TM_DIRECTORY/^(?:.*\\\\)/$1/g}}</h1>",
" </div>",
" );",
"}",
"",
"export default ${1:${TM_DIRECTORY/^(?:.*\\\\)/$1/g}};",
""
],
"description": "Creates a React Functional Component with ES7 module system"
}
}
The result looks like this:
import "./index.css";
function NavBar() {
return (
<div>
<h1>NavBar</h1>
</div>
);
}
export default NavBar;
I have made similar changes for class components and also arrow functions.

Nifi - Extracting Key Value pairs into new fields

With Nifi I am trying to use the ReplaceText processor to extract key value pairs.
The relevant part of the JSON file is the 'RuleName':
"winlog": {
"channel": "Microsoft-Windows-Sysmon/Operational",
"event_id": 3,
"api": "wineventlog",
"process": {
"pid": 1640,
"thread": {
"id": 4452
}
},
"version": 5,
"record_id": 521564887,
"computer_name": "SERVER001",
"event_data": {
"RuleName": "Technique=Commonly Used Port,Tactic=Command and Control,MitreRef=1043"
},
"provider_guid": "{5790385F-C22A-43E0-BF4C-06F5698FFBD9}",
"opcode": "Info",
"provider_name": "Microsoft-Windows-Sysmon",
"task": "Network connection detected (rule: NetworkConnect)",
"user": {
"identifier": "S-1-5-18",
"name": "SYSTEM",
"domain": "NT AUTHORITY",
"type": "Well Known Group"
}
},
Within the ReplaceText processor I have this configuration
ReplaceText
"winlog.event_data.RuleName":"MitreRef=(.*),Technique=(.*),Tactic=(.*),Alert=(.*)"
"MitreRef":"$1","Technique":"$2","Tactic":"$3","Alert":"$4"
The first problem is that the new fields MitreRef etc. are not created.
The second thing is that the fields may appear in any order in the original JSON, e.g.
"RuleName": "Technique=Commonly Used Port,Tactic=Command and Control,MitreRef=1043"
or,
MitreRef=1043,Tactic=Command and Control,Technique=Commonly Used Port
Any ideas on how to proceed?
Welcome to StackOverflow!
As your question is quite ambiqious I'll try to guess what you aimed for.
Replacing string value of "RuleName" with JSON representation
I assume that you want to replace the entry
"RuleName": "Technique=Commonly Used Port,Tactic=Command and Control,MitreRef=1043"
with something along the lines of
"RuleName": {
"Technique": "Commonly Used Port",
"Tactic": "Command and Control",
"MitreRef": "1043"
}
In this case you can grab basically the whole line and assume you have three groups of characters, each consisting of
A number of characters that are not the equals sign: ([^=]+)
The equals sign =
A number of characters that are not the comma sign: ([^,]+)
These groups in turn are separated by a comma: ,
Based on these assumptions you can write the following RegEx inside the Search Value property of the ReplaceText processor:
"RuleName"\s*:\s*"([^=]+)=([^,]+),([^=]+)=([^,]+),([^=]+)=([^,]+)"
With this, you grab the whole line and build a group for every important data point.
Based on the groups you may set the Replacement Value to:
"RuleName": {
"${'$1'}": "${'$2'}",
"${'$3'}": "${'$4'}",
"${'$5'}": "${'$6'}"
}
Resulting in the above mentioned JSON object.
Some remarks
The RegEx assumes that the entry is on a single line and does NOT work when it is splitted onto multiple lines, e.g.
"RuleName":
"Technique=Commonly Used Port,Tactic=Command and Control,MitreRef=1043"
The RegEx assumes the are exactly three "items" inside the value of RuleName and does NOT work with different number of "items".
In case your JSON file can grow larger you may try to avoid using the Entire text evaluation mode, as this loads the content into a buffer and routes the FlowFile to the failure output in case the file is to large. In that case I recommend you to use the Line-by-Line mode as seen in the attached image.
Allowing a fourth additional value
In case there might be a fourth additional value, you may adjust the RegEx in the Search Value property.
You can add (,([^=]+)=([^,]+))? to the previous expression, which roughly translated to:
( )? - match what is in the bracket zero or one times
, - match the character comma
([^=]+)=([^,]+) - followed by the group of characters as explaind above
The whole RegEx will look like this:
"RuleName"\s*:\s*"([^=]+)=([^,]+),([^=]+)=([^,]+),([^=]+)=([^,]+)(,([^=]+)=([^,]+))?"
To allow the new value to be used you have to adjust the replacement value as well.
You can use the Expression Language available in most NiFi processor properties to decide whether to add another item to the JSON object or not.
${'$7':isEmpty():ifElse(
'',
${literal(', "'):append(${'$8'}):append('": '):append('"'):append(${'$9'}):append('"')}
)}
This expression will look if the seventh RegEx group exists or not and either append an empty string or the found values.
With this modification included the whole replacement value will look like the following:
"RuleName": {
"${'$1'}": "${'$2'}",
"${'$3'}": "${'$4'}",
"${'$5'}": "${'$6'}"
${'$7':isEmpty():ifElse(
'',
${literal(', "'):append(${'$8'}):append('": '):append('"'):append(${'$9'}):append('"')}
)}
}
regarding multiple occurrences
The ReplaceText processor replaces all occurrences it finds where the RegEx matches. Using the settings provided in the last paragraph given the following example input
{
"event_data": {
"RuleName": "Technique=Commonly Used Port,Tactic=Command and Control,MitreRef=1043,Foo=Bar"
},
"RuleName": "Technique=Commonly Used Port,Tactic=Command and Control,MitreRef=1043"
}
will result in the following:
{
"event_data": {
"RuleName": {
"Technique": "Commonly Used Port",
"Tactic": "Command and Control",
"MitreRef": "1043",
"Foo": "Bar"
}
},
"RuleName": {
"Technique": "Commonly Used Port",
"Tactic": "Command and Control",
"MitreRef": "1043"
}
}
example template
You may download a template I created that includes the above processor from gist.

regex breaks when I use a colon(:)

I just started working with elastic search. By started working I mean I have to query an already running elastic database. Is there a good documentation of the regex they follow. I know about the one on their official site, but its not very helpful.
The more specific problem is that I want to query for lines of the sort:
10:02:37:623421|0098-TSOT {TRANSITION} {ID} {1619245525} {securityID} {} {fromStatus} {NOT_PRESENT} {toStatus} {WAITING}
or
01:01:36:832516|0058-CT {ADD} {0} {3137TTDR7} {23} {COM} {New} {0} {0} {52} {1}
and more of a similar structure. I don't want a generalized regex. If possible, could someone give me a regex expression for each of these that would run with elastic?
I noticed that it matches if the regexp matches with a substring too when I ran with:
query = {"query":
{"regexp":
{
"message": "[0-9]{2}"
}
},
"sort":
[
{"#timestamp":"asc"}
]
}
But it wont match anything if I use:
query = {"query":
{"regexp":
{
"message": "[0-9]{2}:.*"
}
},
"sort":
[
{"#timestamp":"asc"}
]
}
I want to write regex that are more specific and that are different for the two examples given near the top.
turns out my message is present in the tokenized form instead of the raw form, and : is one of the default delimiters of the tokenizer, in elastic. And as a reason, I can't use regexp query on the whole message because it matches it with each token individually.

How do I use 'include' to apply rules to a capture when writing a Sublime Text syntax definition?

I'm trying to write a syntax definition for Gradle in Sublime Text 3. Many pieces of a Gradle build file are really just Groovy and so I'm trying to take advantage of the current Groovy highlighting support by using include. Thus far this is working fairly well, by I'm stuck on how to apply it to a particular piece.
Here is the Gradle snippet I am trying to highlight:
task copyTask (group: 'Install NGA - deploy', type: Copy, dependsOn: 'whoCares') {
from 'resources'
into 'target'
include('**/*.txt')
}
And this is the syntax I'm using to match that snippet:
- name: copy.task.source.gradle
begin: '\s*(task)\s+(\w+)\s*\((.*type: Copy.*)\)\s*{'
comment: 'Copy task definition'
beginCaptures:
'1': {name: keyword.task.source.gradle}
'2': {name: entity.name.function}
'3': {name: source.groovy}
end: '}'
contentName: copy.body.source.gradle
patterns:
- include: source.groovy
Most of this appears to work as intended. (Always hard to know with RegEx.) My problem is that the third capture. I want to apply all the rules contained in 'source.groovy' to the text between the parentheses and what I have above is not getting the job done.
To clarify: the text is "captured" and tagged as source.groovy, but that's not actually quite what I want. I don't want it simply tagged as source.groovy, I want the rules from source.groovy to be used when evaluating the text. The last line of my example successfully does this to the "content" section (text in between the braces) but simply putting include does not work.
'3': {include: source.groovy} # This gets an error.
If there is a syntax to apply include directly to a capture I can't find it, and I can't figure out another technique. Maybe something that has nested begin and end tags?
If I am understanding this correctly you would like the third capture group source.groovy to match the group: 'Install NGA - deploy', type: Copy, dependsOn: 'whoCares' part of your example.
In that case you would just need to alter you expression to capture more of the string like so:
begin: '\s*(task)\s+(\w+)\s*\((.*type: Copy.*?)\)\s*{'

How to Populate koGrid Groups Array

I have a koGrid configured as follows:
var myItemsGrid = {
data: myItems,
columnDefs: [
{ field: 'item.title', displayName: 'Title', cellTemplate: $("#cdfUrlCellTemplate").html() },
{ field: 'item.dueTimeUtc', displayName: 'Due', cellFormatter: formatDate, sortFn: sortDates },
{ field: 'id', displayName: 'Edit', cellTemplate: $("#editCellTemplate").html() }
],
showGroupPanel: true,
groups: ['item.title'],
showFilter: false,
canSelectRows: false
};
My problem is that the groups array, which I have tried to populate using the field name of one of the fields in my grid, causes the following error:
TypeError: Cannot read property 'isAggCol' of undefined
How should I be populating the groups array so that I can set up initial grouping for my grid?
I had the same problem and took a different approach by sending an event to the grid control to group by the first heading. Something like this:
jQuery("#symbolPickerView").find(".kgGroupIcon").first().click();
This works until there is some sort of patch generally available.
I ended up having to patch the koGrid script to get the initial grouping of columns to work.
If anyone else has the problem I'm happy to provide the patched script. I will look at making a pull request to get the fix into the koGrid repository after putting it through its paces a bit more.