diff --git a/autoload/ingo/regexp/split.vim b/autoload/ingo/regexp/split.vim index c79911e..a740068 100644 --- a/autoload/ingo/regexp/split.vim +++ b/autoload/ingo/regexp/split.vim @@ -1,6 +1,7 @@ " ingo/regexp/split.vim: Functions to split a regular expression. " " DEPENDENCIES: +" - ingo/regexp/length.vim autoload script " " Copyright: (C) 2017-2018 Ingo Karkat " The VIM LICENSE applies to this script; see ':help copyright'. @@ -107,4 +108,38 @@ function! ingo#regexp#split#PrefixGroupsSuffix( pattern ) return l:result endfunction +function! ingo#regexp#split#AddPatternByProjectedMatchLength( branches, pattern ) +"****************************************************************************** +"* PURPOSE: +" Add a:pattern to the List of regexp a:branches, in a position so that +" shorter earlier branches do not eclipse a following longer match. +"* ASSUMPTIONS / PRECONDITIONS: +" None. +"* EFFECTS / POSTCONDITIONS: +" None. +"* INPUTS: +" a:branches List of regular expression branches (e.g. split via +" ingo#regexp#split#TopLevelBranches()). +" a:pattern Regular expression to be added at the appropriate position in +" a:branches, depending on the projected length of the matches. +" Longer matches will come first, so that a shorter earlier match +" does not eclipse a following longer one. +"* RETURN VALUES: +" Modified a:branches List. +"****************************************************************************** + let l:projectedPatternMinLength = ingo#regexp#length#Project(a:pattern)[0] + + let l:i = 0 + while l:i < len(a:branches) + let [l:min, l:max] = ingo#regexp#length#Project(a:branches[l:i]) + let l:compare = (l:max < 0x7FFFFFFF ? l:max : l:min) + if l:compare < l:projectedPatternMinLength + break + endif + + let l:i += 1 + endwhile + return insert(a:branches, a:pattern, l:i) +endfunction + " vim: set ts=8 sts=4 sw=4 noexpandtab ff=unix fdm=syntax : diff --git a/tests/regexp/split/t3000-AddPatternByProjectedMatchLength-literals.vim b/tests/regexp/split/t3000-AddPatternByProjectedMatchLength-literals.vim new file mode 100644 index 0000000..bed49eb --- /dev/null +++ b/tests/regexp/split/t3000-AddPatternByProjectedMatchLength-literals.vim @@ -0,0 +1,17 @@ +" Test addition of literal patterns based on length. + +call vimtest#StartTap() +call vimtap#Plan(8) + +call vimtap#Is(ingo#regexp#split#AddPatternByProjectedMatchLength([], 'foo'), ['foo'], 'add literal pattern to empty list') +call vimtap#Is(ingo#regexp#split#AddPatternByProjectedMatchLength(['foo'], 'fo'), ['foo', 'fo'], 'add shorter literal pattern to one-element list') +call vimtap#Is(ingo#regexp#split#AddPatternByProjectedMatchLength(['foo'], 'fooy'), ['fooy', 'foo'], 'add longer literal pattern to one-element list') +call vimtap#Is(ingo#regexp#split#AddPatternByProjectedMatchLength(['foo'], 'fox'), ['foo', 'fox'], 'add same-length literal pattern to one-element list') + +call vimtap#Is(ingo#regexp#split#AddPatternByProjectedMatchLength(['foo', 'fo'], 'f'), ['foo', 'fo', 'f'], 'add shorter literal pattern to two-element list') +call vimtap#Is(ingo#regexp#split#AddPatternByProjectedMatchLength(['fooxies', 'fo'], 'foox'), ['fooxies', 'foox', 'fo'], 'add literal pattern to middle of two-element list') +call vimtap#Is(ingo#regexp#split#AddPatternByProjectedMatchLength(['fooxies', 'foox', 'fo'], 'foo'), ['fooxies', 'foox', 'foo', 'fo'], 'add literal pattern to middle of three-element list') + +call vimtap#Is(ingo#regexp#split#AddPatternByProjectedMatchLength(['fooxies', 'fo', 'boobies', 'bo'], 'boo'), ['fooxies', 'boo', 'fo', 'boobies', 'bo'], 'add literal pattern to middle of not fully sorted four-element list') + +call vimtest#Quit()