搜索数字范围(在搜索中使用实数)

时间:2012-03-28 10:31:51

标签: search vim numbers range

我想搜索一系列数字(在VIM中),但不知道如何:

示例:

  • 搜索号码> 450,20
  • 搜索号码> 1200(或1.200)
  • 搜索号码> 10.000 AND< 1.000.000
  • 搜索数字< 10

    - 所有数字必须包含小数值p.e. 9,20或8,532是小于10的值 - 可以使用或不使用千位分隔符插入(搜索)所有数字, 输出必须没有区别。

任何人都可以帮我一个代码示例,我该如何继续? 我已经尝试创建这样的东西,计算数字的位数,但它不能按我的意愿工作,因为这样我就不能将值搜索为> 90,50或< 200在飞行中。

2 个答案:

答案 0 :(得分:1)

轻松你不能......但是通过努力,你可以做任何事情!
搜索数字> 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

答案 1 :(得分:0)

我发现当我需要搜索比数字更大/更小的东西时,我还需要对匹配做一些事情。对于这种情况,submatch() 可能非常有用。

考虑我想将所有大于 132 且小于 500 的数字归零的情况。

搜索所有号码:/\v<[0-9.]+>

将 >132 和 <500 的所有数字归零::%s//\=submatch(0)>132 && submatch(0)<500 ? '0' : submatch(0)/g

如果您想逐行工作,也可以将这个技巧与 :global 一起使用:

标记数字 >132 和 <500 的行::%s//\=submatch(0)>132 && submatch(0)<500 ? 'deleteme' : submatch(0)/g

删除::g/deleteme/del


不幸的是,这不是找到它们的最佳解决方案!