Reputation: 1773
^([a-z-]+-on-sale(?:,[a-z-]+-on-sale){0,})[\/]$
This regex is used in a htaccess file and matches a pattern such as this one:
tools-on-sale,candy-on-sale,food-on-sale/
I've been wondering whether it's possible or not for me to capture a subsection of a repeated capture group. I want to match the same pattern, but I want to omit the "-on-sale" part in the repeated capture group. I know I can already do this for the first part of the regex:
^(([a-z-]+)-on-sale(?:,[a-z-]+-on-sale){0,})[\/]$
That way I have "tools" isolated in its own capture group, but I can't seem to do with the same with the second part. Is this even doable with a regex?
Upvotes: 2
Views: 296
Reputation: 6521
There is not a short way to achieve this. However, you could define a maximimum number of items you should expect, and create one optional group for each.
For 1 to 3 items:
^([a-z-]+)-on-sale(?:(,[a-z-]+)-on-sale(?:(,[a-z-]+)-on-sale)?)?/$
Request url
http://foo.bar/tools-on-sale,candy-on-sale,food-on-sale/
htaccess
RewriteRule ^([a-z-]+)-on-sale(?:(,[a-z-]+)-on-sale(?:(,[a-z-]+)-on-sale)?)?/$ http://foo.bar/$1$2$3 [L]
*Thanks to @sln for suggesting an improvement
Output url
http://foo.bar/tools,candy,food
However, if you need a delimiter other than commas, this will generate empty tokens if you have less than 3 items. E.g:
http://foo.bar/tools--
If you must avoid it, you need to create 1 rule for each number of items:
RewriteRule ^([a-z-]+)-on-sale,([a-z-]+)-on-sale,([a-z-]+)-on-sale/$ http://foo.bar/$1-$2-$3 [L]
RewriteRule ^([a-z-]+)-on-sale,([a-z-]+)-on-sale/$ http://foo.bar/$1-$2 [L]
RewriteRule ^([a-z-]+)-on-sale/$ http://foo.bar/$1 [L]
Upvotes: 1
Reputation:
If I think I understand you, you want to get a list of whats on-sale ?
You've already figured out how to capture the first one tools.
But, You need this in a single match.
The good news is that only Dot-Net can do this in a capture collection,
like this:
# ^((?:(?:^|(?<!^),)(?<sale_item>[a-z-]+)-on-sale)+)[\/]$
^
( # (1 start)
(?:
(?:
^
| (?<! ^ )
,
)
(?<sale_item> [a-z-]+ ) # (2)
-on-sale
)+
) # (1 end)
[\/] $
where sale_item is a list.
The bad news is that on all other regular expression engines,
the overall match will be the same, but the sale_item capture buffer
is overwritten each iteration of the quantified group.
So, sale_item will contain only the last item "food".
Upvotes: 1