Диапазон поиска чисел (используя реальные цифры в поиске) - PullRequest
1 голос
/ 28 марта 2012

Я хочу найти диапазон номеров (в VIM), но не знаю как:

пример:

  • поиск номеров> 450,20
  • поиск номеров> 1200 (или 1.200)
  • поиск номеров> 10.000 И <1.000.000 </li>
  • поиск номеров <10 </p>

    - все номера должны включатьдесятичные значения pe 9,20 или 8,532 - это значение меньше 10
    - все числа могут быть вставлены (найдены) с разделителем тысяч или без него, в выводе не должно быть различий.

Может ли кто-нибудь помочь мне с примером кода, как я могу продолжить?
Я уже пытался создать что-то вроде этого, считая количество цифр, но это не работает, как я хочу, потому что втаким образом, я не могу искать значения как> 90,50 или <200 на лету. </p>

1 Ответ

1 голос
/ 27 января 2018

Ну легко вы не можете ... Но с усилиями вы можете сделать все что угодно!
Поиск числа> 450.20 - это не место для регулярных выражений, а:

h perl-patterns: Vim не реализует (к сожалению) execution of arbitrary code in the regex: (?{perl code}).
Это означает, что вы должны использовать некоторую подстановку (s) или глобальный поиск (g), чтобы оценить совпадение как число и так легко выделить его с помощью VimL.

Но вы спрашиваете команду /. Итак, давайте сделаем это с помощью регулярных выражений. Идея состоит в том, чтобы соответствовать:

  • x> 1000: \ d \ d \ d \ d (то есть 4 цифры)
  • x> 500: [5-9] \ d \ d
  • x> 460: 4 [6-9] \ d
  • x> 450: 45 [0-9]
  • И еще для двоеточия

Пример регулярного выражения может занять некоторое место. Тем более, что я повторил границы слов для каждого шаблона.

\% (\% ([^ 0-9]. \ ZS \ | ^) [5-9] \ d \ d \% (\ d *) \ \% (\ ге \ D \.? | $) \ | \% ([^ 0-9]. \ ZS \ | ^) 4 [6-9] \ d \% (\ d *) \ \% (\ ге \ D \ |.? $) \ | \% ([^ 0-9]. \ ZS \ | ^) 45 [1-9] \% \ \% (\ ге \ D \ | $) (\ d *.)? \ | \% ([ ^ 0-9] \ ZS \ |..? ^) \ d * \ d {4} \% (\ d *) \ \% (\ ге \ D \ | $) \ | \% ([^ 0- 9] \ ZS \ |. ^) 450. [3-9] \ d * \ | \% ([^ 0-9] \ ZS \ |. ^) 450,2 [1-9] \ d * \ | \% ([^ 0-9]. \ ZS \ | ^) 450,20 \ d * (\ d \ & [^ 0]) \ d *)

Подробнее:

    " Numbers >= 500         (looking like '***')
    \%([^0-9.]\zs\|^\)[5-9]\d\d\%(\.\d*\)\?\%(\ze\D\|$\)

    " Or numbers >= 460      (looking like '4**')
    \|
    \%([^0-9.]\zs\|^\)4[6-9]\d\%(\.\d*\)\?\%(\ze\D\|$\)

    " Or numbers >= 451      (looking like '45*') 
    \|
    \%([^0-9.]\zs\|^\)45[1-9]\%(\.\d*\)\?\%(\ze\D\|$\)

    " Or numbers > 1000     (more than 4 digits)
    \|
    \%([^0-9.]\zs\|^\)\d*\d\{4}\%(\.\d*\)\?\%(\ze\D\|$\)

    " Or numbers >= 450.3    (450.******) 
    \|
    \%([^0-9.]\zs\|^\)450\.[3-9]\d*

    " Or numbers >= 450.21  (450.2*****) 
    \|
    \%([^0-9.]\zs\|^\)450\.2[1-9]\d*\)

    " Or numbers > 450.20   (450.20 + 0.00000002000) 
    \|
    \%([^0-9.]\zs\|^\)450\.20\d*\(\d\&[^0]\)\d*\)

Я сделал это с помощью следующего скрипта:

" Search for all numbers in a range
"
" Source me then (better put the last command defintion in your vimrc, then
"
" :Isearch > 450.20
" :Isearch > 1000 < 1000000

function! search#char_range(char, dir)
  " Get string with range or '' if < 0 or > 9

  if a:dir
    let l:res = string( str2nr(a:char) + 1 )
    if (l:res == 10) | return '' | endif
    let l:res = '[' . l:res . '-9]'
  else
    let l:res = string( str2nr(a:char) - 1)
    if (l:res == -1) | return '' | endif
    let l:res = '[0-' . l:res . ']'
  endif

  return l:res
endfunction


function! search#isearch(num, dir, inc)
  " Search any number supp to 9
  " 
  " Number:     (number)  Limiting the range
  " Direction:  (boolean) Higher if true
  " Inclusive:  (boolean) Do the number is include >= or <= 
  "

  let l:start_of_number = '\%([^0-9.]\zs\|^\)'
  let l:pat_list = [l:start_of_number]

  " Get hight and low
  let l:list = split(a:num, '\.')
  let l:high = l:list[0]
  if (len(l:list) > 1)
    let l:low = l:list[1]
  else
    let l:low = ''
  endif


  " 1/ High loop
  " ~~~~~~~~~~~~
  for l:c in split(l:high, '\zs')
    " Get the higher range [-]
    let l:range = search#char_range(l:c, a:dir)
    if (l:range != '')
      let l:pat = l:pat_list[0] . l:range
      if (a:dir == 0 && l:pat_list[0] == l:start_of_number) 
        let l:pat .= '\?'
      endif
      call add(l:pat_list, l:pat)
    else
      if (a:dir)
        break
      else
        let l:pat_list[-1] .= '\d\?'
      endif
    endif

    " Add \d to previous guys
    for i in range(1, len(l:pat_list) - 2)
      let l:pat_list[i] .= '\d'
    endfor

    " Add to initial pattern
    let l:pat_list[0] .= l:c
  endfor

  " 1.2/ Include with more digit
  if a:dir
    let l:biggest =  l:start_of_number . '\d*\d\{' . string(len(l:pat_list)) . '}'
    call add(l:pat_list, l:biggest)
  endif

  " 1.3/ indlude rest (after .)
  for i in range(1, len(l:pat_list) - 1)
    " The last digit is non optional (otherwise can match all)
    if l:pat_list[i][-4:] == '\d\?'
      let l:pat_list[i] = l:pat_list[i][:-3]
    endif
    let l:pat_list[i] .= '\%(\.\d*\)\?\%(\ze\D\|$\)'
  endfor


  " 2/ Low loop
  " ~~~~~~~~~~~
  if (len(l:low) != '')
    let l:pat_list[0] .= '\.'
  else
    let l:pat_list[0] .= '\.\?'
  endif
  for l:c in split(l:low, '\zs')
    " Get the higher range [-]
    let l:cp1 = string( str2nr(l:c) + 1 )
    if (l:cp1 == 10) | break | endif
    call add(l:pat_list, l:pat_list[0] . '[' . cp1 . '-9]\d*')

    " Add to initial pattern
    let l:pat_list[0] .= l:c
  endfor

  " 2.2/ A very little drop
  let l:pat = l:pat_list[0] . '\d*\(\d\&[^0]\)\d*'
  call add(l:pat_list, l:pat)

  " 3/ Add the number itself
  if a:inc
    let l:pat = join(l:pat_list, '\|')
  else
    let l:pat = join(l:pat_list[1:], '\|')
  endif

  return l:pat
endfunction


function! search#wrapper(...)
  let l:pat = ''
  for l:i in range(len(a:000))
    " TODO check if there is a number after
    if (a:000[l:i] == '>=')
      if (l:pat != '') | let l:pat .= '\&' | endif
      let l:pat .= '\%(' . search#isearch(a:000[l:i+1], 1, 1) . '\)'
    elseif (a:000[l:i] == '>')
      if (l:pat != '') | let l:pat .= '\&' | endif
      let l:pat .= '\%(' . search#isearch(a:000[l:i+1], 1, 0) . '\)'
    elseif (a:000[l:i] == '<=')
      if (l:pat != '') | let l:pat .= '\&' | endif
      let l:pat .= '\%(' . search#isearch(a:000[l:i+1], 0, 1) . '\)'
    elseif (a:000[l:i] == '<')
      if (l:pat != '') | let l:pat .= '\&' | endif
      let l:pat .= '\%(' . search#isearch(a:000[l:i+1], 0, 0) . '\)'
    endif
  endfor

  let @/ = l:pat
endfunction

command! -nargs=* Isearch call search#wrapper(<f-args>) | normal n

Вы можете найти его (или более новый) на моем github: https://github.com/tinmarino/Vimfiles/blob/master/autoload/search.vim

...