I'm writing a vimscript function that converts a single ASCII control-character in the range 1 - 26 (e.g. ^F) to its two-character printable representation (e.g. ^ F).

Currently, I have:

func! CtrlCharStr(arg)
  let cntrl = matchstr(a:arg, '^[[:cntrl:]]$')
  let ascii = char2nr(cntrl)

  if ascii >= 1 && ascii <= 26
    let letter = nr2char(ascii + 64)
    return '^'.letter
    return ''

Is there a more straightforward way to do this?

The reason I'm doing this in the first place is to check whether the given character appears in 'indentkeys', e.g. !^F, and should re-indent the current line instead of being inserted.


Maybe you could use the strtrans() function. From :h strtrans():

The result is a String, which is {expr} with all unprintable
characters translated into printable characters |'isprint'|.
Like they are shown in a window.  Example:
        echo strtrans(@a)
This displays a newline in register a as "^@" instead of
starting a new line.

As an example, you could try this function:

fu! CtrlCharStr(arg) abort
    return a:arg =~# '^[[:cntrl:]]$'
    \?         strtrans(a:arg)
    \:         ''

Or without continuation lines:

fu! CtrlCharStr(arg) abort
    return a:arg =~# '^[[:cntrl:]]$' ? strtrans(a:arg) : ''

If the argument passed to the function is a single control character, the function should return its caret notation. Otherwise, it should return an empty string.

?: is a ternary operator used to build a conditional expression. The latter evaluates to different values depending on whether an arbitrary test succeeds:

expr = test ? value1 : value2

If test is true, then expr evaluates to value1, otherwise to value2.

For more information, see :h expr1.

| improve this answer | |
  • Great! strtrans() is exactly what I was looking for. – ivan Mar 17 '18 at 22:29

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.