Consider the following line:

€   €

This file is encoded in UTF-8 and between the two Euro marks is a Tab character (the Stack Exchange software expands this to spaces). The byte value is:

e2 82 ac 09 e2 82 ac 0a

In my script I would like to get the character under the cursor.

Vim has several useful functions for dealing with strings in a multibyte-aware fashion, but getting the cursor position seems difficult:

  • col('.') will return the byte position. So for the tab it will return 4 rather than 2.
  • virtcol('.') almost works, but will expand tabs, so this isn't a true character position either.
  • All other functions behave as one of the two above.

What I have so far is:

fun! Getchar()
    let l:line = substitute(getline('.'), '\t', repeat(' ', &tabstop), 'g')
    return strcharpart(l:line, virtcol('.') - 1, 1)
nnoremap GG :echo Getchar()<CR>

Which almost works, but not for the above example since the displayed width is less than &tabstop spaces long.

  • 1
    I would simply use yl plus some saving and restoring of register to take care of. – Christian Brabandt Feb 19 '17 at 18:34

We discussed it less then 10 days ago on reddit.

One solution is matchstr(getline('.'), '\%'.col('.').'c.') which doesn't mess with any register.

I've put the resulting functions (we can ask for the characters before, or after the cursor) in my vimscript library along with other functions on the subject.

  • Also note that we must not use virtcol here but actually col since the regexp will be \%1c. where 1 is an example interpolated col. If you have a virtcol value you must use \%1v. instead (:h ordinary-atom) – SidOfc Dec 8 '20 at 18:53

The following works and is faster than the matchstr() solution:

fun! Getchar()
  return strcharpart(strpart(getline('.'), col('.') - 1), 0, 1)
nnoremap GG :echo Getchar()<CR>

See my question Reliably get the character at a byte index in a string.

  • Best solution in my opinion. – Boris Brodski Dec 23 '20 at 11:22

I have been using this in my plugin.

let char = matchstr(getline('.')[col('.') - 1 :], '^.')

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.