I'm trying to write a Visual Studio Code snippet that converts Pascal case to lowercase with spaces. I'm almost there:
${1/([A-Z]*)([A-Z][a-z]+)/$1 ${2:/downcase} /g}
Group 1 matches acronyms and group 2 matches capitalized words.
So if the placeholder were MyUIDTest
, the expected result would be my UID test
. But currently I get my UID test
(notice the spaces on either side).
How do I only add a space after group 1 if group 1 has a match? And how do I remove the space at the end of the line?
According to the docs, ${1:+ }
means "insert a space iff group 1 is captured":
${
TM_SELECTED_TEXT
/
(?<=([A-Za-z])?) # Lookbehind for and capture ($1) a preceding letter, if any,
(?: # then match a "word" – either
([A-Z]+)(?![a-z]) # ($2) 1+ uppercase not followed by a lowercase
| # or
([A-Z][a-z]+) # ($3) an uppercase followed by 1+ lowercase.
) #
/ # Replace each match with
${1:+\u0020} # a space, iff group 1 is captured,
${2:/upcase} # the uppercase version of group 2
${3:/downcase} # and the lowercase version of group 3.
/g # for all matches found.
}
Since $2
and $3
are mutually exclusive, using them both always results in only one being actually inserted.
Before | After |
---|---|
PascalCase |
pascal case |
MyUIDTest |
my UID test |
FoOBaR |
fo O ba R |
A more precise (and verbose) version would be (note that \b
needs to be escaped again when written in a JSON string: "\\b"
):
${
TM_SELECTED_TEXT
/
(?<= # Lookbehind for
\b # a word boundary followed by
([A-Z]+(?![a-z])|[A-Z][a-z]+)* # 0+ "words"
# and capture the last word, if any.
)
(?:([A-Z]+)(?![a-z])|([A-Z][a-z]+))
/
${1:+\u0020}${2:/upcase}${3:/downcase}
/g
}
I'm using TM_SELECTED_TEXT
here, but you might want to change that depending on your needs.