SOLVED

Velocity: Regex capturing groups

Go to solution
Markus_Bianchi5
Level 2

Velocity: Regex capturing groups

I was wondering if there's a possibility in velocity to use regex capturing groups? So, as a simple example, we may want to get "Some Name", "13:00" and "14:00" from the following input string: "Some Name: 13:00 - 14:00".

 

There are multiple ways how this can be achieved but one possibility would be to use a simple regex such as "^(.+):\s?(\d{1,2}:\d{1,2})\s?\-\s?(\d{1,2}:\d{1,2})$" and then extract the parts from the three capturing groups.

 

Something like "matches" in Velocity only returns a Boolean which can be used to e.g. compare a input to a pattern.

 

#set( $input = "Some Name: 13:00 - 14:00" )
#set( $regex = "^(.+):\s?(\d{1,2}:\d{1,2})\s?\-\s?(\d{1,2}:\d{1,2})$" )
#if ( $input.matches($regex) )
  ## We have a match
#end

 

 

In JavaScript land you could e.g. do something simple such as

 

const [_, name, timeFrom, timeTo] = "Some Name: 13:00 - 14:00".match(/^(.+):\s?(\d{1,2}:\d{1,2})\s?\-\s?(\d{1,2}:\d{1,2})$/i) || [];

 

Is there something similar in Velocity? Given the example above, we could "split" by multiple delimiters or use multiple "replace" runs to get the parts but that obviously has its limitations and feels somewhat hacky.

Maybe @SanfordWhiteman has an idea? Thanks in advance.

Tags (1)
1 ACCEPTED SOLUTION

Accepted Solutions
SanfordWhiteman
Level 10 - Community Moderator

Re: Velocity: Regex capturing groups

It's not so much capturing groups you're lacking (which are supported) it's an iterable set of match results.

 

In Marketo's Velocity, you can't create a Matcher object (other Velocity installs do support this). 

 

The closest way to simulate would be replaceAll and put a known-unused delimiter - like the ASCII record delimiter in the below example - then split on the delimiter.

#set( $input = "Some Name: 13:00 - 14:00" )
#set( $regex = "^(.+):\s?(\d{1,2}:\d{1,2})\s?\-\s?(\d{1,2}:\d{1,2})$" )
#set( $output = $input.replaceAll( $regex, "$1\u001e$2\u001e$3" ).split("\u001e") )
#foreach( $part in $output )
${part}
#end

 

Figure I'll do a blog post on this one of these days.

View solution in original post

5 REPLIES 5
SanfordWhiteman
Level 10 - Community Moderator

Re: Velocity: Regex capturing groups

It's not so much capturing groups you're lacking (which are supported) it's an iterable set of match results.

 

In Marketo's Velocity, you can't create a Matcher object (other Velocity installs do support this). 

 

The closest way to simulate would be replaceAll and put a known-unused delimiter - like the ASCII record delimiter in the below example - then split on the delimiter.

#set( $input = "Some Name: 13:00 - 14:00" )
#set( $regex = "^(.+):\s?(\d{1,2}:\d{1,2})\s?\-\s?(\d{1,2}:\d{1,2})$" )
#set( $output = $input.replaceAll( $regex, "$1\u001e$2\u001e$3" ).split("\u001e") )
#foreach( $part in $output )
${part}
#end

 

Figure I'll do a blog post on this one of these days.

Markus_Bianchi5
Level 2

Re: Velocity: Regex capturing groups

Great, thanks, that's what I was looking for.

Adam_Mokrzecki1
Level 2

Re: Velocity: Regex capturing groups

 Hi Sanford, 

 

Just found this solution, and it's great! thank you! However, I did have a follow up question. 

 

Is it possible assign the regex groups to unique variables?

 

I tried to set up a script using something similar to this line of code you provided:

#set( $output = $input.replaceAll( $regex, "$1\u001e$2\u001e$3" ).split("\u001e") )

 

Here's what I was trying to do for that portion of the script:

#set( $outputA = $input.replaceAll( $regex, "$1" ) )
#set( $outputB = $input.replaceAll( $regex, "$2" ) )

${outputA}
<br>
${outputB}

 

In my case, I'm trying to extract 2 URLs from a field. I needed them in variables so that I can link specific text within the email. 

 

Using the code you created, I'm able to display the URLs correctly, but just not sure how to modify it for my needs. 

 

Thank you!

 

 

 

SanfordWhiteman
Level 10 - Community Moderator

Re: Velocity: Regex capturing groups

There’s no destructing assignment, if that’s what you mean.

 

You can do runtime dynamic variable creation like this, but (a) I don‘t advise it because it looks clumsy and is hard to follow and (b) you can’t use it with URLs in any case:

#set( $partNames = ["name", "start", "end"] )
#foreach( $part in $partNames )
#evaluate( "${esc.h}set( ${esc.d}$part = ${esc.d}output[$foreach.index] )" )
#end
Markus_Bianchi5
Level 2

Re: Velocity: Regex capturing groups

If you already have the $output (the part that Sanford mentioned), I'd say that you can also do something along these lines:

#set( $output = $input.replaceAll( $regex, "$1\u001e$2\u001e$3" ).split("\u001e") )
#set( $outputA = $output[0] )
#set( $outputB = $output[1] )
#set( $outputC = $output[2] )