[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]
それ以外の場合。
編集:申し訳ありません。 Chris Johansenのコードが行っていることを見逃しました。
答え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