Is it possible to highlight unicode characters?

When I copy/paste a code sample I sometimes run into problems because the website uses , , or instead of - or some other characters that are hard to catch.

I'd like to get a visual indicator (e.g. a red background) that these are special characters.

I found some plugins to have the same intent but they don't work for my example:

2 Answers 2


With the help from Konfekt/vim-unicode-homoglyphs and the answers here I found this solution that works quite well and has (almost?) no performance impact:

augroup Hiunicode
  autocmd BufEnter *
      \ syntax match nonascii "[^\x00-\x7F]" |
      \ highlight nonascii ctermfg=NONE ctermbg=red
augroup END
  • Yep, this is basically what I recommended in my answer.
    – D. Ben Knoble
    Mar 2, 2021 at 19:08
  • FYI essentially a "synonym" for [^\x00-\x7F] you could use : [^[:graph:][:cntrl:][:blank:]]. That says anything that's not an ASCII printable character, ASCII control character or space/tab. Use [^[:graph:][:blank:]] if you want to see control characters, too, which probabl shouldn't be in a file.
    – B Layer
    Mar 2, 2021 at 21:35
  • (The last one won't highlight control characters representing line endings and tabs, though. That would have rendered it useless.)
    – B Layer
    Mar 2, 2021 at 21:41

I have a pretty general approach to this in ~/.vim/plugin/badwords.vim which I'll put here (word list subject to opinion). You could easily modify the list to capture the characters you care about. The file highlights all the words automatically (as long as the buffer has some syntax) and provides a global :Badsearch command to put all occurences in the quickfix list. It also supports defining g:badwords to extend the list.

Another option is to loop through the range of unicode-codepoints (or build a representative character class) and handle them in a similar way.

" ~/.vim/plugin/badwords.vim
if exists('g:loaded_badwords')
let g:loaded_badwords = 1

" obvious obviously
" basic basically
" simple simply
" of course
" clear clearly
" just
" everyone knows
" However,
" easy
" utilize utilized utilization utilizes
let s:badwords = [
      \ '\<obvious\(ly\)\?\>',
      \ '\<basic\(ally\)\?\>',
      \ '\<simpl\(e\|y\)\>',
      \ '\<of course\>',
      \ '\<clear\(ly\)\?\>',
      \ '\<just\>',
      \ '\<everyone knows\>',
      \ '\<However\>,',
      \ '\<easy\>',
      \ '\<utiliz\(e\w\?\|ation\)\>',
      \ ]

hi def link Badword ErrorMsg
function s:mark_bad(word) abort
  let l:pattern = printf('/\c%s/', a:word)
  exec 'syn match Badword' l:pattern 'containedin=ALL'

augroup Badword
  autocmd Syntax * for word in get(g:, 'badwords', []) + s:badwords | call s:mark_bad(word) | endfor
augroup END

command -bang -nargs=? -complete=file Badsearch
      \ execute 'vimgrep'
      \ '/'.join(get(g:, 'badwords', []) + s:badwords, '\|').'/'.(<bang>0 ? 'g' : '')
      \ (empty(<q-args>) ? expand('%') : <q-args>)
  • Thank you but I did not want to hunt for characters.
    – laktak
    Mar 2, 2021 at 17:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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