28
\$\begingroup\$

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.

\$\endgroup\$
2
  • \$\begingroup\$ Is it ok if we do the UK keyboard? Just four differences that I can tell. \$\endgroup\$
    – ouflak
    Feb 26, 2020 at 18:08
  • \$\begingroup\$ @ouflak I'm afraid not. \$\endgroup\$ Feb 26, 2020 at 20:01

17 Answers 17

9
\$\begingroup\$

x86-16, Genuine IBM PC, 32 31 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:

enter image description here

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:

enter image description here

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!

\$\endgroup\$
9
\$\begingroup\$

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<n<64\$, we XOR the ASCII code with \$16\$, which is what we need for:

    ! ↔️ 1
    # ↔️ 3
    $ ↔️ 4
    % ↔️ 5
    , ↔️ <
    . ↔️ >
    / ↔️ ?
    
  • If \$64\le n<127\$, 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\$).

\$\endgroup\$
7
\$\begingroup\$

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.

\$\endgroup\$
4
\$\begingroup\$

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 $a$b $b$a

Try it online!

\$\endgroup\$
20
  • 1
    \$\begingroup\$ 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.) \$\endgroup\$ Feb 23, 2020 at 22:37
  • 1
    \$\begingroup\$ @MitchellSpector Sorry it's a bit of a hack, did this from my phone! T_T Will fix it when I get a chance. \$\endgroup\$
    – Noodle9
    Feb 23, 2020 at 23:01
  • 1
    \$\begingroup\$ From your phone? That's impressive in itself! I don't think I could do that. \$\endgroup\$ Feb 23, 2020 at 23:03
  • 1
    \$\begingroup\$ @MitchellSpector All fixed now. \$\endgroup\$
    – Noodle9
    Feb 27, 2020 at 2:07
  • 1
    \$\begingroup\$ Nice solution! - \$\endgroup\$ Feb 27, 2020 at 2:25
3
\$\begingroup\$

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

\$\endgroup\$
4
  • \$\begingroup\$ Is taking the first 71 columns necessary? \$\endgroup\$ Feb 22, 2020 at 23:53
  • \$\begingroup\$ Could '\w\w...'⎕R(5⍴'') be replaced by a reverse-each line (so that the Caps<>Lock mapping is never used)? \$\endgroup\$ Feb 22, 2020 at 23:55
  • \$\begingroup\$ @JonathanAllan The 71 chops "Backspace" into "Backs" and reversing would expose "Enter" instead. \$\endgroup\$
    – Adám
    Feb 23, 2020 at 0:07
  • \$\begingroup\$ Ah, I see, so you'd need to ignore all characters paired with spaces too. \$\endgroup\$ Feb 23, 2020 at 0:11
3
\$\begingroup\$

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'=<_>?;{|}~)!@#$%^&*("+,-./:[\]`
                                 Ɗ    - last three links as a monad:
                              21      -   twenty-one
                             ṙ        -   rotate left                =)!@#$%^&*("+,-./:[\]`0123456789'=<_>?;{|}~
                                ,     -   pair                       =)!@#$%^&*("+,-./:[\]`0123456789'=<_>?;{|}~ and 0123456789'=<_>?;{|}~)!@#$%^&*("+,-./:[\]`
                                  y   - translate (S)
                                   Œs - swap case
\$\endgroup\$
3
\$\begingroup\$

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!

Explanation

  • 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.
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Change everything after the colon to [c.swapcase(),s[s.find(c)^1]][c in s] to save 4 bytes. \$\endgroup\$
    – mypetlion
    Feb 24, 2020 at 18:13
  • 1
    \$\begingroup\$ Clever use of boolean index! \$\endgroup\$ Feb 24, 2020 at 18:26
  • 1
    \$\begingroup\$ Thanks @mypetlion for spotting the erroneous extra space at the end! \$\endgroup\$ Feb 24, 2020 at 20:12
2
\$\begingroup\$

05AB1E, 53 36 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.

\$\endgroup\$
2
  • \$\begingroup\$ 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 œ + è... \$\endgroup\$
    – Grimmy
    Feb 24, 2020 at 13:09
  • 1
    \$\begingroup\$ @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. \$\endgroup\$ Feb 24, 2020 at 13:11
2
\$\begingroup\$

Perl 5 -p, 92 91 bytes

-1 byte thanks to @ValueInk

s/[]a-z{}|\\[]/$&^$"/gei;y/0-9)!@#$%^&*(`~\-=_+';":,.\/<>?/)!@#$%^&*(0-9~`_+\-=":';<>?,.\//

Try it online!

\$\endgroup\$
5
  • \$\begingroup\$ /[]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. \$\endgroup\$
    – Value Ink
    Feb 25, 2020 at 5:03
  • \$\begingroup\$ 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. \$\endgroup\$
    – Xcali
    Feb 25, 2020 at 17:59
  • \$\begingroup\$ 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 \$\endgroup\$
    – Value Ink
    Feb 26, 2020 at 0:27
  • \$\begingroup\$ 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. \$\endgroup\$
    – Xcali
    Feb 26, 2020 at 1:32
  • \$\begingroup\$ 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 \$\endgroup\$
    – Value Ink
    Feb 26, 2020 at 2:19
2
\$\begingroup\$

Pure Bash, 170 165 bytes

a=`echo {A..Z}`')!@#$%^&*("+,-./:[\]`'
b=`echo {a..z}`0123456789"'=<_>?;{|}~"
c=$a$b
d=$b$a
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.

\$\endgroup\$
14
  • \$\begingroup\$ You save 3 bytes using echo {a..z} {0..9} like this. \$\endgroup\$
    – Noodle9
    Feb 27, 2020 at 8:56
  • \$\begingroup\$ @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.) \$\endgroup\$ Feb 27, 2020 at 19:49
  • \$\begingroup\$ 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. :-( \$\endgroup\$
    – Noodle9
    Feb 27, 2020 at 23:01
  • \$\begingroup\$ @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.) \$\endgroup\$ Feb 27, 2020 at 23:10
  • \$\begingroup\$ @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. \$\endgroup\$ Feb 27, 2020 at 23:59
2
\$\begingroup\$

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!

\$\endgroup\$
1
\$\begingroup\$

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

\$\endgroup\$
1
\$\begingroup\$

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 $[0x$a^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 $[0x$a^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
\$\endgroup\$
1
\$\begingroup\$

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!

\$\endgroup\$
1
\$\begingroup\$

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!

\$\endgroup\$
1
\$\begingroup\$

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!

\$\endgroup\$
1
\$\begingroup\$

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.
\$\endgroup\$

Your Answer

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

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