【问题标题】:Search range of Numbers (using real numbers in the search)数字的搜索范围(在搜索中使用实数)
【发布时间】:2012-03-28 10:31:50
【问题描述】:

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

示例:

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

    -- 所有数字必须包含十进制值 p.e. 9,20 或 8,532 是小于 10 的值
    -- 所有数字都可以插入(搜索)有或没有千位分隔符, 输出必须没有差异。

谁能帮我提供一个代码示例,我该怎么做?
我已经尝试创建这样的东西,计算位数,但它不能按我的意愿工作,因为这样我不能即时搜索 > 90,50 或

【问题讨论】:

  • 您能否发布您尝试过的示例以及失败的原因?
  • 当然,这是我尝试过的:\d\{4,}\(,\d\+\)*\|\d*\(\.\d\{3}\)\+\(,\d\+\)*(搜索数字 >=1000)-但我也想插入数字为 95,20,所以我认为使用数字而不是计算数字更容易,但我不知道如何解决这个问题。
  • 我已经阅读了一整天有关 Vim 的网站页面,但我找不到如何即时搜索一系列数字(在命令行中插入实数)。也许在vim中是不可能的?
  • 看起来像是 Perl 或 Python 等脚本语言的任务。可以从 Vim 中调用外部脚本来对范围或选择进行操作。
  • 我还检查了 perl、awk 和 sed。我没有在这些脚本语言中找到突出显示我的 vim 文档中的数字的东西。没有在 Python 中搜索:我的 VIM 与 Python 不兼容。

标签: search vim numbers range


【解决方案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*)\?\%(\ze\D\| $)\|\%([^0-9.]\zs\|^)4[6-9]\d\%(.\d*)\?\%(\ze\D\|$)\ |\%([^0-9.]\zs\|^)45[1-9]\%(.\d*)\?\%(\ze\D\|$)\|\%([ ^0-9.]\zs\|^)\d*\d{4}\%(.\d*)\?\%(\ze\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

【讨论】:

    【解决方案2】:

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

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

    搜索所有号码:/\v&lt;[0-9.]+&gt;

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

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

    标记编号 >132 和 :%s//\=submatch(0)>132 && submatch(0)<500 ? 'deleteme' : submatch(0)/g

    删除::g/deleteme/del


    不幸的是,找到它们并不是最好的解决方案!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-10-07
      • 1970-01-01
      • 2019-08-12
      • 2019-01-22
      • 1970-01-01
      • 1970-01-01
      • 2016-02-03
      相关资源
      最近更新 更多