如何自动小写单词的第二个字母?


13

当我不得不输入大量文本shift时,在写句子的第一个字母时,我常常会按住手指,这通常会给出:

[...]end of sentence. NEw sentence[...]

这里ENEw应该是小写。然后,我试图创建一个函数来检测我键入的句子的第一个单词的第二个字母是否为大写字母,而将其为小写字母。重要的部分是,当我键入句子的结尾时,更正应自动完成。

到目前为止,我已经尝试过使用autocommand事件,InsertCharPre然后才意识到该事件触发的功能无法修改文本。

有什么好的解决方案?

请注意,到目前为止,我不需要关注诸如首字母缩略词之类的边缘情况,首字母缩略词应使用大写字母或类似的东西。

编辑我做了这个,这不是一个完美的解决方法:

autocmd CursorMovedI * call RemoveUnwantedUpper()

function! RemoveUnwantedUpper()
    " Get the current sentence
    " Based on http://stackoverflow.com/a/23315227/4194289
    let l:save_clipboard = &clipboard
    set clipboard= " Avoid clobbering the selection and clipboard registers.
    let l:save_reg = getreg('"')
    let l:save_regmode = getregtype('"')

    normal! y(
    normal! ``

    let l:sentence =getreg('"') 

    call setreg('"', l:save_reg, l:save_regmode)
    let &clipboard = l:save_clipboard

    " Check that we entered a new word (space inserted)
    if l:sentence[len(l:sentence)-1] != " "
       return
    endif 

    " Check if the word is the first one of the sentence
    let l:size = len(split(l:sentence, " "))
    if l:size > 1 
        return
    endif

    " If the last char entered is a space (new word) remove the unwanted Upper case
   normal! bl
   normal! vu
   normal! ``

endfunction

由于在插入模式下输入的第一个字符已移至行尾,因此出现了问题,但我认为可以纠正。

我想现在我的问题变成了代码审查问题

  • 如何消除移动第一个插入字符的副作用?
  • 这是最好的方法吗?
  • 这种方法似乎减慢了Vim的速度:如何改进它?

Answers:


6

这里有些东西很快就熟了。我认为它不那么健壮,但也更轻巧。也许您可以将其合并到您的产品中以使其更快?有空的时候我可能会修改一下。

inoremap <Space> <C-o>:call CheckCase()<CR><Space>

function! CheckCase()
   normal! may2b
   let l:words = getreg('"')
   if l:words[0] == '.'
      normal! wlvu
   endif
   normal! `a
endfunction

我认为这不是一个完整的解决方案,但我想我会尝试一种不同的方法,看看它是否对您有启发。:)


4
重新映射的想法<Space>似乎很有趣,因为它减少了函数的调用次数。我也会尝试以这种方式工作!
statox

4

我不知道它的可靠性如何,但是您可以尝试以下方法:

augroup FixDoubleUppercase
    autocmd!
    autocmd InsertCharPre * if v:char =~ '\u' && getline('.') =~ '\v(\.\s+|^\s*)\u%' . col('.') . 'c' | let v:char = tolower(v:char) | endif
augroup END

它会安装一个autocmd,该命令将在插入字符之前执行以下命令:

if v:char =~ '\u' && getline('.') =~ '\v(\.\s+|^\s*)\u%' . col('.') . 'c' | let v:char = tolower(v:char) | endif

您要插入的字符存储在内部变量中v:char,并且如果测试:

v:char =~ '\u' && getline('.') =~ '\v(\.\s+|^\s*)\u%' . col('.') . 'c'

...成功,则自动命令分配一个新的价值v:char,这是tolower(v:char)

该测试检查您是否要插入大写字母(v:char =~ '\u'),并且光标位于句子第一个单词的第一个字符之后:

getline('.') =~ '\v(\.\s+|^\s*)\u%' . col('.') . 'c'

编辑:我不知道这两种语法之间是否存在差异(在性能方面): :let myvar = test ? new_value : old_value:if test | let myvar = new_value | endif

我曾经读过,当您要优化代码时,必须使用尽可能少的Ex命令。所以,也许第二个语法(这可算作3个Ex命令::if:let:endif)比一日一慢,我不知道。

但是,在这种情况下,可以将autocmd替换为:

autocmd InsertCharPre * let v:char = (v:char =~ '\u' && getline('.') =~ '\v(\.\s+|^\s*)\u%' . col('.') . 'c') ? tolower(v:char) : v:char

1
现在,这是一个优雅的解决方案!根据我的首次测试,它运作良好。我将不得不使用一段时间以确保它的健壮性。我喜欢您如何修改v:char我第一次尝试时就丢失的想法。
statox

1

另一种方法(不是那么自动,不是那么通用;只是更短):

  • 因为您是在写句子/散文,而不是代码,所以让Vim激活文本缓冲区中的拼写检查
  • 创建一个快速插入模式组合键,该键可以返回到最后的拼写错误,进行修复,然后恢复位置/状态;例如:

    inoremap <C-s> <Esc>[s1z=gi
    

所以现在说你开始写作

"THis is a mistake|"

...而您刚意识到错误-怎么办?-只需点击<C-s>并继续写句子即可。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.