Friday, April 6, 2012

Re: match and matchend with a negative lookbehind

On Thursday, April 5, 2012 10:13:55 PM UTC-5, John Little wrote:
> On Friday, April 6, 2012 10:02:48 AM UTC+12, Ben Fritz wrote:
> > Please give the EXACT command you ran...
>
> Perhaps this script will illustrate:
>
> let s = '-2 3-4-5-6-7-8'
> let p = '\([0-9-]\@<!-\)\?\d[0-9]*'
> let [start, end] = [0, 0]
> while 1
> let start = match(s, p, end)
> let end = matchend(s, p, end)
> if start == -1
> break
> endif
> echo s[start : end-1]
> endwhile
>
> I get:
>
> -2
> 3
> -4
> -5
> -6
> -7
> -8
>
> It would appear that using the third parameter to match() and matchend(), the match is done as if on a substring starting at the parameter, so the look behind assertion does not see what's there in the original string.
>
> This is unlike searching in a buffer; the look behind assertion does look behind the start position of the search. Rameo, is this what you're getting at?
>

I think you've analyzed it perfectly! Looking closer at the help for match(), I see:

For a String, if {start} > 0 then it is like the string starts
{start} bytes later, thus "^" will match at {start}. Except
when {count} is given, then it's like matches before the
{start} byte are ignored

So with only 3 arguments, from this help text, I would expect exactly the results given, for the reason given.

However, this gave me a hint to fix the problem. With a minor tweak:

let s = '-2 3-4-5-6-7-8'
let p = '\([0-9-]\@<!-\)\?\d[0-9]*'
let [start, end] = [0, 0]
while 1
" count=1 to ignore previous matches rather than making the string
" start at a new place
let start = match(s, p, end, 1)
let end = matchend(s, p, end, 1)
if start == -1
break
endif
echo s[start : end-1]
endwhile

It works as intended. With this script, I get:

-2
3
4
5
6
7
8

--
You received this message from the "vim_use" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

No comments: