I have this:
${1/([A-Z]*)(?:_)([A-Z]+)*/${1:/downcase}${2:/downcase}/g}
How to make use downcase and capitalize on the same (2) group?
${1/([A-Z]*)(?:_)([A-Z]+)*/${1:/downcase}${2:/downcase/capitalize}/g}
I want to tansform ZXC_ASD to zxcAsd.
Try it like this:
"camelCaseSnail": {
"scope": "javascript,typescript",
"prefix": "log",
"body": "${1/([A-Z]*)(?:_)(?:([A-Z])([A-Z]+))*/${1:/downcase}${2:/capitalize}${3:/downcase}/g}"
}
Basically, I've changed the second capture group ([A-Z]+)* to a non-capture group that has two inner capture groups (?:([A-Z])([A-Z]+))*, a single letter for camel-case and the rest, which I refer in the replace/transform part: /downcase}${2:/capitalize}${3:/downcase}/
Apparently coming to vscode v1.58 is a /camelcase modifier. So your case is as easy as
"${1/(.*)/${1:/camelcase}/}"
Tested in the Insiders Build. See Add a camelCase transform for Snippet variables. See also https://stackoverflow.com/a/51228186/836330 for another example.
Old answer:
Using the undocumented (see Snippet regex: match arbitrary number of groups and transform to CamelCase) /pascalcase transform, it is quite easy:
"${1/([A-Z]*)(?:_)([A-Z]+)*/${1:/downcase}${2:/pascalcase}/g}"
as the /pascalcase will do both the /capitalize and the /downcase at once.
Related
I'm coding in Elixir/Phoenix Framework using VS Code and trying to transform the following relative path
lib/shop_web/live/product_live/index.ex
into
ShopWeb.Live.ProductLive.Index
using snippets.
The closest to that was the regex below
"${RELATIVE_FILEPATH/^(lib\\/|test\\/)(\\w)|(.ex|.exs)$|\\/(\\w)|_(\\w)/${2:/upcase}${4:/upcase}${5:/upcase}/g}"
who gives me the following output
ShopWebLiveProductLiveIndex
I could not find a way to insert the missing dots.
Can anyone help me?
Thanks in advance!
Try this:
"test7": {
"prefix": "al",
"body": [
// my version
"${RELATIVE_FILEPATH/^([^\\/\\\\]+[\\/\\\\])|(\\.ex|\\.exs)$|([^._\\/\\\\]+)|_|([\\/\\\\])/${3:/capitalize}${4:+.}/g}",
// your version tweaked
"${RELATIVE_FILEPATH/^(lib[\\/\\\\]|test[\\/\\\\])(\\w)|(\\.ex|\\.exs)$|([\\/\\\\])(\\w)|_(\\w)/${2:/upcase}${4:+.}${5:/upcase}${6:/upcase}/g}",
],
"description": "alert line"
}
[Note: I made these work for both path.separators / and \. If you don't need that you could shorten the snippet by a lot.]
Your version was very close. I changed it to \\.ex just to make the dots explicit.
I also added a 4th capturing group ([\\/\\\\]) just before the 5th as in ([\\/\\\\])(\\w).
Now that 4th group can be used in a conditional ${4:+.} to add the .'s where the path separators were.
My version is a little shorter - it matches but doesn't use whatever directory is first, be it lib or test or whatever. If that doesn't work for you it is easy to modify that bit of the regexp. I shortened it to 4 capture groups.
([^._\\/\\\\]+)|_|([\\/\\\\]) the end of my version:
([^._\\/\\\\]+) : match characters other than ._\/, or
_ : match it but we aren't using it so no need for a capture group, or
([\\/\\\\]) : match just the path separator in group 4 to use in the conditional.
${4:+.} : conditional, if there is a group 4 (a path separator) add a ..
Thanks to #Mark, my snippet to create a module in Elixir or Phoenix Framework looks like this now:
"Module": {
"prefix": "defmodule",
"description": "Create a module by the Elixir naming convention",
"body": [
"defmodule ${RELATIVE_FILEPATH/^([^\\/\\\\]+[\\/\\\\])|(\\.ex|\\.exs)$|([^._\\/\\\\]+)|_|([\\/\\\\])/${3:/capitalize}${4:+.}/g} do",
"\t$1",
"end"
],
}
As the naming convention, the output for the file in my question lib/shop_web/live/product_live/index.ex will be:
defmodule ShopWeb.Live.ProductLive.Index do
end
I'm currently working on a big svg sprite.
The diffrent images are always 2000px apart.
What I have is:
<g transform="translate(0,0)">
<g transform="translate(0,2000)">
<g transform="translate(0,4000)">
After regex want this so just adding 2000 onto the second number:
<g transform="translate(0,2000)">
<g transform="translate(0,4000)">
<g transform="translate(0,6000)">
I have the issue now that some new images have to be put at the top of the document, thus meaning i would need to change all numbers and they are quite alot.
I was thinking about using regular expressions and even found out that it works in the search bar of VS Code. The thing is i never worked with any regex and i'm kinda confused.
Could someone give me a solution and an explanation for incrementing all the sample numbers by 2000?
I hope i understand it afterwards so i can get my foot into that topic.
I'm also happy with just links to tutorials in general or my specific use case.
Thank you very much :)
In VSCode, you can't replace with an incremented value inside a match/capture. You can only do that inside a callback function passed as the replacement argument to a regex replace function/method.
You may use Notepad++ to perform these replacements after installing Python Script plugin. Follow these instructions and then use the following Python code:
def increment_after_openparen(match):
return "{0}{1}".format(match.group(1),str(int(match.group(2))+2000))
editor.rereplace(r'(transform="translate\(\d+,\s*)(\d+)', increment_after_openparen)
See the regex demo.
Note:
(transform="translate\(\d+,\s*)(\d+) matches and captures into Group 1 transform="translate( + 1 or more digits, then , and 0 or more whitespaces (with (transform="translate\(\d+,\s*))) and then captures into Group 2 any one or more digits (with (\d+))
match.group(1) is the Group 1 contents, match.group(2) is the Group 2 contents.
Basically, any group is formed with a pair of unescaped parentheses and the group count starts with 1. So, if you use a pattern like (Item:\s*)(\d+)([.;]), you will need to use return "{0}{1}{2}".format(match.group(1),str(int(match.group(2))+2000), match.group(3)). Or, return "{}{}{}".format(match.group(1),str(int(match.group(2))+2000), match.group(3)).
you can use the extension Regex Text Generator
Select the numbers with Multi Cursor, can be done with Regex Find and Alt+Enter in find box
Run command: Generate text based on regular expression
As Match Expression use: (\d+)
As generator extression use: {{=N[1]+2000}}
You get a preview of the result.
Press Enter if OK, or Esc to abort
You can set this type of search replace as a predefined in the setting regexTextGen.predefined
"regexTextGen.predefined": {
"Add/Subtract a number" : {
"originalTextRegex": "(\d+)",
"generatorRegex": "{{=N[1]+1}}"
}
}
You can edit the expressions (change the 1) if you choose a predefined.
SublimeText3 with the Text-Pastry add-in can also do \i
I wrote an extension, Find and Transform, to make these math operations on find and replaces with regex's quite simple (and much more like path variables, conditionals, string operations, etc.). In this case, this keybinding (in your keybindings.json) will do what you want:
{
"key": "alt+r", // whatever keybinding you want
"command": "findInCurrentFile",
"args": {
"find": "(?<=translate\\(\\d+,\\s*)(\\d+)", // double-escaped
"replace": "$${ return $1 + 2000 }$$",
"isRegex": true,
// "restrictFind": "document", // or line/once/selections/etc.
}
}
That could also be a setting in your settings.json if you wanted that - see the README.
(?<=translate\\(\\d+,\\s*) a positive lookbehind, you can use non-fixed length items in the lookbehind, like \\d+.
(\\d+) capture group 1
The replace: $${ return $1 + 2000 }$$
$${ <your string or math operation here> }}$
return $1 + 2000 add 2000 to capture group 1
Demo:
I'm trying to create a custom syntax language file to highlight and help with creating new documents in Sublime Text 2. I have come pretty far, but I'm stuck at a specific problem regarding Regex searches in the tmLanguage file. I simply want to be able to match a regex over multiple lines within a YAML document that I then convert to PList to use in Sublime Text as a package. It won't work.
This is my regex:
/(foo[^.#]*bar)/
And this is how it looks inside the tmLanguage YAML document:
patterns:
- include: '#test'
repository:
test:
comment: Tester pattern
name: constant.numeric.xdoc
match: (foo[^.#]*bar)
If I build this YAML to a tmLanguage file and use it as a package in Sublime Text, I create a document that uses this custom syntax, try it out and the following happens:
This WILL match:
foo 12345 bar
This WILL NOT match:
foo
12345
bar
In a Regex tester, they should and will both match, but in my tmLanguage file it does not work.
I also already tried to add modifiers to my regex in the tmLanguage file, but the following either don't work or break the document entirely:
match: (/foo[^.#]*bar/gm)
match: /(/foo[^.#]*bar/)/gm
match: /foo[^.#]*bar/gm
match: foo[^.#]*bar
Note: My Regex rule works in the tester, this problem occurs in the tmLanguage file in Sublime Text 2 only.
Any help is greatly appreciated.
EDIT: The reason I use a match instead of begin/end clauses is because I want to use capture groups to give them different names. If someone has a solution with begin and end clauses where you can still name 'foo', '12345' and 'bar' differently, that's fine by me too.
I found that this is impossible to do. This is directly from the TextMate Manual, which is the text editor Sublime Text is based on.
12.2 Language Rules
<...>
Note that the regular expressions are matched against only a single
line of the document at a time. That means it is not possible to use a
pattern that matches multiple lines. The reason for this is technical:
being able to restart the parser at an arbitrary line and having to
re-parse only the minimal number of lines affected by an edit. In most
situations it is possible to use the begin/end model to overcome this
limitation.
My situation is one of the few in which a begin/end model cannot overcome the limitation. Unfortunate.
Long time since asked, but are you sure you can't use begin/end? I had similar problems with begin/end until I got a better grasp of the syntax/logic. Here's a rough example from a json tmLanguage file I'm doing (don't know the proper YAML syntax).
"repository": {
"foobar": {
"begin": "foo(?=[^.#]*)", // not sure about what's needed for your circumstance. the lookahead probably only covers the foo line
"end": "bar",
"beginCaptures": {
"0": {
"name": "foo"
}
},
"endCaptures": {
"0": {
"name": "bar"
}
},
"patterns": [
{"include": "#test-after-foobarmet"}
]
},
"test-after-foobarmet": {
"comment": "this can apply to many lines before next bar so you may need more testing",
"comment2": "you could continue to have captures here that go to another deeper level...",
"name": "constant.numeric.xdoc",
"match": "anyOtherRegexNeeded?"
}
}
I didn't follow your
"i need to number the different sections between the '#' and '.'
characters."
, but you should be able to have a test in test-after-foobarmet with more captures if needed for naming different groups between foo bar.
There's are good explanation of TextMate Grammar here. May still suffer from some errors but explains it in a way that was helpful for me when I didn't know anything about the topic.
I have a file that looks like this...
"1234567123456","V","0","0","BLAH","BLAH","BLAH","BLAH"
"1234567123456","D","TEST1 "
"1234567123456","D","TEST 2~TEST3"
"1234567123456","R","TEST4~TEST5"
"1234567123457","V","0","0","BLAH","BLAH","BLAH","BLAH"
"1234567123457","D","TEST 6"
"1234567123457","D","TEST7"
"1234567123457","R","TEST 8~TEST9~TEST,10"
All I'm trying to do is parse the D and R lines. The ~ is used in this case as a separator. So the end results would be...
"1234567123456","V","0","0","BLAH","BLAH","BLAH","BLAH"
"1234567123456","D","TEST1 "
"1234567123456","D","TEST3"
"1234567123456","D","TEST3"
"1234567123456","R","TEST4"
"1234567123456","R","TEST5"
"1234567123457","V","0","0","BLAH","BLAH","BLAH","BLAH"
"1234567123457","D","TEST 6"
"1234567123457","D","TEST7"
"1234567123457","R","TEST 8"
"1234567123457","R","TEST9"
"1234567123457","R","TEST,10"
I'm using regex on applications like Textpad and Notepad++. I have not figured out how to use a regex like /.+/g because the applications do not like the forward slashes. So I don't think I can use things like the global modifier. I currently have the following regex...
//In a program like Textpad/Notepad++
<FIND> "(.{13})","D","([^~]*)~(.*)
<REPLACE> "\1","D","\2"\n"\1","D","\3
Now if I run a find and replace with the above params a few times it would work fine (for the D lines only). The problem is there is an unknown number of lines to be made. For example...
"1234567123456","D","TEST1~TEST2~TEST3~TEST4~TEST5"
"1234567123457","D","TEST1~TEST2~TEST3"
"1234567123458","D","TEST1~TEST2"
"1234567123459","D","TEST1~TEST2~TEST3~TEST4"
I was hoping to be able to use a MULTI capture group to make this work. I found this PAGE talking about the common mistake between repeating a capturing group and capturing a repeated group. I need to capture a repeated group. For some reason I just could not make mine work right though. Anyone else have an idea?
Note: If I could get rid of the leading and trailing spaces EX: "1234567123456","D","TEST1 " ending up as "1234567123456","D","TEST1" that would be even better but not necessary.
RESOURCES:
http://www.regular-expressions.info/captureall.html
http://regex101.com/
I'm working on regular expressions for some syntax highlighting in a Sublime/TextMate language file, and it requires that I "begin" on a non-self closing html tag, and end on the respective closing tag:
begin: (<)([a-zA-Z0-9:.]+)[^/>]*(>)
end: (</)(\2)([^>]*>)
So far, so good, I'm able to capture the tag name, and it matches to be able to apply the appropriate patterns for the area between the tags.
jsx-tag-area:
begin: (<)([a-zA-Z0-9:.]+)[^/>]*>
beginCaptures:
'1': {name: punctuation.definition.tag.begin.jsx}
'2': {name: entity.name.tag.jsx}
end: (</)(\2)([^>]*>)
endCaptures:
'1': {name: punctuation.definition.tag.begin.jsx}
'2': {name: entity.name.tag.jsx}
'3': {name: punctuation.definition.tag.end.jsx}
name: jsx.tag-area.jsx
patterns:
- {include: '#jsx'}
- {include: '#jsx-evaluated-code'}
Now I'm also looking to also be able to capture zero or more of the html attributes in the opening tag to be able to highlight them.
So if the tag were <div attr="Something" data-attr="test" data-foo>
It would be able to match on attr, data-attr, and data-foo, as well as the < and div
Something like (this is very rough):
(<)([a-zA-Z0-9:.]+)(?:\s(?:([0-9a-zA-Z_-]*=?))\s?)*)[^/>]*(>)
It doesn't need to be perfect, it's just for some syntax highlighting, but I was having a hard time figuring out how to achieve multiple capture groups within the tag, whether I should be using look-around, etc, or whether this is even possible with a single expression.
Edit: here are more details about the specific case / question - https://github.com/reactjs/sublime-react/issues/18
I may found a possible solution.
It is not perfect because as #skamazin said in the comments if you are trying to capture an arbitrary amount of attributes you will have to repeat the pattern that matches the attributes as many times as you want to limit the number of attributes you will allow.
The regex is pretty scary but it may work for your goal. Maybe it would be possible to simplify it a bit or maybe you will have to adjust some things
For only one attribute it will be as this:
(<)([a-zA-Z0-9:.]+)(?:(?: ((?<= )[^ ]+?(?==| |>)))(?:=[^ >]+)(?: |>))
DEMO
For more attributes you will need to add this as many times as you want:
(?:(?:((?<= )[^ ]+?(?==| |>)))(?:=[^ >]+)(?: |>))?
So for example if you want to allow maximum 3 attributes your regex will be like this:
(<)([a-zA-Z0-9:.]+)(?:(?: ((?<= )[^ ]+?(?==| |>)))(?:=[^ >]+)(?: |>))(?:(?:((?<= )[^ ]+?(?==| |>)))(?:=[^ >]+)?(?: |>))?(?:(?:((?<= )[^ ]+?(?==| |>)))(?:=[^ >]+)?(?: |>))?
DEMO
Tell me if it suits you and if you need further details.
I'm unfamiliar with sublimetext or react-jsx but this to me sounds like a case of "Regex is your tool, not your solution."
A solution that uses regex as a tool for this would be something like this JsFiddle (note that the regex is slightly obfuscated because of html-entities like > for > etc.)
Code that does the actual replacing:
blabla.replace(/(<!--(?:[^-]|-(?!->))*-->)|(<(?:(?!>).)+>)|(\{[^\}]+\})/g, function(m, c, t, a) {
if (c!=undefined)
return '<span class="comment">' + c + '</span>';
if (t!=undefined)
return '<span class="tag">' + t.replace(/ [a-z_-]+=?/ig, '<span class="attr">$&</span>') + '</span>';
if (a!=undefined)
return a.replace(/'[^']+'/g, '<span class="quoted">$&</span>');
});
So here I'm first capturing the separate type of groups following this general pattern adapted for this use-case of HTML with accolade-blocks. Those captures are fed to a function that determines what type of capture we're dealing with and further replaces subgroups within this capture with its own .replace() statements.
There's really no other reliable way to do this. I can't tell you how this translates to your environment but maybe this is of help.
Regex alone doesn't seem to be good enough, but since you're working with sublime's scripting here, there's a way to simplify both the code and the process. Keep in mind, I'm a vim user and not familiar with sublime's internals - also, I usually work with javascript regexes, not PCREs (which seems to be the format used by sublime, or closest thereof).
The idea is as follows:
use a regex to get the tag, attributes (in a string) and contents of the tag
use capture groups to do further processing and matching if necessary
In this case, I made this regex:
<([a-z]+)\ ?([a-z]+=\".*?\"\ ?)?>([.\n\sa-z]*)(<\/\1>)?
It starts by finding an opening tag, creates a control group for the tag name, if it finds a space it proceeds, matches the bulk of attributes (inside the \"...\" pattern I could have used \"[^\"]*?\" to match only non-quote characters, but I purposefully match any character greedily until the closing quote - this is to match the bulk of attributes, which we can process later), matches any text in between tags and then finally matches the closing tag.
It creates 4 capture groups:
tag name
attribute string
tag contents
closing tag
as you can see in this demo, if there is no closing tag, we get no capture group for it, same for attributes, but we always get a capture group for the contents of the tag. This can be a problem generally (since we can't assume that a captured feature will be in the same group) but it isn't here because, in the conflict case where we get no attributes and no content, thus the 2nd capture group is empty, we can just assume it means no attributes and the lack of a 3rd group speaks for itself. If there's nothing to parse, nothing can be parsed wrongly.
Now to parse the attributes, we can simply do it with:
([a-z]+=\"[^\"]*?\")
demo here. This gives us the attributes exactly. If sublime's scripting lets you get this far, it certainly would allow you further processing if necessary. You can of course always use something like this:
(([a-z]+)=\"([^\"]*?)\")
which will provide capture groups for the attribute as a whole and its name and value separately.
Using this approach, you should be able to parse the tags well enough for highlighting in 2-3 passes and send off the contents for highlighting to whatever highlighter you want (or just highlight it as plaintext in whatever fancy way you want).
Your own regex was quite helpful in answering your question.
This seems to work well for me:
/(:?<|<\/)([a-zA-Z0-9:.]+)(?:\s(?:([0-9a-zA-Z_-]*=?))\s?)*[^/>]*(:?>|\/>)/g
The / at the beginning and end are just the wrappers regex usually requires. In addition, the g at the end stands for global, so it works for repetitions as well.
A good tool I use to figure out what I am doing wrong with my regex is: http://regexr.com/
Hope this helps!