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?

+2


a source to share


7 replies


.*

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.

+2


a source


Modify your pattern to match only characters other than /

( [^/]

):



#([^/]*)/\.\./#

      

+1


a source


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

      

+1


a source


I think you are essentially right, you just need to make the match non-greedy, or change (.*)

to not allow slashes:#/([^/]*)/\.\./#

0


a source


In your favorite language, do some sections and string manipulations like Python

>>> s="this/is/a/./path/that/../includes/face/./stuff/../hat"
>>> a=s.split("/../")[:-1]  # the last item is not required.
>>> for item in a:
...   print item.split("/")[-1]
...
that
stuff

      

0


a source


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']

      

0


a source


([^/]+)

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)
--------------------------------------------------------------------------------
  /                        '/'
--------------------------------------------------------------------------------
  \.                       '.'
--------------------------------------------------------------------------------
  \.                       '.'

      

0


a source







All Articles