1

With vim script I can do let found = matchstr("abbaba", 'a') and get back "a" as a result. How would I matchstr to get back a list of all matches for the string? found == ["a", "a", "a"] as in g/a/

3

An alternative to repeatedly calling match( is to use substitute( with a \= expression:

function MatchStrAll(str, pat)
    let l:res = []
    call substitute(a:str, a:pat, '\=add(l:res, submatch(0))', 'g')
    return l:res
endfunction
  • Are there special regex rules for substitute? Because when I match a document with \v(\<)@<=[A-Z][a-zA-Z0-9]{-}(\:|\>|\,)@= I get all matches. If I let lst = [] then %s/\v(\<)@<=[A-Z][a-zA-Z0-9]{-}(\:|\>|\,)@=/\=add(lst, submatch(0))/gn It works also fine. I assume substitute does the same thing? I tried adding an n flag but no results call substitute(a:str, a:pat, '\=add(l:res, submatch(0))', 'gn') – Seph Jun 13 '18 at 21:50
  • what is a:str and a:pat in your case? there are a few differences but I don't think apply to you. also as far as I know there is no 'n' flag to substitute( (only to :substitute, function vs command) – Mass Jun 13 '18 at 22:42
  • str is join(getline(1, '$'), "\n") and pat is \v(\<)@<=[A-Z][a-zA-Z0-9]{-}(\:|\>|\,)@= – Seph Jun 13 '18 at 22:48
  • 1
    It's probably because you're using double quotes in the pattern. switch to single quotes '(\<)@<=[A-Z][a-zA-Z0-9]{-}(\:|\>|\,)@='. see :help expr-quote. – Mass Jun 14 '18 at 0:00
1

You can use the {count} parameter for matchstr() to increment your way through the string and give you all the matches.

Here is an example MatchStrAll() function doing just that:

function! MatchStrAll(expr, pat, ...)
  let start = a:0 ? a:1 : 0
  let lst = []
  let cnt = 1
  let found = match(a:expr, a:pat, start, cnt)
  while found != -1
    call add(lst, matchstr(a:expr, a:pat, start, cnt))
    let cnt += 1
    let found = match(a:expr, a:pat, start, cnt)
  endwhile
  return lst
endfunction

Usage:

echo MatchStrAll("abbaba", 'a')
" yields: ['a', 'a', 'a']

For more help see:

:h match()
:h matchstr()

Something different

I meant trying to do something like this MatchStrAll(join(getline(1, '$'), "\n"), pattern) and getting back a list of all matches

This would be far easier with a substitution and a sub-replace-expression.

:let lst = []
:%s/pattern/\=add(lst, submatch(0))/gn

For more help see:

:h :s
:h sub-replace-expression
:h submatch()
:h List
  • I saw the {count} option in :help but it never explains what it does or how to use it. Can you give me a quick rundown, I'm trying to grok your code right now. I want to also use matchstr to return all instances of a match in a single string with line breaks. – Seph Jun 13 '18 at 20:51
  • Use join() to join the list together. e.g. :echo join(MatchStrAll("abbaba", 'a'), "\n") – Peter Rincker Jun 13 '18 at 20:53
  • I meant trying to do something like this MatchStrAll(join(getline(1, '$'), "\n"), pattern) and getting back a list of all matches. – Seph Jun 13 '18 at 20:56
  • "When {count} is given use the {count}'th match." – Mass Jun 13 '18 at 21:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.