Trying to match what is before /../ but after / with regular expressions
I'm trying to match what came before /../
but after /
against regexes, but I want it to look back and stop at the first/
I feel like I'm close, but it just looks at the first slash and then takes everything after it, like ... input:
this/is/a/./path/that/../includes/face/./stuff/../hat
and my regex:
#\/(.*)\.\.\/#
comparison /is/a/./path/that/../includes/face/./stuff/../
instead of that/../
andstuff/../
How do I change my regex to make it work?
a source to share
.*
means "matches any number of characters at all [1]". This is not what you want. You want to match any number of / characters that are written [^/]*
.
Anytime you try to use .*
or .+
in regex, be very suspicious. Stop and ask yourself if you really mean "any character at all [1]" or not - most of the time you don't. (And yes, non-greedy quantifiers can help, but character classes are more efficient for the regex engine to match and is clearer in their message of your intent to readers.)
[1] OK, OK ... .
not quite "any character at all" - it doesn't match newline ( \n
) by default in most regex flavors, but close enough.
a source to share
Alternatively, you can use lookahead .
#(\w+)(?=/\.\./)#
Explanation
NODE EXPLANATION
--------------------------------------------------------------------------------
( group and capture to \1:
--------------------------------------------------------------------------------
\w+ word characters (a-z, A-Z, 0-9, _) (1 or
more times (matching the most amount
possible))
--------------------------------------------------------------------------------
) end of \1
--------------------------------------------------------------------------------
(?= look ahead to see if there is:
--------------------------------------------------------------------------------
/ '/'
--------------------------------------------------------------------------------
\. '.'
--------------------------------------------------------------------------------
\. '.'
--------------------------------------------------------------------------------
/ '/'
--------------------------------------------------------------------------------
) end of look-ahead
a source to share
In python:
>>> test = 'this/is/a/./path/that/../includes/face/./stuff/../hat'
>>> regex = re.compile(r'/\w+?/\.\./')
>>> regex.findall(me)
['/that/..', '/stuff/..']
Or, if you just want the text without the forward slash:
>>> regex = re.compile(r'/(\w+?)/\.\./')
>>> regex.findall(me)
['that', 'stuff']
([^/]+)
will write all text between slashes.
([^/]+)*/\.\.
corresponds to that\..
and stuff\..
in line this/is/a/./path/that/../includes/face/./stuff/../hat
. It captures that
or stuff
, and you can change that, obviously, by changing the placement of captured parsers and your program logic.
You haven't specified if you want to capture or just a match. The regex here only captures this last match (stuff), but is easily replaced by return that
and then stuff
if global is used in global match.
NODE EXPLANATION
--------------------------------------------------------------------------------
( group and capture to \1 (0 or more times
(matching the most amount possible)):
--------------------------------------------------------------------------------
[^/]+ any character except: '/' (1 or more
times (matching the most amount
possible))
--------------------------------------------------------------------------------
)* end of \1 (NOTE: because you're using a
quantifier on this capture, only the LAST
repetition of the captured pattern will be
stored in \1)
--------------------------------------------------------------------------------
/ '/'
--------------------------------------------------------------------------------
\. '.'
--------------------------------------------------------------------------------
\. '.'
a source to share