I want to change 3rd byte of a string to x, i'm currently using this code:

let s = s[:1] . 'x' . s[3:]

It's a bit awkward, i wish i can do let s[2] = 'x', but that's not allowed.

Are there any other built-in ways to do it nicely?

1 Answer 1


In vimscript, strings are invariant: it would be very hard to poke odd bytes into a series of Unicode characters without trashing the entire thing.

Concatenation of parts as you have done is not so hard!

An alternative approach uses the substitute() function:

let s = substitute(s, "^\\(..\\).", "\\1x", "")

but that is not much more readable or flexible. It is possible to wrap up both attacks in a more useable fashion:

function! s:replacechar(src, pos, chr)
  if len(a:src) < a:pos
    return a:src
        return (a:pos ? a:src[0:(a:pos-1)] : "") . a:chr . a:src[(a:pos+1):]

function! s:rereplacechar(src, pos, chr)
  let l:pat = "^\\(" . repeat(".", a:pos) . "\\).\\(.*\\)"
  let l:rep = "\\1" . a:chr . "\\2"
  return substitute(a:src, l:pat, l:rep, "")

(Edit to correct a:p == 0 bug spotted by Mass)

Hope that helps


  • bug: when a:pos = 0, a:pos-1 is -1 and a:src[0:-1] yields the whole string.
    – Mass
    Apr 27, 2019 at 14:04
  • @TimFerguson Thanks. But i only want to know other built-in ways to do this, function is not an option. No need to consider unicode, it's byte index, not character index. You code would be clearer if you use single quote string.
    – dedowsdi
    May 6, 2019 at 3:39

Your Answer

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

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