更新
提交的issue已在Vim 8.1.1061中修复。
我正在编写一个简短的脚本,以增加Vim中.srt文件的延迟。
实际上,核心功能可以是单行替换命令,用于搜索时间码,并引用一个助手函数,该助手函数将其参数转换为毫秒,进行数学运算,然后将结果转换回时间码格式。
但是,我想做一个额外的检查-如果任何新值是负数,则抛出一个异常,该异常我想处理。给定一个格式正确的字幕文件,其时间代码行按正确的顺序排列,我们可以假设在第一个匹配项(如果有的话)就立即抛出异常,因此无需担心任何状态更改-至少我是这么想的。
fun! s:DelayTimecodes(delay)
try
let saved_view = winsaveview()
let timecode = '\v\d{2}:\d{2}:\d{2},\d{3}'
exe 'keepjumps keeppatterns %s/' . timecode . '/'
\ . '\=s:DelayedTimecode(submatch(0), a:delay)/g'
catch 'illegal timecode value'
redraw | echo 'Cannot apply: the given delay time would result'
\ . ' in negative timecode value(s)'
finally
call winrestview(saved_view)
endtry
endfun
但是,当DelayedTimecode
表达式内的\=
抛出异常时,第一条匹配行上的匹配仍将替换为空字符串。作为一个临时解决方案,我编写了一个循环,逐行进行替换,首先创建整个延迟的行(这可能会引发异常),然后将其传递给替换命令。效果很好,但设计起来却很荒谬。
这背后的原因是什么?有什么方法可以避免这种行为,而无需撤消替换命令并清除历史记录,这有点麻烦?
答案 0 :(得分:1)
sub-replace-expression
不能很好地处理异常。您可以在Vim的bug tracker上提出问题,也可以在vim_dev mailing list上直接讨论此问题,但是这种情况有可能被归类为特定于实现的行为,并且被搁置一旁。
最简单的解决方法是只返回原始匹配项(submatch(0)
,而不是引发异常(使:substitute
成为无操作),并设置一个内部标志使表达式执行对于:substitute
中的表达式的每次后续调用都相同。然后,您可以像在:catch
中一样,检查该标志并打印错误消息。
如果要避免任何缓冲区修改(也将其标记为已修改),则必须:call search()
来找到第一个时间码实例,并将其提取(getline()
,matchstr()
),然后在实际的:substitute
之前进行检查。