229
\$\begingroup\$

What happens when the CapsLock key on your keyboard doesn't have a notch in it?

"This hPPENS."

The goal of this program is to consistently emulate keyboard misses where each A press is replaced with CapsLock. Uppercase 'A's from the source should yield the same effect. When CapsLock is enabled, capitalization is reversed.

Test Cases

"The quick brown fox jumps over the lazy dog."
-> "The quick brown fox jumps over the lZY DOG."

"Compilation finished successfully."
-> "CompilTION FINISHED SUCCESSFULLY."

"What happens when the CapsLock key on your keyboard doesn't have a notch in it?"
-> "WhT Hppens when the CPSlOCK KEY ON YOUR KEYBOrd doesn't hVE  notch in it?"

"The end of the institution, maintenance, and administration of government, is to secure the existence of the body politic, to protect it, and to furnish the individuals who compose it with the power of enjoying in safety and tranquillity their natural rights, and the blessings of life: and whenever these great objects are not obtained, the people have a right to alter the government, and to take measures necessary for their safety, prosperity and happiness."
-> "The end of the institution, mINTENnce, ND dministrTION OF GOVERNMENT, IS TO SECURE THE EXISTENCE OF THE BODY POLITIC, TO PROTECT IT, nd to furnish the individuLS WHO COMPOSE IT WITH THE POWER OF ENJOYING IN Sfety ND TRnquillity their nTURl rights, ND THE BLESSINGS OF LIFE: nd whenever these greT OBJECTS re not obtINED, THE PEOPLE Hve  RIGHT TO lter the government, ND TO Tke meSURES NECESSry for their sFETY, PROSPERITY nd hPPINESS."

"aAaaaaAaaaAAaAa"
-> "" (Without the notch, no one can hear you scream)

"CapsLock locks cAPSlOCK"
-> "CPSlOCK LOCKS CPSlOCK"

"wHAT IF cAPSlOCK IS ALREADY ON?"
-> "wHt if CPSlOCK IS lreDY ON?"

The winning criterion is, as usual, the size of the submitted program's source code.

\$\endgroup\$
20
  • 125
    \$\begingroup\$ Welcome to the site! This is a nice first challenge, and unfortunately very relatable for me and my fT FINGERS. \$\endgroup\$
    – DJMcMayhem
    Commented Mar 14, 2018 at 18:29
  • 100
    \$\begingroup\$ If only the enter key also had a notch in it so this wouldn' \$\endgroup\$
    – 12Me21
    Commented Mar 14, 2018 at 19:33
  • 85
    \$\begingroup\$ t happen....... \$\endgroup\$
    – 12Me21
    Commented Mar 14, 2018 at 19:33
  • 30
    \$\begingroup\$ Literally joined this site to upvote "Without the notch, no one can hear you scream" \$\endgroup\$
    – lucasvw
    Commented Mar 15, 2018 at 21:10
  • 9
    \$\begingroup\$ I LSO WISH THt my keyboRD Hd a bigger bCKSPce kwt==et=y \$\endgroup\$ Commented Mar 16, 2018 at 20:58

65 Answers 65

137
\$\begingroup\$

AutoHotKey, 7 bytes

a::vk14

// Is this valid? This really do what OP want -- replace a by CapsLock (vk14).

Run this program, and type the input from keyboard..

\$\endgroup\$
8
  • 5
    \$\begingroup\$ "Is this valid?" OP did not specify input or output constraints so I´d consider this valid. \$\endgroup\$
    – Nefrin
    Commented Mar 15, 2018 at 13:22
  • 9
    \$\begingroup\$ Don't see too many ahk answers! \$\endgroup\$ Commented Mar 15, 2018 at 13:57
  • 3
    \$\begingroup\$ "my code runs everywhere" \$\endgroup\$ Commented Mar 15, 2018 at 15:02
  • 67
    \$\begingroup\$ ThT'S GREt but how do I disBLE IT? \$\endgroup\$
    – RobbG
    Commented Mar 16, 2018 at 13:52
  • 82
    \$\begingroup\$ @RobbG just type "killLL utohotkey" ... oh wIT \$\endgroup\$
    – Nefrin
    Commented Mar 16, 2018 at 14:04
36
\$\begingroup\$

V, 9 bytes

ò/ãa
xg~$

Try it online!

Hexdump:

00000000: f22f e361 0a78 677e 24                   ./.a.xg~$

Explanation:

ò       " Recursively:
 /ãa    "   Move forward to the next 'a' (upper or lowercase)
        "   This will break the loop when there are no more 'a's
x       "   Delete the 'a'
 g~$    "   Toggle the case of every character after the cursor's position.
\$\endgroup\$
26
\$\begingroup\$

Vim, 16 bytes

qq/\ca
xg~$@qq@q

Assumes the input is on a single line

Explanation

qq            Start a loop
 /\ca␊         Find the first occurence of an a, end the loop if there are none left
 xg~$          Remove it and invert the case of the rest of the file
@qq@q         End the loop 
\$\endgroup\$
6
  • \$\begingroup\$ Is this case insensitive finding of 'a'? \$\endgroup\$
    – Gnudiff
    Commented Mar 16, 2018 at 21:06
  • \$\begingroup\$ @Gnudiff \c anywhere in a regex-search enables case-insensitivity \$\endgroup\$
    – Endenite
    Commented Mar 16, 2018 at 21:14
  • \$\begingroup\$ Do you need to set a specific flag for g~$ to work? Because for me it only inverts case until the end of the line, not the whole file, so this doesn't really work for multiline files for me. \$\endgroup\$
    – Cubic
    Commented Mar 19, 2018 at 15:34
  • 1
    \$\begingroup\$ @Cubic As I wrote in the answer, it "assumes the input is on a single line" \$\endgroup\$
    – Endenite
    Commented Mar 19, 2018 at 15:58
  • \$\begingroup\$ @Cubic If you wanted it to go the end of the file and support inputs on multiple lines, you could do g~vG or vG~. \$\endgroup\$
    – DJMcMayhem
    Commented Mar 19, 2018 at 17:15
16
\$\begingroup\$

C, 72 bytes

Thanks to @Ton Hospel for helping to save 16 bytes!

t,c;f(char*s){for(t=0;c=*s++;6305%c?putchar(isalpha(c)?c^t:c):(t^=32));}

Try it online!

\$\endgroup\$
6
  • 2
    \$\begingroup\$ You can swap the case of letters using a xor with 32 \$\endgroup\$
    – Ton Hospel
    Commented Mar 14, 2018 at 19:19
  • \$\begingroup\$ You can probably save even more by having t be 0/32 instead of even/odd (xor t with 32 for each a) and then xor letters directly with t \$\endgroup\$
    – Ton Hospel
    Commented Mar 14, 2018 at 20:14
  • 2
    \$\begingroup\$ Nice way to detect a's \$\endgroup\$
    – Ton Hospel
    Commented Mar 14, 2018 at 20:17
  • 1
    \$\begingroup\$ @TonHospel Functions have to be reusable, and I don't think it counts as reusable if you need external code to make it usable again after each call. \$\endgroup\$
    – Steadybox
    Commented Mar 15, 2018 at 10:49
  • 1
    \$\begingroup\$ 6305%c is 0 if c is 13. \$\endgroup\$
    – Rosie F
    Commented Mar 16, 2018 at 11:55
13
\$\begingroup\$

Husk, 11 bytes

Γ·§?m\:€"Aa

Try it online!

Explanation

I'm using the somewhat obscure overloading of Γ called listNF, which constructs recursive functions that operate on lists. It corresponds to the following Haskell pattern:

listNF f = g
  where g (x : xs) = f g x xs
        g [] = []

The idea is that listNF takes a helper function f and returns a new function g, which takes a list. The function f takes a function, which will always be g, and the head x and tail xs of the list, and does something with them. In our application, f calls g recursively on xs. The program is interpreted like this:

Γ (· (§ (?m\) : (€"Aa")))
Γ (                     )  Create a function g that takes a list (x:xs) and applies a function on x and xs.
   · (                 )   Compose g with second argument of function in parentheses.
                           Instead of x and xs, the function is called on x and the result of a recursive call of g on xs.
                (€"Aa")    Check if x is 'A' or 'a'.
        (?m\)              If it is, then swap the case of every char in g(xs).
      §       :            Otherwise, prepend x to g(xs).
\$\endgroup\$
5
  • 4
    \$\begingroup\$ Wow, good thing I refreshed before I posted my 12 byte solution: Ḟ·+m\ṁx'Ax'a. Could we get an explanation? I can't find any information on what Γ does exactly and this seems like a good chance to learn. \$\endgroup\$ Commented Mar 15, 2018 at 0:02
  • 1
    \$\begingroup\$ @SophiaLechner Done. This version of Γ is a bit hard to explain, I hope you can make sense of it. \$\endgroup\$
    – Zgarb
    Commented Mar 15, 2018 at 8:16
  • 1
    \$\begingroup\$ Wow this is slow. Is it just TIO? \$\endgroup\$
    – FrownyFrog
    Commented Mar 15, 2018 at 13:00
  • 2
    \$\begingroup\$ @FrownyFrog It's Husk. Type inference of programs containing Γ seems to be slow in general. If you're not familiar with Husk, a program is interpreted by looping through all possible structures of the program (essentially the possible placements of parentheses) and all overloadings of each built-in, and choosing the first one where the result is well-typed. The interpreter is smart enough to reject some possibilities early, but it seems that the recursive version of Γ can mess with this step and force it to loop through a lot of choices. \$\endgroup\$
    – Zgarb
    Commented Mar 15, 2018 at 13:34
  • \$\begingroup\$ @SophiaLechner I wrote a tip that explains Γ in some detail. \$\endgroup\$
    – Zgarb
    Commented Mar 15, 2018 at 14:42
12
\$\begingroup\$

Retina, 33 21 17 bytes

i(Tv`lL`Ll`a.*
a

Try it online

Explanation:

i(              i is for case-insensitive, the paren makes it modify both stages
  Tv`           Transliteration, with simple overlaps (v) - 1 match at every start pos
     lL`Ll`     Replace lowercase with uppercase, and vice versa
           a.*  Every 'a' will match, overlapping to the end of the string
                This swaps the case on all letters after each 'a'
a               Replace all 'a's with nothing

-12 bytes thanks to Martin
-4 bytes thanks to Leo

\$\endgroup\$
4
  • \$\begingroup\$ Amazingly this is almost as short as the current Pyth solutions \$\endgroup\$
    – Ton Hospel
    Commented Mar 14, 2018 at 19:11
  • 1
    \$\begingroup\$ I think iT`aAlL`__Ll`a[^a]*a? also works for 21 bytes. \$\endgroup\$
    – Neil
    Commented Mar 14, 2018 at 20:29
  • \$\begingroup\$ 4 bytes shorter using overlapping matches \$\endgroup\$
    – Leo
    Commented Mar 14, 2018 at 21:37
  • \$\begingroup\$ I'm interested in how this works if you have time to add the explanation. Thanks! \$\endgroup\$
    – seshoumara
    Commented Mar 15, 2018 at 7:41
7
\$\begingroup\$

Python, 63 bytes

f=lambda s:s and[s[0]+f(s[1:]),f(s[1:]).swapcase()][s[0]in"aA"]

Another Python solution, works in Python 2 and 3. Takes a very long time for all but small inputs.

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

R, 92 bytes

cat(`[<-`(v<-el(strsplit(scan(,""),"a|A")),w<-c(F,T),chartr("a-zA-Z","A-Za-z",v)[w]),sep="")

Thank @Giuseppe for fixing the answer.

Explanation

# Write
cat(
  # Replace and return, this is the function that powers
  # the R store at index operations, a[i]<-b
  `[<-`(
    # First arg - what to replace = extract first list element
    # of a string input after splitting at a or A
    v<-el(strsplit(scan(,""),"a|A")),
    # Second arg - index to replace = abuse vector recycling
    # to create infinite F, T, F, T, F, etc series
    w<-c(F,T),
    # Third arg - replacement values = replace with case toggled letters
    chartr("a-zA-Z","A-Za-z",v)[w]),
  # Write without separation
  sep="")

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Perhaps I didn't make it clear, but this answer does not reverse capitalization when CapsLock is enabled (it only performs toupper), which is a requirement. \$\endgroup\$
    – Broadwell
    Commented Mar 14, 2018 at 21:19
  • 2
    \$\begingroup\$ ooohhhhhhh that's very clever with the c(F,T), although @Broadwell is right; looks like it'll be a chartr("a-zA-Z","A-Za-z",v)[w] rather than toupper \$\endgroup\$
    – Giuseppe
    Commented Mar 14, 2018 at 21:22
7
\$\begingroup\$

Java 8, 119 108 98 bytes

s->{int f=0,t;for(int c:s)if((t=c&95)==65)f^=1;else System.out.printf("%c",f<1|t<66|t>90?c:c^32);}

-11 bytes thanks to @OlivierGrégoire.
-10 bytes thanks to @Nevay.

Explanation:

Try it online.

s->{                           // Method with char-array parameter and no return-type
  int f=0,t;                   //  Flag-integer, starting at 0
  for(int c:s)                 //  Loop over the characters of the input as integers
    if((t=c&95)==65)           //   If the current character is an 'A' or 'a':
      f^=1;                    //    Toggle the flag (0→1 or 1→0)
    else                       //   Else:
      System.out.printf("%c",  //    Print integer as character
        f<1|                   //     If the flag-integer is 0,
        t<66|t>90?             //     or the current character isn't a letter:
         c                     //      Simply output the character as is
        :                      //     Else (the flag it 1 and it's a letter)
         c^32);}               //      Print it with its case reversed
\$\endgroup\$
8
  • 1
    \$\begingroup\$ Damn imperatives... they forbade me to post my answer before yours... Anyways, here's my answer, 11 bytes shorter: s->{int z=0,d;for(int c:s)if((d=c&95)==65)z^=1;else System.out.printf("%c",z<1|d<66|d>90?c:c<91?c|32:c&95);} \$\endgroup\$ Commented Mar 15, 2018 at 10:51
  • \$\begingroup\$ @OlivierGrégoire Nice answer! And what do you mean by forbade me to post? Is your work-network that strict? \$\endgroup\$ Commented Mar 15, 2018 at 11:16
  • \$\begingroup\$ My answer was ready for a while: I was just polishing the test cases before posting but then suddenly endless meetings happened. \$\endgroup\$ Commented Mar 15, 2018 at 11:19
  • 1
    \$\begingroup\$ No, it's ok, I only have to blame myself for not being quick enough before the meetings ;-) But thank you for suggesting this! \$\endgroup\$ Commented Mar 15, 2018 at 13:23
  • 2
    \$\begingroup\$ 98 bytes: s->{int f=0,t;for(int c:s)if((t=c&95)==65)f^=1;else System.out.printf("%c",f<1|t<66|t>90?c:c^32);} \$\endgroup\$
    – Nevay
    Commented Mar 17, 2018 at 17:01
7
\$\begingroup\$

JavaScript (ES6), 93 88 84 82 bytes

(saved 5 bytes thanks to @Shaggy, 4 bytes thanks to @user81655, and 2 bytes thanks to @l4m2.)

a=>a.replace(A=/./g,c=>c in{a,A}?(A=!A,''):A?c:c[`to${c<{}?'Low':'Upp'}erCase`]())

Test cases:

let f=

a=>a.replace(A=/./g,c=>c in{a,A}?(A=!A,''):A?c:c[`to${c<{}?'Low':'Upp'}erCase`]())

console.log(f("The quick brown fox jumps over the lazy dog."));
console.log(f("Compilation finished successfully."));
console.log(f("What happens when the CapsLock key on your keyboard doesn't have a notch in it?"));
console.log(f("The end of the institution, maintenance, and administration of government, is to secure the existence of the body politic, to protect it, and to furnish the individuals who compose it with the power of enjoying in safety and tranquillity their natural rights, and the blessings of life: and whenever these great objects are not obtained, the people have a right to alter the government, and to take measures necessary for their safety, prosperity and happiness."));
console.log(f("aAaaaaAaaaAAaAa"));
console.log(f("CapsLock locks cAPSlOCK"));
console.log(f("wHAT IF cAPSlOCK IS ALREADY ON?"));

\$\endgroup\$
9
  • 1
    \$\begingroup\$ ['to${c<'a'?'Low':'Upp'}erCase'] should save you a few bytes, replacing single quotes with backticks. \$\endgroup\$
    – Shaggy
    Commented Mar 15, 2018 at 0:13
  • \$\begingroup\$ Sure does, @Shaggy. Thanks! \$\endgroup\$ Commented Mar 15, 2018 at 15:51
  • \$\begingroup\$ Using ^1 to have u be the parity can let you initialise it shorter: s=>s.replace(u=/./g,c=>/a/i.test(c)?(u^=1,''):+u?c[`to${c<'a'?'Low':'Upp'}erCase`]():c) \$\endgroup\$
    – user81655
    Commented Mar 18, 2018 at 7:45
  • \$\begingroup\$ Also here's another tricky way to test for the letter a which is shorter: a=>a.replace(A=/./g,c=>c in{a,A}?(A^=1,''):+A?c[`to${c<'a'?'Low':'Upp'}erCase`]():c) \$\endgroup\$
    – user81655
    Commented Mar 18, 2018 at 7:53
  • \$\begingroup\$ Brilliant, @user81655, especially using the in operator like that. Always more to learn! \$\endgroup\$ Commented Mar 18, 2018 at 10:45
6
\$\begingroup\$

Ruby, 42 41 bytes

->s{s.sub!(/a(.*)/i){$1.swapcase}?redo:s}

Try it online!

A lambda accepting a string, mutating the string in place, and returning it. The trick here is that sub returns the string (a truthy value) if a substitution was made, and returns nil otherwise. The existence of swapcase is pretty handy, too.

-1 byte: Replace boolean logic with ternary operator, thanks to Asone Tuhid

->s{
  s.sub!(/a(.*)/i){     # Replace "a" followed by anything with
    $1.swapcase         #   the case-swapped capture group
  } ? redo              # If a match was found, restart the block
    : s                 # Otherwise, return the modified string
}
\$\endgroup\$
2
  • \$\begingroup\$ save 1 byte. The link was too long if I included all the test cases. \$\endgroup\$ Commented Mar 16, 2018 at 6:17
  • \$\begingroup\$ @AsoneTuhid Thanks... One of these days I'll remember to use the ternary operator straight away, so you won't have to remind me. \$\endgroup\$
    – benj2240
    Commented Mar 16, 2018 at 15:01
6
\$\begingroup\$

PowerShell Core, 105 bytes

"$args"|% t*y|%{if($_-in97,65){$c=!$c}else{Write-Host -n($_,("$_"|%("*per","*wer")[$_-in65..90]))[!!$c]}}

Try it online!

What with no real ternary operator and no default alias for printing to screen, it's not that short.

  • % t*y expands to | ForEach-Object -Method ToCharArray equiv. of "$args".ToCharArray()
  • Write-Host -n is for the parameter -NoNewLine
  • "$_" turns the [char] type back to [string] (chars have no upper/lower case in .Net)
  • |% *per does the same method call shortcut as earlier, but for .ToUpper(), same with .ToLower()
  • ($a,$b)[boolean test] abused as fake-ternary operator
  • !!$c force-casts to [bool] here it starts undefined $null so it gets forced it into existence as "caps lock: $false".
\$\endgroup\$
2
  • 1
    \$\begingroup\$ That |% t*y is a neat trick I'll need to remember. Shorter than [char[]], which I use a lot. I'd almost say that should go onto the Tips thread. \$\endgroup\$ Commented Mar 19, 2018 at 13:10
  • \$\begingroup\$ 94 bytes: -join($args|% t*y|%{if($_-eq'a'){$c=!$c}else{(("$_"|%("*per","*wer")[$_-in65..90]),$_)[!$c]}}). thanks for a |% *ethod operator! \$\endgroup\$
    – mazzy
    Commented Jul 8, 2018 at 11:55
6
\$\begingroup\$

Perl 5 -p, 31 30 29 bytes

-1 byte thanks to @nwellnhof

-1 byte thanks to @ikegami

#!/usr/bin/perl -p
s/a([^a]*)a?/$1^uc$1^lc$1/egi

Try it online!

\$\endgroup\$
5
  • \$\begingroup\$ Why not simply s/a(.*?)(a|$)/uc$1/egi (22 bytes)? \$\endgroup\$
    – nwellnhof
    Commented Mar 16, 2018 at 13:59
  • \$\begingroup\$ @nwellnhof Because the capslock when active toggles the case, it doesn't just uppercase \$\endgroup\$
    – Ton Hospel
    Commented Mar 16, 2018 at 15:18
  • 1
    \$\begingroup\$ Ah, I see. Then s/a(.*?)(a|$)/$1^uc$1^lc$1/egi is one byte shorter. \$\endgroup\$
    – nwellnhof
    Commented Mar 16, 2018 at 18:09
  • \$\begingroup\$ @nwellnhof Thanks, that is very neat \$\endgroup\$
    – Ton Hospel
    Commented Mar 16, 2018 at 20:51
  • \$\begingroup\$ a([^a]*)a? is shorter than a(.*?)(a|$) \$\endgroup\$
    – ikegami
    Commented Mar 18, 2018 at 8:47
6
\$\begingroup\$

C, 167 168 158 131 bytes

Thanks for @Martin Ender for the code review: I've switched the stream processing for string processing to help with reusability. Also many thanks to @RiaD and @ceilingcat for their suggestions.

c,d;(*t[][2])()={{isupper,tolower},{islower,toupper}};f(char*s){for(d=1;c=*s++;)t[0][1](c)==97?d=!d:putchar(t[!t[d][0](c)][1](c));}

Try it online!

How does it work?

/* int c is the input character,
   int d is the Caps Lock flag (1=off, 0=on)  starting as "Off". */
int c, d;
/* array of comparison functions and transformation functions for each state */
(*t[][2])() = {{isupper, tolower}, {islower, toupper}};

f(char *s) {
  /* Loop if we haven't hit the terminator */
  for(d = 1; c = *s++;)
    t[0][1](c) == 97 ?
      /* If tolower(c)=='a' then flip the Caps Lock state */
      d=!d:
      /* Otherwise, convert character according to the following table:

                       Character case
         Caps Lock  UPPER       LOWER
                ON  tolower()   toupper()
               OFF  toupper()   tolower()
      */
      putchar(t[!t[d][0](c)][1](c));
  }
}

Notes

  • s[][] is where the magic happens: [][0] is the comparison function and [][1] is the related transformation function for each state.
  • ! is applied to the comparison function to force it into the range [0,1].
\$\endgroup\$
7
  • \$\begingroup\$ Welcome to PPCG! Unfortunately, you can't rely on the initialisation of d like this because it means that your function is not reusable. A simple d=0; should fix it. \$\endgroup\$ Commented Mar 16, 2018 at 10:01
  • \$\begingroup\$ I wasn't sure if reusability or maintaining state was more important in this case. If reusability is more important, I would move the variable declarations inside the function so the beginning would read void f(){int c,d=0;[...]. In any case, the stream dies, so an edit is in order! \$\endgroup\$
    – ErikF
    Commented Mar 16, 2018 at 11:05
  • \$\begingroup\$ do you need s in your while loop? It can't became NULL unless you called with f(NULL) \$\endgroup\$
    – RiaD
    Commented Mar 16, 2018 at 14:42
  • \$\begingroup\$ d=!d for flipping \$\endgroup\$
    – RiaD
    Commented Mar 16, 2018 at 14:43
  • \$\begingroup\$ !! will be ! if you flip order of t, and start d with 1 \$\endgroup\$
    – RiaD
    Commented Mar 16, 2018 at 14:54
5
\$\begingroup\$

6502 machine code routine (C64), 51 bytes

A0 00 84 FE B1 FC F0 2A C9 41 F0 06 90 1A C9 C1 D0 08 A9 80 45 FE 85 FE B0 11
B0 06 C9 5B B0 08 90 04 C9 DB B0 02 45 FE 20 16 E7 C8 D0 D6 E6 FD D0 D2 60

Expects a pointer to a 0-terminated input string in $fc/$fd, outputs to the screen.

Commented disassembly

 .caps:
A0 00       LDY #$00
84 FE       STY $FE             ; init capslock state
 .loop:
B1 FC       LDA ($FC),Y         ; next char from string
F0 2A       BEQ .done           ; NUL -> we're done
C9 41       CMP #$41            ; compare to 'a'
F0 06       BEQ .isa            ; if equal, toggle capslock
90 1A       BCC .out            ; if smaller, direct output
C9 C1       CMP #$C1            ; compare to 'A'
D0 08       BNE .ctog           ; if not equal, check for letter
 .isa:
A9 80       LDA #$80            ; toggle bit 7 in caps lock state
45 FE       EOR $FE
85 FE       STA $FE
B0 11       BCS .next           ; and go on
 .ctog:
B0 06       BCS .cZ             ; if char larger 'A', check for 'Z'
C9 5B       CMP #$5B            ; compare with 'z'+1
B0 08       BCS .out            ; larger or equal -> direct output
90 04       BCC .tog            ; smaller -> apply capslock
 .cZ:
C9 DB       CMP #$DB            ; compare with 'Z'+1
B0 02       BCS .out            ; larger or equal -> direct output
 .tog:
45 FE       EOR $FE             ; toggle bit from capslock state
 .out:
20 16 E7    JSR $E716           ; output char
 .next:
C8          INY                 ; and loop to next char
D0 D6       BNE .loop
E6 FD       INC $FD
D0 D2       BNE .loop
.done:
60          RTS

Example assembler program using the routine:

Online demo

screenshot

Code in ca65 syntax:

.import caps ; link with routine above

.segment "BHDR" ; BASIC header
                .word   $0801           ; load address
                .word   $080b           ; pointer next BASIC line
                .word   2018            ; line number
                .byte   $9e             ; BASIC token "SYS"
                .byte   "2061",$0,$0,$0 ; 2061 ($080d) and terminating 0 bytes

.bss
string:         .res    $800

.data
prompt:         .byte   $d, "input> ", $0

.code
                lda     #$17            ; set upper/lower mode
                sta     $d018

                lda     #<prompt        ; display prompt
                ldy     #>prompt
                jsr     $ab1e

                lda     #<string        ; read string into buffer
                sta     $fc
                lda     #>string
                sta     $fd
                jsr     readline

                lda     #>string        ; call our caps routine on buffer
                sta     $fd
                jmp     caps

; read a line of input from keyboard, terminate it with 0
; expects pointer to input buffer in $fc/$fd
; NO protection agains buffer overflows !!!
.proc readline
                ldy     #$0
                sty     $cc             ; enable cursor blinking
                sty     $fe             ; temporary for loop variable
                lda     $fd
                sta     $2              ; initial page of string buffer
getkey:         jsr     $f142           ; get character from keyboard
                beq     getkey
                sta     $fb             ; save to temporary
                and     #$7f
                cmp     #$20            ; check for control character
                bcs     prepout         ; no -> to normal flow
                cmp     #$d             ; was it enter/return?
                beq     prepout         ; -> normal flow
                cmp     #$14            ; was it backspace/delete?
                bne     getkey          ; if not, get next char
                lda     $fe             ; check current index
                bne     prepout         ; not zero -> ok
                lda     $2              ; otherwise check if we're in the
                cmp     $fd             ;    first page of the buffer
                beq     getkey          ; if yes, can't use backspace
prepout:        ldx     $cf             ; check cursor phase
                beq     output          ; invisible -> to output
                sei                     ; no interrupts
                ldy     $d3             ; get current screen column
                lda     ($d1),y         ; and clear 
                and     #$7f            ;   cursor in
                sta     ($d1),y         ;   current row
                cli                     ; enable interrupts
output:         lda     $fb             ; load character
                jsr     $e716           ;   and output
                ldx     $cf             ; check cursor phase
                beq     store           ; invisible -> to store
                sei                     ; no interrupts
                ldy     $d3             ; get current screen column
                lda     ($d1),y         ; and show
                ora     #$80            ;   cursor in
                sta     ($d1),y         ;   current row
                cli                     ; enable interrupts
                lda     $fb             ; load character
store:          cmp     #$14            ; was it backspace/delete?
                beq     backspace       ; to backspace handling code
                ldy     $fe             ; load buffer index
                sta     ($fc),y         ; store character in buffer
                cmp     #$d             ; was it enter/return?
                beq     done            ; then we're done.
                iny                     ; advance buffer index
                sty     $fe
                bne     getkey          ; not zero -> ok
                inc     $fd             ; otherwise advance buffer page
                bne     getkey
done:           lda     #$0             ; terminate string in buffer with zero
                ldy     $fe             ; get buffer index
                iny
                bne     termidxok       ; and advance ...
                inc     $fd
termidxok:      sta     ($fc),y         ; store terminator in buffer
                inc     $cc             ; disable cursor blinking
                rts                     ; return
backspace:      ldy     $fe             ; load buffer index
                bne     bsidxok         ; if zero
                dec     $fd             ;   decrement current page
bsidxok:        dey                     ; decrement buffer index
                sty     $fe
                bcs     getkey          ; and get next key
.endproc        
\$\endgroup\$
3
  • \$\begingroup\$ I just have to say I admire you went to the effort to write in assembly. I don’t think this has much to do with the fact I used to really enjoy asm but maybe having the experience makes me more aware of what it entails. Experience or ease is besides the point to me. It brightens my day just a bit to see such enthusiasm too. \$\endgroup\$
    – Pryftan
    Commented Mar 18, 2018 at 21:23
  • \$\begingroup\$ @Pryftan thanks :) It's just a nice way to keep in practice, I'm working on some game and recently also demo code for this nice old machine :) \$\endgroup\$ Commented Mar 19, 2018 at 8:20
  • \$\begingroup\$ Well it's great to see! Keep it up; I remember enjoying asm but I don't think I'd enjoy it so much nowadays (unless maybe I had an old machine like you do, that is but possibly not even then) - C is my favourite all time and it's what I primarily use. Anyway, won't let this evolve into chat - just wanted to say I appreciated the answer! \$\endgroup\$
    – Pryftan
    Commented Mar 19, 2018 at 20:56
5
\$\begingroup\$

Jelly, 14 bytes

Œu=”Aœp⁸ŒsJḤ$¦

Try it online!

Full program.

Explanation:

Œu=”Aœp⁸ŒsJḤ$¦ Arguments: x
Œu             Uppercase x
  =”A          ^ Equals 'A' (vectorizes)
     œp⁸       ^ Partition ⁸ [⁸=x]
             ¦ Apply link A, keep results at specific indices B
        Œs     A: Swap case
            $  B: Form a >=2-link monadic chain
          JḤ      Arguments: y
          J       Get list indices ([1, length(list)]) of y
           Ḥ      Double (vectorizes) ^
                  This way, we only "apply" link A to even indices, so every second
                  element, starting from the secondd one.
\$\endgroup\$
2
  • \$\begingroup\$ Explanation of the code? \$\endgroup\$
    – SK19
    Commented Mar 16, 2018 at 22:00
  • 1
    \$\begingroup\$ @SK19 Added an explanation. \$\endgroup\$ Commented Mar 19, 2018 at 10:07
4
\$\begingroup\$

05AB1E, 12 bytes

õ?„AaS¡Dvć?š

Try it online!

Explanation

õ?             # print an empty string (to account for the special case of only A's)
  „AaS¡        # split on occurrences of "A" or "a"
       D       # duplicate
        v      # for each element in the top copy
         ć?    # extract and print the head of the other copy
           š   # switch the case of the rest of the other copy
\$\endgroup\$
4
\$\begingroup\$

Wolfram Language (Mathematica), 70 bytes

#//.{x___,"a"|"A",y___}:>Join[{x},ToUpperCase@#+ToLowerCase@#-#&@{y}]&

Try it online!

Takes input and output as a list of characters. For convenience I've added code in the footer to convert this from and back to a string.

How it works

The #//.{x___,"a"|"A",y___}:>Join[{x},...{y}]& part is standard: we find the first A (uppercase or lowercase), reverse case of that comes after the A, and repeat until there are no more A's to be found.

The interesting part is how we reverse case: the function ToUpperCase@# + ToLowerCase@# - #&. We add together the upper-cased version of the input and the lower-cased version of the input, then subtract the actual input. For example, given the list {"I","n","P","u","T"} this computes

{"I","N","P","U","T"}+{"i","n","p","u","t"}-{"I","n","P","u","T"}

which threads over lists as

{"I"+"i"-"I","N"+"n"-"n","P"+"p"-"P","U"+"u"-"u","T"+"t"-"T"}

and although Mathematica doesn't have any particular way of adding two strings, it's smart enough to simplify a+b-a to b for any values of a and b, including string values, so this simplifies to {"i","N","p","U","t"}.

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

PHP 101 99 bytes

for($s=$argn;$i<strlen($s);$i++)lcfirst($s[$i])==a?$s=strtolower($s)^strtoupper($s)^$s:print$s[$i];

Run like this:

echo '[the input]' | php -nR '[the code]'

Ungolfed:

for ($s = $argn; $i < strlen($s); $i++) {
    if (lcfirst($s[$i]) == 'a') {
        $s = strtolower($s) ^ strtoupper($s) ^ $s; // Flip the whole string's case.
    } else {
        print $s[$i]; // Print the current letter.
    }
}

This just loops through the string with a for loop, and on each iteration it checks if the current letter is a, if so, then flip the case of the whole string (method from here), and if not, then print the current letter.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ The convention for code golf is that all code must be included. That means you have to take input as function parameter and actually declare a function (via the function keyword in php) or have a complete script (e.g. using $argn, $argv, $_GET). So at the moment this is not a correct submission. Return must be echoed or returned (only allowed for functions ofc). \$\endgroup\$
    – Christoph
    Commented Mar 15, 2018 at 12:10
  • 1
    \$\begingroup\$ Thanks for that @Christoph, I'm kind of new to golfing :). I've updated my answer now, just let me know if there's anything else that's wrong. \$\endgroup\$
    – Ethan
    Commented Mar 15, 2018 at 20:14
  • \$\begingroup\$ @Christoph Wow! 75! Very nice! You have my +1 :) \$\endgroup\$
    – Ethan
    Commented Mar 16, 2018 at 16:07
4
\$\begingroup\$

Fortran (GFortran), 307 bytes

CHARACTER(999)F,G
G=' '
READ(*,'(A)')F
N=1
M=1
DO I=1,999
IF(F(I:I)=='a'.OR.F(I:I)=='A')THEN
M=-M
ELSEIF(M==1)THEN
G(N:N)=F(I:I)
N=N+1
ELSE
J=IACHAR(F(I:I))
SELECTCASE(J)
CASE(65:90)
G(N:N)=ACHAR(J+32)
CASE(97:122)
G(N:N)=ACHAR(J-32)
CASE DEFAULT
G(N:N)=F(I:I)
ENDSELECT
N=N+1
ENDIF
ENDDO
PRINT*,TRIM(G)
END

Try it online!

Since Fortran has not "advanced" tools for dealing with strings, I came up with this little monster.

Indented and commented:

CHARACTER(999)F,G	!Define input and output strings (up to 999 characters)
G=' '			!Fill output with spaces
READ(*,'(A)')F		!Take input
N=1			!Represent the position to be written in output string
M=1			!M=-1: Change case; M=1: Do not change case
DO I=1,999
	IF(F(I:I)=='a'.OR.F(I:I)=='A')THEN	!If the character is A...
		M=-M				!Ah-ha - you pressed cPS-LOCK!
	ELSEIF(M==1)THEN			!Case the character is not A, and do not need to change case...
		G(N:N)=F(I:I)			!...only copy the character
		N=N+1
	ELSE !Otherwise...
		J=IACHAR(F(I:I))			!...get ascii of current character
		SELECTCASE(J)
			CASE(65:90)			!If is upper case,
				G(N:N)=ACHAR(J+32)	!now is lower case
			CASE(97:122)			!If is lower case,
				G(N:N)=ACHAR(J-32)	!now is upper case
			CASE DEFAULT			!If do not belong to alphabet,
				G(N:N)=F(I:I)		!simply copy the character
		ENDSELECT
		N=N+1
	ENDIF
ENDDO
PRINT*,TRIM(G) !Trim out trailing spaces
END !That's all folks!
\$\endgroup\$
4
\$\begingroup\$

MATL, 23 20 bytes

'a A'Yb&Ybt2L)Yo2L(g

Try it online!

Explanation:

'a A'Yb   % form a cell array containing {'a', 'A'}
&Yb       % split input into substrings, with either of those ('a' or 'A') as delimiters
t2L)      % extract out the even positioned cells from that result
Yo        % switch the case of those substrings
2L(       % place the result back in even positioned cells of the original cell array
g         % convert cell array to matrix, concatenating all substrings in the process
          % implicit output

Older answer (23 bytes):

"H@'aA'm?~XHx}@w~?Yo]&h

Other methods I tried:

0w"@t'aA'm?x~}y?Yo]w]]xv!
t'aA'mXHYsot&y*XzcYowf([]H(
t'aA'mXHYsoy3Y2m*32*Z~c[]H(
\$\endgroup\$
4
\$\begingroup\$

Julia 1.0, 82 bytes

s->foldl((b,c)->c∈"aA" ? !b : (print(c+32isletter(c)sign('_'-c)b);b),s,init=1<0)

Explanation

De-golfed:

function f(s::String)::Bool
    foldl(s, init=false) do b, c
        if c ∈ "aA"
            return !b
        else
            print(c + 32 * (isletter(c) & b) * sign('_'-c))
            return b
        end
    end
end

foldl(f, s, init=false): takes a function f that maps a state and a Char c to a new state. Applys f repeatedly over each Char of the string s, always passing the state previously returned by f back to f. init is the initial state. Here the state represents whether caps-lock is on.

if c in "aA": If c is an upper- or lowercase 'a', just return the opposite state.

isletter(c) & b: Bool, returns true iff c is a letter and b indicates, that caps-lock is on.

sign('_'-c): -1 if c is lowercase, 1 if c is uppercase.

print(c + 32 * (isletter(c) & b) * sign('_'-c)): Bools act like 0/1 under simple arithmetic operations, so if caps-lock should have an effect, this either adds or substracts 32 from c, returning a Char with opposite case. Then just print that.

Try it online!

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

Vyxal s, 12 10 9 bytes

Saved 2 bytes by using to split the string with a regex.

Saved 1 byte by using to define the function.

`a|A`ṡ⁽Nẇ

Try it Online!

Explanation:

           # Implicit input
`a|A`ṡ     # Split string every instance 'a' OR 'A'
      ⁽N   # Define a function that swaps the casing of strings
        ẇ  # Apply the function to every 2nd string
           # 's' flag: concatenate top of the stack and print
\$\endgroup\$
3
\$\begingroup\$

Haskell, 92 bytes

import Data.Char
g x|x<'['=toLower x|1>0=toUpper x
f(a:b)|elem a"aA"=f$g<$>b|1>0=a:f b
f x=x

Try it online!

Explanation

First we declare g to be the function that maps lowercase to upper case and uppercase to lowercase. This is actually the majority of our bytecount. Then we define the function f. If the input to f is of the form a:b we do

f(a:b)
 |elem a"aA"=f$g<$>b
 |1>0=a:f b

a and A match the first pattern and thus we apply f to the input with it's case inverted. Otherwise we move a out front and apply f to b.

\$\endgroup\$
3
\$\begingroup\$

Husk, 15 bytes

ω(F·+otm\↕·≠_'a

Try it online!

Explanation

ω(F·+(tm\)↕·≠_'a) -- example input: "Bar, baz and Foo."
ω(              ) -- apply the following, until fixpoint is reached:
          ↕       -- | split string with predicate
           · _    -- | | the lower-cased character
            ≠ 'a  -- | | is not 'a'
                  -- | : ("B","ar, baz and Foo.")
  F               -- | apply the following to the tuple
    +             -- | | join the elements with..
   · (   )        -- | | ..the second element: "ar, baz and Foo."
       m\         -- | | | swap case: "AR, BAZ AND fOO."
      t           -- | | | tail: "R, BAZ AND fOO."
                  -- | : "BR, BAZ AND fOO."
                  -- : "BR, Bz ND fOO."
\$\endgroup\$
3
\$\begingroup\$

Rust, 330 bytes

fn main(){let mut i=String::new();std::io::stdin().read_line(&mut i);let mut o=vec![];let mut c=false;for l in i.trim().as_bytes(){if*l==65||*l==97{c=!c;}else if c{if l.is_ascii_uppercase(){o.push((*l).to_ascii_lowercase());}else{o.push((*l).to_ascii_uppercase());}}else{o.push(*l);}}println!("{}",String::from_utf8(o).unwrap());}

Ungolfed

fn main() {
    let mut input = String::new();
    std::io::stdin().read_line(&mut input);
    let mut output_chars = vec![];
    let mut capslock = false;
    for letter in input.trim().as_bytes() {
        if *letter == 65 || *letter == 97 {
            capslock = !capslock;
        } else if capslock {
            if letter.is_ascii_uppercase() {
                output_chars.push((*letter).to_ascii_lowercase());
            } else {
                output_chars.push((*letter).to_ascii_uppercase());
            }
        } else {
            output_chars.push(*letter);
        }
    }
    println!("{}", String::from_utf8(output_chars).unwrap());
}

Since this uses bytes instead of chars in the loop, 65 and 97 are the byte values for 'A' and 'a'.

I'm new to Rust, so this might be golfable further.

\$\endgroup\$
1
  • 3
    \$\begingroup\$ Welcome to PPCG! \$\endgroup\$
    – Giuseppe
    Commented Mar 15, 2018 at 12:09
3
\$\begingroup\$

Japt v2.0a0, 16 bytes

e/a.*/i_År\l_c^H

Try it


Explanation

e                   :Recursively replace
 /a.*/i             :RegEx /a.*/gi
       _            :Pass each match through a function
        Å           :  Slice off the first character
         r          :  Replace
          \l        :  RegEx /[A-Za-z]/g
            _       :  Pass each match though a function
             c^     :    Bitwise XOR the character code
               H    :    With 32
\$\endgroup\$
0
3
\$\begingroup\$

PHP 4, 77 76 75

foreach(spliti(a,$argn)as$b)echo$a++&1?strtoupper($b)^strtolower($b)^$b:$b;

Split into substrings by A (case insensitive) then toogle every second case.

Try it out here.


Old version

for(;a&$c=$argn[$i++];)trim($c,aA)?print($c^chr($f*ctype_alpha($c))):$f^=32;

walks over the string and toogles a flag if the current char is a or A else the char gets toogled depending on the flag and echoed.

\$\endgroup\$
3
\$\begingroup\$

SNOBOL4 (CSNOBOL4), 141 92 bytes

	I =INPUT
S	I ANY("Aa") REM . R =REPLACE(R,&LCASE &UCASE,&UCASE &LCASE) :S(S)
	OUTPUT =I
END

Try it online!

Assumes a single line of input.

A whopping 49 bytes saved by @ninjalj!

Line S does all the work, explained below:

I                    # in the subject string I match the following PATTERN:
 ANY("Aa")           # match A or a and
 REM . R             # match the remainder of I, assigning this to R
 =REPLACE(           # replace the PATTERN above with
          R, ...)    # R with swapped cases.
   :S(S)             # and if there was a match, goto S, else goto next line 

\$\endgroup\$
6
  • \$\begingroup\$ This gives the wrong answer (as you stated in your comment, case is swapped when CapsLock is on) \$\endgroup\$
    – mbomb007
    Commented Mar 14, 2018 at 18:34
  • \$\begingroup\$ I've edited the post to require case-swapping (rather than simply uppercase) when CapsLock is enabled because I never realized that my machine does this. \$\endgroup\$
    – Broadwell
    Commented Mar 14, 2018 at 18:35
  • \$\begingroup\$ @mbomb007 ah, I hadn't realized OP had changed it; I'm editing for an explanation now so I'll include that in the explanation. \$\endgroup\$
    – Giuseppe
    Commented Mar 14, 2018 at 18:35
  • \$\begingroup\$ I =INPUT;S I ANY("Aa") REM . R =REPLACE(R,&LCASE &UCASE,&UCASE &LCASE) :S(S); OUTPUT =I;END \$\endgroup\$
    – ninjalj
    Commented Mar 16, 2018 at 1:02
  • \$\begingroup\$ @ninjalj are you also a SNOBOL golfer or am I just terrible at golfing it?? \$\endgroup\$
    – Giuseppe
    Commented Mar 16, 2018 at 13:35
3
\$\begingroup\$

Stax, 12 bytes

ìo'½`║â↨╪U?5

Run and debug it online

It splits on a regex, and then alternately toggles case. Here's the same program, unpacked, ungolfed, and commented.

"a|A"|s split on regex /a|A/
rE  reverse and explode array to stack
W   repeat forever...
p   print top of stack with no newline
:~p print top of stack, case inverted, with no newline

Run this one

\$\endgroup\$
3
  • \$\begingroup\$ I somehow cannot relate your explanation to your code. \$\endgroup\$
    – SK19
    Commented Mar 16, 2018 at 21:59
  • \$\begingroup\$ Try stepping through the commented one, and watching the internal state of the interpreter. Does that help? \$\endgroup\$
    – recursive
    Commented Mar 16, 2018 at 22:29
  • 2
    \$\begingroup\$ @SK19: Oh, I think I see the problem. I didn't mention that stax programs have two representations. Ascii and packed. There's a lossless conversion between the two. Ascii is easy to type, but wasteful for golf, since there are only 95 symbols. The golfed program is packed, so it looks different, but it's the same program. \$\endgroup\$
    – recursive
    Commented Mar 16, 2018 at 23:45

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