Double rotation
Retina, 55 bytes
O$i`[a-m](?=.*([a-m]))?
$1
O$i`((?<![n-z].*))?[n-z]
$#1
Try it online!
Uses two sorting stages to rotate the first- and second-half letters separately.
05AB1E, 44 43 42 bytes
Оn2äø€J2ä©`ŠÃÁUÃÀVv®`yåiY¬?¦VëyåiX¬?¦Uëy?
Explanation
Generate a list of the letters of the alphabet of both cases. ['Aa','Bb', ..., 'Zz']
Оn2äø€J
Split into 2 parts and store a copy in the register.
2ä©
Extract the letters from the input that are a part of the 1st half of the alphabet, rotate it and store in X.
`ŠÃÁU
Extract the letters from the input that are a part of the 2nd half of the alphabet, rotate it and store in Y.
ÃÀV
Main loop
v # for each char in input
®` # push the lists of first and second half of the alphabet
yåi # if current char is part of the 2nd half of the alphabet
Y¬? # push the first char of the rotated letters in Y
¦V # and remove that char from Y
ëyåi # else if current char is part of the 1st half of the alphabet
X¬? # push the first char of the rotated letters in X
¦U # and remove that char from X
ëy? # else print the current char
Try it online!
Note: The leading Ð
can be omitted in 2sable for a 41 byte solution.
Javascript (ES6), 155 142 138 bytes
s=>(a=[],b=[],S=s,R=m=>s=s.replace(/[a-z]/gi,c=>(c<'N'|c<'n'&c>'Z'?a:b)[m](c)),R`push`,a.unshift(a.pop(b.push(b.shift()))),s=S,R`shift`,s)
Edit: saved 3 4 bytes by using unshift()
(inspired by edc65's answer)
How it works
The R
function takes an array method as its parameter m
:
R = m => s = s.replace(/[a-z]/gi, c => (c < 'N' | c < 'n' & c > 'Z' ? a : b)[m](c))
It is first used with the push
method to store extracted characters in a[]
(first half of alphabet) and b[]
(second half of alphabet). Once these arrays have been rotated, R()
is called a second time with the shift
method to inject the new characters in the final string.
Hence the slightly unusual syntax: R`push`
and R`shift`
.
Demo
let f =
s=>(a=[],b=[],S=s,R=m=>s=s.replace(/[a-z]/gi,c=>(c<'N'|c<'n'&c>'Z'?a:b)[m](c)),R`push`,a.unshift(a.pop(b.push(b.shift()))),s=S,R`shift`,s)
console.log("Hello_world", "=>", f("Hello_world"));
console.log("codegolf", "=>", f("codegolf"));
console.log("HELLO_WORLD", "=>", f("HELLO_WORLD"));