[abc]
string 의 집합에 있는 문자의 마지막 인덱스를 찾고 싶지만 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