# Overwrite a string on a tape

Take the string abcdfghjk. To overwrite it, starting from f, with the string wxyz, you would continue along the original, replacing each character with the one from the replacement string. The result would be abcdwxyzk.

Now, consider a string which would be too long to fit, like lmnopqrs. Starting at f you would get abcdlmnop, then hit the end of the string. In order to continue, you wrap back to the beginning, resulting in qrsdefghi. With a long enough string, you could even wrap around multiple times.

You should take three inputs: the original string, the replacement string, and an index to start replacing at. This can be zero or one indexed.

Test Cases:

"This is a string"  "That"                  0   ->  "That is a string"
"This is a string"  "That"                  5   ->  "This That string"
"This is a string"  "That"                  14  ->  "atis is a striTh"
"hi"                "Hello there!"          0   ->  "e!"
"hi"                "Hello there!"          1   ->  "!e"
"over"              "write multiple times"  0   ->  "imes"
"over"              "write multiple times"  3   ->  "mesi"


Other:

This is , shortest answer per language in bytes wins!

• Do we have to handle a index that would make us start past the end of the tape?
– Wezl
Apr 7 at 14:11
• @Wezl No [padding] Apr 7 at 14:11
• Can I take the length of the original string as an input value? (Asking based on a suggested golf) Apr 8 at 20:03
• @hyper-neutrino No, sorry. Apr 8 at 20:15

# Python 3, 39 bytes

def f(x,y,z):
for x[z%len(x)]in y:z+=1


Try it online!

-5 bytes thanks to ovs for spotting the trick with cleverly using python's for loop specifics

• You are really speed..... Apr 7 at 1:33
• @Wasif well, it has been 12 minutes, so not as speed, but had i seen it earlier i could've answered faster Apr 7 at 1:35
• -5 bytes using the way for loops work.
– ovs
Apr 7 at 6:06
• @ovs that's allowed? o.O Apr 7 at 6:09
• @Jonah The for loop assigns to the assignment target in for <target> in ... in every iteration. There is no extra scope for the for loop, so it can modify existing variables with that assignment. Here is an even more obscure example.
– ovs
Apr 7 at 7:33

# Jelly, 8 bytes

Ż¡sL}o@ƒ


Try it online!

## How it works

Take some of the examples (the two "over", "write multiple times" and "This is a string" "That", 14), and "layer" them, as though overwriting. At the end, the lowest letter in each column is taken:

over    over    This is a string
writ       w                  Th
e mu    rite    at
ltip     mul
le t    tipl
imes    e ti
mes

imes    mesi    atis is a striTh


We reshape the inputs into a matrix like this, then take the final character in each column. In order to offset the "overwriting" string, and to make the final replacement easier, we don't prepend spaces, instead 0s

Ż¡sL}o@ƒ - Main link. Takes R on the left and O on the right, i third
¡       - Do the following i times to R:
Ż        -   Prepend 0 to R
}    - To O:
L     -   Length of O, L
s      - Slice into rows of length L
ƒ - Reduce columnwise by the following, starting with O:
o@  -   Reversed logical OR, taking the final element,
or the first, if all zero


# Scratch 3.0, 37 blocks / 262 bytes

As ScratchBlocks syntax:

define(L)(y)(x)
set[a v]to(1
set[l v]to(length of(L
repeat(l
change[a v]by(1
end
set[a v]to((y)mod(l
set[! v]to(1
repeat(length of(x
replace item((a)+(1))of[T v]with(letter(!)of(x
change[! v]by(1
set[a v]to(((a)+(1))mod(length
end
say(T


I am very glad Scratch has a modulo block built-in, otherwise this would have been pain.

Try it on Scratch!

• "this would have been pain" It is still pain :P
– Wezl
Apr 7 at 3:12
• 32 blocks, 265 bytes, reusable
– att
Apr 7 at 6:30

# vim, 33 30 bytes

Thanks for the sweet golf @kops

Pure vim answer, the TIO link is to V, which is a superset of vim. Takes input in 3 lines: index, original string, replacement string. Final buffer is "replaced string" output. 1-indexed.

D3gJhmd@"|qqmmdlDmR"|@qq@q

D3gJhmd@"|qqmmdlDmR<C-r>"<esc>|mm@qq@q # with unprintables shown


Try it online!

Bonus 14 byte V answer, but vim is cooler

• very cool answer! Do you mind adding this to the LoTM thread? Apr 9 at 2:07
• @Razetime done! Thanks, happy accident that it was Vim for this month! Apr 9 at 15:59
• This is cool, I was stumbling over how to do this at all but the mark usage is very neat! Here's a direct golf to 30 bytes by smushing the two mms into one. By the way, how do you get unprintable characters into TIO? I haven't done any vim golfing on there before.
– kops
Apr 12 at 7:45
• Thanks so much @kops! The way that I put unprintables into TIO is to just write the program in vim, and then "+Y to copy it to my system clipboard. Then I paste into TIO. This only works in xterm for me, so I do it there. It could be easier. Apr 13 at 12:13
• @kops the -v flag on tio allows adding unprintable keystrokes like <esc> and <c-x> and so on Apr 19 at 5:34

# J, 31 30 bytes

1 :'-@u|.[[((|i.)~&#)]}u|.]'


Try it online!

Surprisingly hard to find a decent golf in J, given how simple the problem is.

This is a J adverb, modifying the index, and taking the main string as the right arg and the replacement string as the left arg. Eg:

'That' (5 f) 'This is a string'


This would have been the perfect place to use the semidual version of under u&.(a:v), but it cost more bytes than explicitly doing the rotation and its reverse.

## how

                     u|.]  NB. Rotate by index
}~      NB. Replace:
]        NB. String with
[                   NB. Replacement chars
((|i.)~&#)         NB. At indexes 0...<str len>
NB. Each modded by <replacement len>
-@u|.                      NB. Unrotate by index


# JavaScript (Node.js), 36 bytes

(a,b,i)=>b.map(c=>a[i++%a.length]=c)


Try it online!

Input two strings as array of characters. Input the integer as 0-indexed. Modify the first string in-place.

• Note that this function takes arrays (not strings) as arguments, probably because there is no map function for strings. This note is just an aide to understanding, not a criticism :) Apr 7 at 21:29
• @JaredBeck String in JavaScript is immutable. You cannot modify it in-place.
– tsh
Apr 8 at 1:32

# PowerShell, 79 bytes

param($x,$y,$i)$y|% t*y|%{$x=$x.remove(($n=$i++%$x.length),1).insert($n,$_)};$x


Try it online!

# C (gcc), 50 bytes

f(x,y,z)char*x,*y;{for(;*y;z++)x[z*=x[z]>0]=*y++;}


Try it online!

-45 bytes thanks to dingledooper with a lot of golfing from someone who actually knows C :P (also inlining ++, which i forgot about because python doesn't have that)
-1 byte thanks to tsh with a clever trick to set z to 0 if x[z] is 0, which happens with the null byte after the end of the string

• You can reach 56 bytes with a bit of golfing. It also helps to update x within the function rather than returning it. Apr 7 at 4:41
• @dingledooper oh, never knew that syntax was a thing. thanks! also TIL you can scanf regexs, lol Apr 7 at 5:00
• Oh, I had forgot to remove the useless char* at the beginning, so it can actually be 51 bytes Apr 7 at 5:24
• -1 byte: f(x,y,z)char*x,*y;{for(;*y;z++)x[z*=x[z]>0]=*y++;}
– tsh
Apr 7 at 5:38
• @AZTECCO because generally, taking extra values like that isn't allowed. I also just asked OP and it is confirmed that this isn't allowed. Apr 8 at 20:19

# APL (Dyalog Unicode), 19 bytes

Assumes ⎕IO←0.

{⍺@((⍴⍵)|⍺⍺+⍳⍴⍺)⊢⍵}


Try it online!

A dop which takes the index as the left operator operand ⍺⍺, the original string as right input ⍵ and the replacement string as a left input ⍺.

⍳⍴⍺ generate the indices of the replacement string.
⍺⍺+ add the index offset to each index.
(⍴⍵)| each index modulo the length of the original string.
⍺@(...)⊢⍵ place the replacement string at those indices in the original string.

# R, 81 bytes

function(o,r,i,?=utf8ToInt,!=nchar){p=?o;p[1+(i-1+1:!r)%%!o]=?r;intToUtf8(p)}


Try it online!

# Retina 0.8.2, 103 78 bytes

^.+
$* (1)*(¶(?<-1>.)*)(.*)¶$2$3$2
+¶.(.*)¶(.)
1¶$1$2¶
+1¶(.*)(.)
¶$2$1
G.


Try it online! Takes the 0-indexed index on the first line. Explanation:

^.+
$*  Convert the index to unary. (1)*(¶(?<-1>.)*)(.*)¶$2$3$2


Prefix the replacement string with the original string up to the index. This was inspired by @Wezl's sed answer. (Previously I was rotating the original string to bring the index to the beginning.)

+¶.(.*)¶(.)
1¶$1$2¶


Rotate the original string, replacing it with characters from the replacement string, keeping track of the number of characters rotated.

+1¶(.*)(.)
¶$2$1


Rotate the original string back to its initial position.

G.


Remove the now empty working lines.

# GNU sed <4.3-E, 125 124 117 bytes

Takes offset-0-based-unary-~tildes@replacement#textontape like ~~~~~~~~~~@banana made of mush#This is a tape made of text. The input tape and replacement cannot contain tilde ~, at @, or hash # characters.


s/(.*)@/@\1/
:
s/^(.*)@~(.*#\1(.))/\1\3@\2/
t
s/.*@#//
te
s/^(.*)@(.)(.*#\1)./\1\2@\3\2/
s/^(.*)@(.+#)\1$/@\2\1/ t :e  ## explanation ~~~~~~~~~~@banana made of mush#This is a tape made of text s/(.*)@/@\1/  @~~~~~~~~~~banana made of mush#This is a tape made of text @ is the cursor, which marks the current character :  start loop s/^(.*)@~(.*#\1(.))/\1\3@\2/  When the cursor is before a tilde ~, replace the ~ with the corresponding letter from the tape. t  If a ~ was replaced, loop again. This works like so: @~~~~~~~~~~banana made of mush#This is a tape made of text T@~~~~~~~~~banana made of mush#This is a tape made of text Th@~~~~~~~~banana made of mush#This is a tape made of text ... This is a @banana made of mush#This is a tape made of text s/.*@#// te  If the cursor has reached the end of the replacement, finish by branching to e s/^(.*)@([^~])(.*#\1)./\1\2@\3\2/  If the cursor is followed by a not ~ character, advance it and place that character on the tape. It finds its place in the tape with a backreference. Like so: This is a @banana made of mush#This is a tape made of text This is a b@anana made of mush#This is a bape made of text This is a ba@nana made of mush#This is a bape made of text ... This is a banana made of mu@sh#This is a banana made of mu s/^(.*)@([^~]+)#\1$/@\2#\1/


If the cursor is at the end of the tape but not the end of the replacement text, remove the replacement text before the cursor so it is now at the start of the line. Like so:

This is a banana made of mu@sh#This is a banana made of mu

->

@sh#This is a banana made of mu

t


If either of these above two replacements worked, the work is not finished, loop again.

:e


The end label

# Stax, 8 bytes

║H┤1╫╢╘i


Run and debug it

input taken as index, original, replacement.

## Explanation

Fdix+n%%_&
F          for each char in replacement:
d         delete current iteration
ix+      add iteration index and input index
n%    get original's length
%   modulo by that
(this is needed because & extends the string when out of bounds)
_  push current iteration value
& replace at that index


# Red, 54 bytes

func[s r i][forall r[s/:i: r/1 i:(i % length? s)+ 1]s]


Try it online!

# Charcoal, 16 bytes

ＰＳＭＮ→ＦＳ«Ｆ¬ＫＫＭⅈ←ι


Try it online! Link is to verbose version of code. Takes the index as the middle input. Explanation:

ＰＳ


Print the original string without moving the cursor.

ＭＮ→


Move to the desired index.

ＦＳ«


Loop over the characters of the replacement string.

Ｆ¬ＫＫ


If we reached the end of the original string...

Ｍⅈ←


... then move the cursor back to the beginning.

ι


Overwrite the original string with the current character of the replacement string.

(s!l@(h:t))i|(a,b:c)<-splitAt i s=(a++h:c)!t$i+1|0<1=s!l$0
(s!_)_=s


Try it online!

The relevant function is (!), which takes as input the original string s, the replacement string l and the index i (0-indexed).

## How?

Haskell is definitely the wrong tool for the job, since there is no easy way to replace a character at a given index in a string. As far as I can tell, the best way is to split the string s at index i in two parts, replace the first character of the second part, and then join them back.

To make up for the immutability of values in Haskell, we define the overwrite function recursively. $$\text{overwrite}(s,l,i)= \begin{cases} s&\text{if l=\epsilon},\\ \text{overwrite}(s,l,0)&\text{if i\ge\text{length}(s)},\\ \text{overwrite}(s',l[1:],i+1)&\text{where s'=s except for s'[i]=l[0]}. \end{cases}$$

# Java, 41 bytes

(o,r,i)->{for(var c:r)o[i++%o.length]=c;}


Takes two char arrays and the index as input.

Try it online!

# Ruby, 42 39 bytes

->a,b,n{b.map{|c|a[n%a.size]=c;n+=1};a}


Try it online!

Taking 2 char arrays in input.

# VBA, 105 bytes

Function f(x,y,z)
For i=1 To Len(x)
Mid(x,(z Mod Len(x))+1,1)=Mid(y,i,1)
z=z+1
Next
MsgBox x
End Function


Chosen VBA instead of VBScript, because VBA has Mid() instruction, but VBScript lacks that.

-5 bytes thanks to @BrianJ

• I know in VB6 and VB.NET you can use the name of the function (in your case f) as a variable and it counts as the return value. So instead of MsgBox x you could do f=x. I don't know if the same applies in VBA, but it's worth checking and save yourself 5 bytes. Apr 9 at 17:49
• I think you can remove the space after the 1 in your loop declaration. And you also have an s="" that doesn't appear to be used. Apr 9 at 17:53

# Icon, 55 bytes

procedure f(s,r,i)
!r:=:s[i%*s+1]&i+:=1&\z
return s
end


Try it online!

procedure, return and end add a lot to the bytecount :)

# Perl 5-lF, 38 bytes

$i=<>;$F[$i++%@F]=$_ for<>=~/./g;say@F


Try it online!

Input is on three lines:

original string
offset
replacement string


# Julia 1.0, 39 bytes

inputs and output are lists of chars

a*b*c=([a[mod1(c+=1,end)]=i for i=b];a)


Try it online!

# Rust, 129 bytes

This is about as close as I could get while maintaining safety

|mut x:Vec<u8>,y:Vec<u8>,z:usize|->String{let l=x.len();(z..y.len()+z).for_each(|i|x[i%l]=y[i-z]);String::from_utf8(x).unwrap()};

• Welcome to Code Golf! It looks like this takes input from variables, which isn't allowed. It shouldn't cost very many bytes to make this a function, which would be valid. Apr 12 at 13:52

# C (gcc), 50 bytes

o(v,e,r)char*v,*e;{for(;*e;r*=!!v[++r])v[r]=*e++;}


Try it online!

This is almost identical to @hyper-neutrino's answer, but I saved 3 bytes by writing the solution as a macro instead of a function.

# C (gcc), 47 bytes

#define f(x,y,z) for(;*y;z++)x[z*=x[z]>0]=*y++;


Try it online!

• Welcome to Code Golf! I'm not sure if answering with macros is typically allowed, otherwise they'd probably be used quite a bit more. At 50 reputation you'll get the ability to comment, which is helpful for suggesting small golfs to other answers. Apr 9 at 4:58
• Suggest dropping the space before the for` and the trailing semicolon. Apr 9 at 15:23
• @ceilingcat If you drop the semicolon, it will become a true snippet. Apr 14 at 11:29