Como reverter uma string na linguagem de programação Vim?

2

Eu quero encontrar o último índice de qualquer caractere no [abc] definido na string abcabc , mas a pesquisa deve começar no final da string:

" Returns the 0th index but I want the 5th.
let a=match('abcabc', '[abc]')

Eu folheei o "4. Builtin Functions" do Vim ( :h functions ), mas o único método que parecia promissor, o método reverse , só funciona em listas. Uma limitação que não entendo porque funções como len foram projetadas para funcionar mesmo com strings, números e listas.

Para resolver o problema, desenvolvi minha seguinte função:

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

Então, posso dizer let a=match(s:Rvrs('abcabc'), '[abc]') .

    
por Tim Friske 15.12.2012 / 01:08

3 respostas

1

Eu olhei em volta, mas não encontrei nenhuma função incorporada que parecesse que faria o que você queria.

Você pode encontrar as seguintes funções úteis: (variações incluídas para coincidências sobrepostas e não sobrepostas a partir do início ou do fim da string; todas elas suportam padrões de múltiplos caracteres com algumas restrições ou limitações em torno dos usos de \zs e / ou \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
    
por 16.12.2012 / 07:22
2

Se eu ler a pergunta,

echo match('abcabc', '.*\zs[abc]')

é uma resposta: ele retornará o início da última ocorrência do padrão no texto.

Se você quiser as outras ocorrências anteriores à anterior, você terá que cortar a string para trabalhar em 'abcabc'[0:start_of_match+len(matched_string)-1] se quiser aceitar sobreposições (o que não faz sentido no seu caso enquanto você procura [abc] e não abc ) ou 'abcabc'[0:start_of_match-1] de outra forma.

EDIT: Desculpe eu perdi que era o que o código de Chris Johnsen estava fazendo.

    
por 17.12.2012 / 16:20
1

Adicione a seguinte função ao seu arquivo .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

e executá-lo como:

:echo Rvrs( 'abcabcabbc', 'abc' )

Isso produz:

6
    
por 15.12.2012 / 02:20