0

I'm trying this in javascript

/\/.*?$/.exec('foo/bar/tar')[0]

I was expecting to get /tar as result but getting /bar/tar. As far as I understand non-greed regex would take the smallest match.

I'm circumventing this with myvar.split('/').reverse()[0] but I couldn't understand what is going wrong with the regex.

geckos
  • 5,687
  • 1
  • 41
  • 53
  • Your pattern `\/.*?$` matches from the first forward slash until the end of the string, which is `/bar/tar` If you want your match, you could match a forward slash and not anymore slashes `\/[^\/]+$` [demo](https://regex101.com/r/9mr7Dc/1) – The fourth bird Apr 20 '19 at 15:11
  • So is `\/.*?$` just equal to `\/.*$` I know that non-greedy regex works, but I just missed the concept. I thought that it was match the smaller possible match, which would be `/tar` not `/bar/tar` so what is the point of non greedy regexps?! – geckos Apr 20 '19 at 15:46
  • 1
    You missed the point that regular expressions are matched against each position of input string from left to right. The difference between `/.*?$` and `/.*$` is that the lazy version matches one byte at a time then checks if next position is end of input string, if not expands the match by byte and then checks for end of input string again... But with greedy version, everything that `.` matches are consumed immediately starting from the first `/` then checks if the next immediate position is the end of input string. So they are not totally equal. Remove `$` from both REs to see their behavior. – revo Apr 20 '19 at 15:53
  • revo can you post as an answer? I just got it – geckos Apr 20 '19 at 15:54
  • 1
    `.*?` doesn't match the shortest but it matches the first possible occurrence. This is the better definition. – revo Apr 20 '19 at 15:55
  • The lazy vs greed only differ for right most contents of the regex, it will not work backwards. Thanks! – geckos Apr 20 '19 at 15:55
  • I already marked two questions that point to this confusion. Please see. – revo Apr 20 '19 at 15:58
  • Yeah I did, was reading those that I got it! – geckos Apr 20 '19 at 15:58

1 Answers1

2

There is nothing wrong with the regex but the pattern \/.*?$ matches from the first forward slash until the end of the string non greedy.

The dot matches any character except a newline and does not take a forward slash into account, so that will result in /bar/tar.

If you want to match /tar, you could match a forward slash, followed by not matching anymore forward slashes using a negated character class and then assert the end of the string.

\/[^\/]+$

Pattern demo

console.log(/\/[^\/]+$/.exec('foo/bar/tar')[0]);
The fourth bird
  • 154,723
  • 16
  • 55
  • 70
  • I know that I could use negated characters but this is not the question. `myvar.split('/').reverse()[0]` is possible too and is more readable too, que point is that I thought that I knew non-greedy concept, but it seems that I'm not. – geckos Apr 20 '19 at 15:48
  • 1
    The greedy `.*` matches any char except a newline as much as possible. The non greedy `.*?` matches as least as possible and gives up as least as possible matches to fit the whole pattern. In this case, it is followed by `$` to assert the end of the line so the `.*` and the `.*?` will match the same only the way in how that match is done is different. For example, see this this [greedy match](https://regex101.com/r/9WFGcD/1), and this non [greedy example](https://regex101.com/r/9WFGcD/2) – The fourth bird Apr 20 '19 at 15:53