1

我想向后视觉选择一个计算pe

200 + 3 This is my text -300 +2 + (9*3)
                        |-------------|*

This is text 0,25 + 2.000 + sqrt(15/1.5)
             |-------------------------|*

原因是我会在插入模式下使用它。编写计算后,我想选择计算(使用地图)并将计算结果放在文本中。

正则表达式必须做的是:
- 从光标(参见*上面的示例)向后选择到计算的开始
(包括\/-+*:.,^)。
- 计算只能从 log/sqrt/abs/round/ceil/floor/sin/cos/tan 或正数或负数
开始 - 计算也可以从行首开始,但永远不会回到上一行

我尝试了各种方式,但找不到正确的正则表达式。
我注意到向后搜索与向前搜索不同。

有人能帮我吗?

编辑
忘了提到它还必须包括“=”,如果有一个,如果“=”在光标之前,或者光标和“=”之间只有空格。
它不得包含其他“=”符号。

200 + 3 = 203 -300 +2 + (9*3) =
          |-------------------|<SPACES>*

200 + 3 = 203 -300 +2 + (9*3)
          |-----------------|<SPACES>*

*= 光标所在的位置

4

2 回答 2

3

在纯 vim 中接近的正则表达式是

\v\c\s*\zs(\s{-}(((sqrt|log|sin|cos|tan|exp)?\(.{-}\))|(-?[0-9,.]+(e-?[0-9]+)?)|([-+*/%^]+)))+(\s*\=?)?\s*

有一些限制:不解析子表达式(包括函数参数)。您需要使用适当的语法解析器来做到这一点,我不建议在纯 vim 1中这样做

运算符映射

要像使用文本对象一样使用它,请在 $MYVIMRC 中使用类似的内容:

func! DetectExpr(flag)
    let regex = '\v\c\s*\zs(\s{-}(((sqrt|log|sin|cos|tan|exp)?\(.{-}\))|(-?[0-9,.]+(e-?[0-9]+)?)|([-+*/%^]+)))+(\s*\=?)?\s*' 
    return searchpos(regex, a:flag . 'ncW', line('.'))
endf

func! PositionLessThanEqual(a, b)
    "echo 'a: ' . string(a:a)
    "echo 'b: ' . string(a:b)
    if (a:a[0] == a:b[0])
        return (a:a[1] <= a:b[1]) ? 1 : 0
    else
        return (a:a[0] <= a:b[0]) ? 1 : 0
    endif
endf

func! SelectExpr(mustthrow)
    let cpos  = getpos(".")
    let cpos  = [cpos[1], cpos[2]] " use only [lnum,col] elements
    let begin = DetectExpr('b')
    if ( ((begin[0] == 0) && (begin[1] == 0))
      \ || !PositionLessThanEqual(begin, cpos) )
        if (a:mustthrow)
            throw "Cursor not inside a valid expression"
        else
            "echoerr "not satisfied: " . string(begin) . " < " . string(cpos)
        endif
        return 0
    endif
    "echo "satisfied: " . string(begin) . " < " . string(cpos)

    call setpos('.', [0, begin[0], begin[1], 0])
    let end = DetectExpr('e')
    if ( ((end[0] == 0) || (end[1] == 0))
      \ || !PositionLessThanEqual(cpos,  end) )
        call setpos('.', [0, cpos[0], cpos[1], 0])
        if (a:mustthrow)
            throw "Cursor not inside a valid expression"
        else
            "echoerr "not satisfied: " . string(begin) . " < " . string(cpos) . " < " . string(end) 
        endif
        return 0
    endif
    "echo "satisfied: " . string(begin) . " < " . string(cpos) . " < " . string(end) 

    norm! v
    call setpos('.', [0, end[0],   end[1],   0])
    return 1
endf

silent! unmap X
silent! unmap <M-.>

xnoremap <silent>X :<C-u>call SelectExpr(0)<CR>
onoremap <silent>X :<C-u>call SelectExpr(0)<CR>

现在您可以对光标位置周围(或之后)最近的表达式进行操作:

  • vX - [v]通常选择 e[X]pression
  • dX - [d]删除当前的 e[X]pression
  • yX - [y]ank 当前 e[X]pression
  • "ayX - ID。注册a

作为一个技巧,使用以下内容从 OP 获得确切的 ascii 艺术(使用virtualedit进行演示):

插入模式映射

回复聊天:

" if you want trailing spaces/equal sign to be eaten:
imap <M-.> <C-o>:let @e=""<CR><C-o>"edX<C-r>=substitute(@e, '^\v(.{-})(\s*\=?)?\s*$', '\=string(eval(submatch(1)))', '')<CR>

" but I'm assuming you wanted them preserved:
imap <M-.> <C-o>:let @e=""<CR><C-o>"edX<C-r>=substitute(@e, '^\v(.{-})(\s*\=?\s*)?$', '\=string(eval(submatch(1))) . submatch(2)', '')<CR>

允许您Alt-.在插入模式下点击,并且当前表达式被它的评估替换。在插入模式下,光标最终位于结果的末尾。

200 + 3 This is my text -300 +2 + (9*3)

This is text 0.25 + 2.000 + sqrt(15/1.5)

通过按Alt-.入插件 3 次进行测试:

203 This is my text -271

This is text 5.412278

为了好玩:ascii 艺术

vXoyoEsc`<jPvXr-r|e.

自己轻松测试:

:let @q="vXoyo\x1b`<jPvXr-r|e.a*\x1b"
:set virtualedit=all

现在你可以@q在任何地方,它会用 ascii 装饰最近的表达式:)

200 + 3 = 203 -300 +2 + (9*3) =
|-------|*
          |-------------------|*

200 + 3 = 203 -300 +2 + (9*3)
          |-----------------|*
|-------|*

This is text 0,25 + 2.000 + sqrt(15/1.5)
             |-------------------------|*

1考虑使用Vim的python集成做这样的解析

于 2012-05-08T23:51:25.740 回答
1

毕竟用正则表达式来实现这似乎是一项相当复杂的任务,所以如果你能以任何方式避免它,请尝试这样做。

我创建了一个适用于几个示例的正则表达式 - 试一试,看看它是否有效:

^(?:[A-Za-z]|\s)+((?:[^A-Za-z]+)?(?:log|sqrt|abs|round|ceil|floor|sin|cos|tan)[^A-Za-z]+)(?:[A-Za-z]|\s)*$

您感兴趣的部分应该在第一个匹配组中。

如果您需要解释,请告诉我。

编辑:

^- 匹配一行的开头

(?:[A-Za-z]|\s)+- 匹配所有字母或空格一次或多次

匹配并捕获以下 3 个:
((?:[^A-Za-z]+)?- 匹配不是字母的所有内容(即在您的案例编号或运算符中)

(?:log|sqrt|abs|round|ceil|floor|sin|cos|tan)- 匹配您的关键字之一

[^A-Za-z]+)- 匹配不是字母的所有内容(即在您的案例编号或运算符中)

(?:[A-Za-z]|\s)*- 匹配所有字母或空格零次或多次

$- 匹配行尾

于 2012-05-08T11:58:34.753 回答