Vimプログラミング言語で文字列を逆方向に一致させるには?

Vimプログラミング言語で文字列を逆方向に一致させるには?

[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

関連情報