我想向后选择一个计算p.e。
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>*
*
=光标所在的位置
答案 0 :(得分: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>
现在你可以操作光标位置周围(或之后)最近的表达式:
"a
y X - 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)
在插入3次中按 Alt - 。进行测试:
203 This is my text -271
This is text 5.412278
自己轻松测试:
: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集成来进行这样的解析
答案 1 :(得分:1)
毕竟用regex来实现这似乎是一项相当复杂的任务,所以如果你能以任何方式避免它,那么试着这样做。
我已经创建了一个适用于几个示例的正则表达式 - 尝试一下,看看它是否有效:
^(?:[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)*
- 匹配所有字母或空格零或更多次
$
- 匹配行尾