我想找到字符串[abc]
中集合 中任何字符的最后一个索引abcabc
,但搜索应该从字符串的末尾开始:
" Returns the 0th index but I want the 5th.
let a=match('abcabc', '[abc]')
我浏览了 Vim 的“4. 内置函数”( :h functions
),但唯一看起来有前途的方法reverse
是仅对列表进行操作的方法。我不明白这个限制,因为类似的函数len
被设计为甚至可以处理字符串、数字和列表。
为了解决这个问题,我想出了以下功能:
function! s:Rvrs(str)
let a=len(a:str)
let b=a - 1
let c=''
while b >= 0
let c.=a:str[b]
let b-=1
endwhile
return c
endfunction
所以我可以说let a=match(s:Rvrs('abcabc'), '[abc]')
。
答案1
如果我读到这个问题,
echo match('abcabc', '.*\zs[abc]')
是一个答案:它将返回文本中最后一次出现的模式的开头。
'abcabc'[0:start_of_match+len(matched_string)-1]
如果您想要最后一个之前的其他出现,如果您想接受重叠,则必须剪切字符串才能处理(这在您的情况下没有意义,因为您正在寻找[abc]
,而不是abc
),或者'abcabc'[0:start_of_match-1]
否则。
编辑:抱歉,我错过了克里斯·约翰森的代码正在做的事情。
答案2
我环顾四周,但没有找到任何看起来像你想要的内置函数。
不过,您可能会发现以下函数很有用:(包括从字符串开头或结尾开始的重叠和非重叠匹配的变体;所有这些都支持多字符模式,但对\zs
和/或的使用有一些限制或限制\ze
)
function! s:AllOverlappableMatches(str, pat)
" Restriction: a:pat should not use \ze
let indicies = []
let index = 0
let splits = split(a:str, '\ze'.a:pat, 1)
for segment in splits
if len(segment) == 0
call add(indicies, index)
else
let index += len(segment)
endif
endfor
return indicies
endfunction
function! s:AllOverlappableMatchesFromEnd(str, pat)
" Restriction: a:pat should not use \ze
return reverse(s:AllOverlappableMatches(a:str, a:pat))
endfunction
function! s:AllNonoverlappingMatches(str, pat)
" If a:pat uses \zs, the returned indicies will be based on that
" position.
" If a:pst uses \ze, subsequent matches may re-use characters
" after \ze that were consumed, but not 'matched' (due to \ze)
" in earlier matches.
let indicies = []
let start = 0
let next = 0
while next != -1
let next = match(a:str, a:pat, start)
if next != -1
call add(indicies, next)
let start = matchend(a:str, a:pat, start)
endif
endwhile
return indicies
endfunction
function! s:AllNonoverlappingMatchesFromEnd(str, pat)
" If a:pat uses \zs, the returned indicies will be based on that
" position.
let str = a:str
let indicies = []
let start = len(a:str) - 1
while start >= 0
let next = match(str, '.*\zs' . a:pat, start)
if next != -1
call add(indicies, next)
let str = str[ : next - 1]
endif
let start -= 1
endwhile
return indicies
endfunction
echo s:AllOverlappableMatchesFromEnd('abcabc', '[abc]')
" -> [5, 4, 3, 2, 1, 0]
echo s:AllOverlappableMatchesFromEnd('dabcabc', '[abc]')
" -> [6, 5, 4, 3, 2, 1]
echo s:AllOverlappableMatchesFromEnd('dab - cabc', '[abc]')
" -> [9, 8, 7, 6, 2, 1]
echo s:AllOverlappableMatchesFromEnd('dab - cabce', '[abc]')
" -> [9, 8, 7, 6, 2, 1]
echo s:AllOverlappableMatchesFromEnd('dab - cabc', '[abc]\{2}')
" -> [8, 7, 6, 1]
echo s:AllOverlappableMatches('dab - cabc', '[abc]\{2}')
" -> [1, 6, 7, 8] 0123456789
echo s:AllNonoverlappingMatches('dab - cabc', '[abc]\{2}')
" -> [1, 6, 8] 0123456789
echo s:AllNonoverlappingMatchesFromEnd('dab - cabca', '[abc]\{2}')
" -> [9, 7, 1] 0123456789A
echo s:AllNonoverlappingMatchesFromEnd('ab - cabca', '[abc]\{2}')
" -> [8, 6, 0] 0123456789
echo s:AllNonoverlappingMatchesFromEnd('abcabc', '[abc]\{2}')
" -> [4, 2, 0] 012345
echo s:AllNonoverlappingMatchesFromEnd(' ab c abcd', '[abc]\{2}')
" -> [7, 1] 0123456789
echo s:AllNonoverlappingMatchesFromEnd('abcabc', '[abc]\{2}')
" -> [4, 2, 0] 012345
echo s:AllNonoverlappingMatches( 'abcabcabbc', 'abc')
" -> [0, 3] 0123456789
echo s:AllNonoverlappingMatchesFromEnd( 'abcdabcabbc', 'abc')
" -> [4, 0] 0123456789A
" A multi-character, overlappable pattern
echo s:AllOverlappableMatchesFromEnd( 'aaaabcaaac', 'aaa')
" -> [6, 1, 0] 0123456789
答案3
将以下函数添加到您的.vimrc
文件中
function! Rvrs( str, chars )
"" 'a:chars' is a string. Convert it to a list.
let l:chars_list = split( a:chars, '\zs' )
"" Process 'str' from the end one character each time.
"" I remove that character from the list if found.
let l:i = len( a:str )
while l:i >= 0 && ! empty( l:chars_list )
let l:i = l:i - 1
if index( l:chars_list, strpart( a:str, l:i, 1 ) ) != -1
let l:dummy = remove( l:chars_list, index( l:chars_list, strpart( a:str, l:i, 1)))
endif
endwhile
"" If the loop go throught all the string means that couldn't find
"" all characters of the list, so return and incorrect code.
"" Otherwise the position where the list got empty.
if i < 0
return -1
else
return l:i
endif
endfunction
并像这样执行:
:echo Rvrs( 'abcabcabbc', 'abc' )
得出:
6