# Objective

Given an ASCII character, toggle its "shift-ness" on the standard US keyboard (ANSI-INCITS 154-1988 (R1999)), then output it.

# Mapping

) ↔️ 0
! ↔️ 1
@ ↔️ 2
# ↔️ 3
$↔️ 4 % ↔️ 5 ^ ↔️ 6 & ↔️ 7 * ↔️ 8 ( ↔️ 9 " ↔️ ' + ↔️ = , ↔️ < - ↔️ _ . ↔️ > / ↔️ ? : ↔️ ; (Capital Latin letters) ↔️ (Small Latin letters) [ ↔️ { \ ↔️ | ] ↔️ }  ↔️ ~ (ASCII whitespaces and control characters are left intact)  # Rule • Non-ASCII characters fall into don't care situation. # Examples Given a character 0, output ). Given a character C, output c. Given a character (space), output . Given a character \t (horizontal tab), output \t. Given a character \a (bell), output \a. • Is it ok if we do the UK keyboard? Just four differences that I can tell. Feb 26 '20 at 18:08 • @ouflak I'm afraid not. Feb 26 '20 at 20:01 ## 17 Answers # x86-16, Genuine IBM PC, 3231 29 bytes 00000000: b4f0 8ec0 bfe5 e8b3 3ab1 74a0 8200 f2ae ........:.t..... 00000010: 3acb 7f02 f7db 268a 41ff cd29 c3 :.....&.A..).  Build with xxd -r. Unassembled listing: B4 F0 MOV AH, 0F0H ; BIOS segment address (F000H) 8E C0 MOV ES, AX ; set ES to BIOS segment for SCASB BF E8E5 MOV DI, E8E5H ; set to LABEL K10 B3 3A MOV BL, 58 ; size of table B1 74 MOV CL, 58*2 ; size of both tables A0 0082 MOV AL, BYTE PTR DS:[82H] ; get input char from command line F2/ AE REPNZ SCASB ; search BIOS table for char 3A CB CMP CL, BL ; found in the lowercase table? 7F 02 JG UPPER ; if so, convert with uppercase table by adding F7 DB NEG BX ; otherwise subtract the offset UPPER: 26:8A 41 FF MOV AL, ES:[BX+DI-1] ; get char from table CD 29 INT 29H ; DOS fast write to console C3 RET ; return to DOS  Input/Output: How does it work? Well, the PC BIOS already contains all of the code and tables necessary for this since it actually handles the conversion of scan codes received from the keyboard to ASCII chars (in real/DOS mode at least). There's no way (that I know of) to actually hook this on just any "PC-compatible" BIOS, however if you know the location of the table in ROM (on the IBM PC it starts at F000:E8E5), you can use that. On Page A-25 of Appendix A the IBM PC Technical Reference (listing of the entire source code of the PC BIOS) is the disassembly of this table: Unfortunately, this address will be different on any given PC-clone BIOS and of course, there's no guarantee that it would even be implemented in the same way by anyone else. Thus, this submission is guaranteed to run only on a Genuine IBM PC. Go Big Blue! # JavaScript (Node.js), 110 ... 97 96 bytes c=>(s=")0@2^6&7*8(9\"'+=-_:;~")[s.indexOf(c)^1]||(B=Buffer)([([n]=B(c),n%127>32)<<4+n/64^n])+''  Try it online! ### How? We use a lookup table for these pairs: ) ↔️ 0 @ ↔️ 2 ^ ↔️ 6 & ↔️ 7 * ↔️ 8 ( ↔️ 9 " ↔️ ' + ↔️ = - ↔️ _ : ↔️ ;  ↔️ ~  For all other characters, we use the following code: (B = Buffer)([ // generate a buffer from a singleton array: ( // [n] = B(c), // n = ASCII code of the input character n % 127 > 32 // 1 if 32 < n < 127, or 0 otherwise ) // << 4 + n / 64 // left-shifted by 4 if n < 64, or by 5 otherwise ^ n // XOR'ed with n ]) + '' // end of Buffer(); coerce it to a string  which supports these 3 cases: • If $$\32, we XOR the ASCII code with $$\16$/extract_tex], which is what we need for: ! ↔️ 1 # ↔️ 3 ↔️ 4 % ↔️ 5 , ↔️ < . ↔️ > / ↔️ ?  • If $$\64\le n<127$$/extract_tex], we XOR the ASCII code with $$\32\$$, which toggles the case of letters and also works for these pairs: [ ↔️ { \ ↔️ | ] ↔️ }  • If $$\n\le32\$$ or $$\n=127\$$, the character is left unchanged (ASCII code XOR'ed with $$\0\$$). # Retina 0.8.2, 34 bytes T-~A-]d';-?/.+,:"(*&^%#@!)}-_Ro  Try it online! Link includes test cases. Explanation: The T command is Retina's transliteration operation. Among its special characters are: • : Delimit the parts of the command • -: Introduce a range (this suppresses the following special characters so d-o just means defghijklmno) • _: Delete the matching character • d: 0-9 • R: Reverse the next range • o: Take the source string as the range The trick is therefore to create as many ranges as possible to reduce the length, plus avoiding having the - and _ characters where they would be interpreted as a special character and avoiding the  at all by including it inside a range. Additionally arranging for the range to transliterate to its reversal allows that to be expressed very cheaply. # Bash + core utilities, 58 $$\\cdots\$$ 51 49 bytes Added 47 50 bytes to fix a bug kindly pointed out by Giuseppe. Saved 8 bytes thanks to Value Ink!!! Saved 2 bytes thanks to Mitchell Spector!!! a='"A-]=<_>?)!@#%^&*(;' b=\'a-~+-: tr ab ba  Try it online! • I like the idea behind this, but it doesn't seem to be coming out right. For example, 'A' => 'b'. Also, it's not actually bash -- it's "bash + core utilities", so I think the language listed should be changed accordingly. (tr isn't a bash built-in.) Feb 23 '20 at 22:37 • @MitchellSpector Sorry it's a bit of a hack, did this from my phone! T_T Will fix it when I get a chance. Feb 23 '20 at 23:01 • From your phone? That's impressive in itself! I don't think I could do that. Feb 23 '20 at 23:03 • @MitchellSpector All fixed now. Feb 27 '20 at 2:07 • Nice solution! - Feb 27 '20 at 2:25 # APL (Dyalog Extended), 86 bytesSBCS This solution has been out-golfed but is preserved due to being interesting for its sourcing of the data. Anonymous prefix lambda. Requires 0-based indexing (⎕IO←0). {⍵∊a←↑'[!-~]{2}'⎕S'&'↓⍉↑'\w\w...'⎕R(5⍴'')↓11 71↑30↓⎕FMT⌂notes.keyboards:a⌷⍨~@1⊃⍸⍵=a⋄⍵}  Try it online! This works by extracting the character pairs from a built-in note about keyboards. {} "dfn"; argument character is ⍵: ⌂notes.keyboards the built-in string ⎕FMT ForMaT as a character matrix 30↓ drop the first 30 lines 11 71↑ take the first 11 lines' first 71 columns ↓ split into list of strings '\w\w...'⎕R() PCRE Replace word-character,word-character,any-symbol,any-symbol with: '' the empty string 5⍴ reshaped to length 5, padding with spaces; i.e. 5 spaces ↑ mix list of strings into character matrix ⍉ transpose ↓ split matrix into list of strings '[!-~]{2}'⎕R'&' PCRE Search and return any pair of printable ASCII characters ↑ mix list of character pairs into two-column matrix a← store in a (for all) ⍵∊: if the argument character is a member of that matrix: ⍵= Boolean matrix mask where they are equal ⍸ get indices where true ⊃ pick the first (row,column) pair ~@1 negate the number at position 1 (the column; i.e. 1→0 and 0→1) a⌷⍨ use that to index into the matrix of all pairs ⋄ else: ⍵ the argument character • Is taking the first 71 columns necessary? Feb 22 '20 at 23:53 • Could '\w\w...'⎕R(5⍴'') be replaced by a reverse-each line (so that the Caps<>Lock mapping is never used)? Feb 22 '20 at 23:55 • @JonathanAllan The 71 chops "Backspace" into "Backs" and reversing would expose "Enter" instead. – Adám Feb 23 '20 at 0:07 • Ah, I see, so you'd need to ignore all characters paired with spaces too. Feb 23 '20 at 0:11 # Jelly, 38 37 bytes “Æz⁶ɦG!€u<ʂCP]ƭƝ’œ?ØṖḟØB¤ḊØD;ṙ21,ƊyŒs  A monadic Link accepting a list of characters which yields a list of characters. Try it online! ### How? Forms a mapping for non alphabetic characters, applies the translate atom, y, and then swaps case. “Æz⁶ɦG!€u<ʂCP]ƭƝ’œ?ØṖḟØB¤ḊØD;ṙ21,ƊyŒs - Link: list of characters, S “Æz⁶ɦG!€u<ʂCP]ƭƝ’ - base 250 number =53994992086540427749431907521542401 ¤ - nilad followed by link(s) as a nilad: ØṖ - printable characters = !"#%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[$^_abcdefghijklmnopqrstuvwxyz{|}~ ØB - base-62 characters =0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ḟ - filter discard = !"#%&'()*+,-./:;<=>?@[$$^_{|}~ œ? - lexicographical permutation = '=<_>?;{|}~)!@#$%^&*("+,-./:[\]
Ḋ            - dequeue                      ='=<_>?;{|}~)!@#$%^&*("+,-./:[\] ØD - digit characters =0123456789 ; - concatenate =0123456789'=<_>?;{|}~)!@#$%^&*("+,-./:[\]
21      -   twenty-one
ṙ        -   rotate left                =)!@#$%^&*("+,-./:[\]0123456789'=<_>?;{|}~ , - pair =)!@#$%^&*("+,-./:[\]0123456789'=<_>?;{|}~ and 0123456789'=<_>?;{|}~)!@#$%^&*("+,-./:[\] y - translate (S) Œs - swap case  # Python 3, 99 95 bytes Same strategy as @Arnauld's answer. -4 bytes thanks to @mypetlion lambda c,s=")0!1@2#3$4%5^6&7*8(9\"'+=,<-_.>/?:;[{\\|]}~":[c.swapcase(),s[s.find(c)^1]][c in s]


Try it online!

• s=")0!1@2#3$4%5^6&7*8(9\"'+=,<-_.>/?:;[{\\|]}~" contains all pairs of special toggles. • s[s.index(c)^1] gets the index of the other character from the same pair • If the character is a Latin or control character (c in s is False), c.swapcase() is returned. c.swapcase() toggles the case of a Latin character, but doesn't affect control character. • Change everything after the colon to [c.swapcase(),s[s.find(c)^1]][c in s] to save 4 bytes. Feb 24 '20 at 18:13 • Clever use of boolean index! Feb 24 '20 at 18:26 • Thanks @mypetlion for spotting the erroneous extra space at the end! Feb 24 '20 at 20:12 # 05AB1E, 5336 35 bytes .šžQžiмDœ•1ĀêŽƵÆ{çIΣeÿí‚Ð"pkālrÙ•è‡  -1 byte implicitly thanks to @Grimmy due to his comment. Try it online or verify all printable ASCII characters. NOTE: The TIO versions use the S•...•.I (builtin for the n'th permutation of a list) instead of œ•...•è (push all permutations of the string (extremely slow bottleneck for a string this large), and index into it). Explanation: .š # Switch-case of the (implicit) input-character (if it's a letter) žQ # Push all printable ASCII characters: # !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz{|}~
žiм   # Remove all letters [A-Za-z]:
#   !"#$%&'()*+,-./0123456789:;<=>?@[\]^_{|}~ D # Duplicate it œ # Push a list of all permutations of this string •1ĀêŽƵÆ{çIΣeÿí‚Ð"pkālrÙ• "# Push compressed integer 540470878544692028277787799913384202055137480696656 è # Index it into the string-list of permutations: # 1'3457"908=<_>?)!@#$%^&*(;:,+./2{|}6-~[\]
‡       # Transliterate the characters at the same indices
# (after which the result is output implicitly)


See this 05AB1E tip of mine (section How to compress large integers?) to understand why •1ĀêŽƵÆ{çIΣeÿí‚Ð"pkālrÙ• is 540470878544692028277787799913384202055137480696656.

This number(+1) is generated by the Jelly builtin Œ¿, which gets the 1-based index of the permutation.

• Oooh we have an nth-permutation built-in, why did i never notice that! Though I guess it doesn't actually save any bytes over œ + è... Feb 24 '20 at 13:09
• @Grimmy Hmm, seeing your comment actually made me realize that œ...è is a byte shorter here, since .I doesn't work on strings (only on lists). So I can drop the S. Feb 24 '20 at 13:11

# Perl 5-p, 92 91 bytes

-1 byte thanks to @ValueInk

s/[]a-z{}|\$]/&^"/gei;y/0-9)!@#%^&*(~\-=_+';":,.\/<>?/)!@#%^&*(0-9~_+\-=":';<>?,.\//  Try it online! • /[]a-z{}|\$$]/ lets you cut out the extra backslash while still matching ] in your first regex. Also, why did you put those particular characters into its own s/// operation instead of wrapping them into the y///? I don't know much about Perl but I did use the Ruby y/// analogue (tr) in my own solution without needing to do a regex sub at all. Maybe that could help you out with golfing your solution. Feb 25 '20 at 5:03 • You don't need the substitution, but it works out to be a couple of bytes shorter than accounting for those characters in the translation. Feb 25 '20 at 17:59 • Hmmm. Could you have 2 strings (one with upper only and one with lower only) and pass them into tr in different orders similar to what I did in my Ruby solution? I'm not sure how costly it is to declare variables in Perl though Feb 26 '20 at 0:27 • No. tr/// is a quote-like operator in Perl. It does not do variable interpolation. You'd have to put it inside an eval, costing even more bytes. Feb 26 '20 at 1:32 • I figured it out; eval might cost bytes, but not as much as it saves. 77 bytes, probably can be golfed further depending on how the strings are set up Feb 26 '20 at 2:19 # Pure Bash, 170 165 bytes a=echo {A..Z}')!@#%^&*("+,-./:[$' b=echo {a..z}0123456789"'=<_>?;{|}~" c=ab d=ba for((;n<164;n++)){ [ "1" = "{c:n:1}" ]&&echo {d:n:1}&&exit;} echo "1"  Try it online! I decided to implement a solution inspired by @Noodle9's very nice answer, but using pure bash without any utilities (like tr). Note that you need to run this in an empty directory; this can be fixed at the cost of 2 bytes by using quotes for "{d:n:1}". (This issue only arises with a non-empty current directory when the input is 8, so the output is supposed to be *.) On the other hand, you can gain 2 bytes if you don't require output for the input \n: just eliminate the quotes in the final echo. • You save 3 bytes using echo {a..z} {0..9} like this. Feb 27 '20 at 8:56 • @Noodle9 Thanks for the suggestion. I had tried that before posting, but it was a little bit longer that way. (The problem is that {0..9} expands to 0 1 2 3 4 5 6 7 8 9, so I needed to add spaces into the other string to make the two strings still match up correctly.) But maybe you figured out some clever way of dealing with that? (Your link looks like it's just a link to your original answer, not to whatever you intended to link to.) Feb 27 '20 at 19:49 • Sorry I sent the wrong link. I didn't perform any magic, simply substituted {0-9} for 0123456789 and it worked for your test. So incorrect then. :-( Feb 27 '20 at 23:01 • @Noodle9 That's a shame -- I was hoping you had come up with some cool trick for getting past that issue! (If it worked for you on some test, you must have gotten lucky with the particular input you happened to try.) Feb 27 '20 at 23:10 • @Noodle9 Unfortunately, that doesn't work :( . If you look at the test in your link, you'll see that, for instance, b gets mapped to b, instead of to B. I investigated it a bit when I was working on this answer, and it turns out that the {A..Z} construct isn't expanded on the right side of an assignment statement. Feb 27 '20 at 23:59 # Julia, 87 bytes x->Char[0:32;b"1'3457\"908=<_>?)!@#%^&*(;:,+./2";97:125;b"6-~";65:93;96;127][Int(x)+1]  Try it online! # APL (Dyalog Extended), 60 bytesSBCS Anonymous tacit prefix function. -(,⊃⍨⍳-¯1*⍳)⍨('"''+=,<-_.>/?:;[{\|]}~',∊')!@#%^&*(',¨⎕D),-  Try it online! - swap case (), prepend the following: ⎕D the digits ')!@#%^&*(',¨ prepend each of these characters to the corresponding digit ∊ϵnlist (flatten) '"''+=,<-_.>/?:;[{\|]}~', prepend these characters ('' is an escaped single quote) -()⍨ apply the following function with that as left argument and the case-swapped original argument as right argument: ⍳ɩndex of the case-swapped argument in the substitution string ¯1* negative one raised to that power ⍳- subtract that from the ɩndex of the case-swapped argument in the substitution string ,⊃⍨ use that to pick an element from the case-swapped argument appended to the substitution string # Pure Bash, 217 bytes P=printf\ a=P%x "'1" case a in 3[ab])x=1;;2[27])x=5;;2[68]|3[79])x=17;;2a|38)x=18;;2b|3d)x=22;;29|30)x=25;;36|5e)x=104;;2d|32|40|5f)x=114;;20|7f)x=0;;60|7e)x=30;;[23]?)x=16;;[4-7]?)x=32 esac P\\P%o [0xa^x]  Try it online! Just bash -- no Unix utilities. Input character is passed as an argument, and the output is on stdout. _____________________________________________________________ Test runs:  cat shifttoggle P=printf\ a=P%x "'1" case a in 3[ab])x=1;;2[27])x=5;;2[68]|3[79])x=17;;2a|38)x=18;;2b|3d)x=22;;29|30)x=25;;36|5e)x=104;;2d|32|40|5f)x=114;;20|7f)x=0;;60|7e)x=30;;[23]?)x=16;;[4-7]?)x=32 esac P\\P%o [0xa^x] cat shifttoggleTest #!/bin/bash count=1 for s in ')!@#%^&*("+,-./:' "0123456789'=<_>?;" ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz '[$$' '{|}~' $' \a\n\r\t\x7F\x80\x88\x8F' do echo "TEST #$count"

for ((n=0;n<${#s};n++)) do c="${s:$n:1}" d=./shifttoggle "$c"

# Backticks remove any trailing newline, so restore that here for the case where c is \n (you can check that shifttoggle really prints \n in that case).
if test -z "$d" then d=$'\n'
fi

if test "$count" -eq 7 then printf " ASCII %d => ASCII %d\n" "'$c" "'$d" else echo "$c => $d" fi done (( count++ )) echo '' done$ ./shifttoggleTest
TEST #1
) => 0
! => 1
@ => 2
# => 3
$=> 4 % => 5 ^ => 6 & => 7 * => 8 ( => 9 " => ' + => = , => < - => _ . => > / => ? : => ; TEST #2 0 => ) 1 => ! 2 => @ 3 => # 4 =>$
5 => %
6 => ^
7 => &
8 => *
9 => (
' => "
= => +
< => ,
_ => -
> => .
? => /
; => :

TEST #3
A => a
B => b
C => c
D => d
E => e
F => f
G => g
H => h
I => i
J => j
K => k
L => l
M => m
N => n
O => o
P => p
Q => q
R => r
S => s
T => t
U => u
V => v
W => w
X => x
Y => y
Z => z

TEST #4
a => A
b => B
c => C
d => D
e => E
f => F
g => G
h => H
i => I
j => J
k => K
l => L
m => M
n => N
o => O
p => P
q => Q
r => R
s => S
t => T
u => U
v => V
w => W
x => X
y => Y
z => Z

TEST #5
[ => {
\ => |
] => }
=> ~

TEST #6
{ => [
| => \
} => ]
~ => 

TEST #7
ASCII 32 => ASCII 32
ASCII 7 => ASCII 7
ASCII 10 => ASCII 10
ASCII 13 => ASCII 13
ASCII 9 => ASCII 9
ASCII 127 => ASCII 127
ASCII 128 => ASCII 128
ASCII 136 => ASCII 136
ASCII 143 => ASCII 143


# C (gcc), 100 bytes

char*strchrnul(),*s=")0@2^6&7*8(9\"'+=-_:;~\0";f(c){c=s[strchrnul(s,c)-s^1]?:(c%127>32)<<4+c/64^c;}


Similar to the Javascript strategy. I'd like to get rid of the extra parentheses but this is pretty good.

Try it online!

# Ruby-p, 66 bytes

Builds the "lowercase" and "uppercase" strings so that everything lines up, and connects them together to be passed into the tr function so it can do the proper conversions.

l="\\-a-z0-9=[-];',./"
u='_A-Z)!@#$%^&*(+{|}:"<>?~'$_.tr!u+l,l+u


Try it online!

# PowerShell, 189 bytes

param($x)if(($s=")0@2^6&7*8(9""'+=-_:;~").contains($x)){$s[$s.indexof($x)-bxor1]}else{
$n=[byte][char]$x;if($n-in32..64){[char]($n-bxor16)}elseif($n-in65..127){[char]($n-bxor32)}else{$x}}  Try it online! # PowerShell, 111 bytes $k=')!@#$%^&*("+,-./:[\]'+'A'..'Z'+"0123456789'=<_>?;{|}~"+'a'..'z' "$k$k$args"[($p=$k|% i*f @args)+72*!!++$p]  Try it online! i*f is shortcut for indexOf. Explain: • The shift series contains 72 chars )!@#..A B C.. Y Z. • The shift-ness series contains 72 chars also • $k contains concatenated shift and shift-ness series
• if $args does not found in $k, then indexOf returns -1 and script returns the last char from string $k+$k+$args. It is $args.
• if $args found in $k, then the script return shifted char.