53
\$\begingroup\$

For today's challenge, you must write a program or function that alternates the case of a string. However, you must ignore non-alphabetic characters. This means that every alphabetic character must have a different case than the preceding and following alphabetic character. This is slightly more complex than uppercasing every other letter for example. If you take a string such as

hello world

and convert every other character to uppercase, you'll get:

hElLo wOrLd

As you can see, the lowercase o is followed by a lowercase w. This is invalid. Instead, you must ignore the space, giving us this result:

hElLo WoRlD

All non-alphabetic characters must be left the same. The output can start with upper or lowercase, as long as it consistently alternates. This means the following would also be an acceptable output:

HeLlO wOrLd

Your program should work regardless of the case of the input.

The input string will only ever contain printable ASCII, so you don't have to worry about unprintable characters, newlines or unicode. Your submission can be either a full program or a function, and you may take the input and output in any reasonable format. For example, function arguments/return value, STDIN/STDOUT, reading/writing a file, etc.

Examples:

ASCII                                   ->  AsCiI
42                                      ->  42
#include <iostream>                     ->  #InClUdE <iOsTrEaM>
LEAVE_my_symbols#!#&^%_ALONE!!!         ->  lEaVe_My_SyMbOlS#!#&^%_aLoNe!!!
PPCG Rocks!!! For realz.                ->  PpCg RoCkS!!! fOr ReAlZ.
This example will start with lowercase  ->  tHiS eXaMpLe WiLl StArT wItH lOwErCaSe
This example will start with uppercase  ->  ThIs ExAmPlE wIlL sTaRt WiTh UpPeRcAsE
A1B2                                    ->  A1b2

Since this is , standard loopholes apply and the shortest answer in bytes wins!

\$\endgroup\$
6
  • 38
    \$\begingroup\$ Ugh, I've only just realised this was that meme xD \$\endgroup\$
    – Beta Decay
    Commented May 25, 2017 at 17:26
  • 1
    \$\begingroup\$ @BetaDecay Hahaha, that was not my intention. More just unfortunate timing. I though of it as a chat-mini-challenge, and I like the idea behind it because it's subtly harder than it seems. \$\endgroup\$
    – DJMcMayhem
    Commented May 25, 2017 at 17:28
  • 4
    \$\begingroup\$ The next challenge is to print an ascii spongebob à la cowsay \$\endgroup\$
    – 000
    Commented May 25, 2017 at 19:41
  • 1
    \$\begingroup\$ Darn it! I just wrote a CJam script for this (as in yesterday) and deleted it. \$\endgroup\$ Commented May 26, 2017 at 1:58
  • 2
    \$\begingroup\$ There is some missed potential for the title or at least the examples using either penguin of doom or sporks. \$\endgroup\$
    – Ian
    Commented May 26, 2017 at 6:00

48 Answers 48

1
2
2
\$\begingroup\$

QuadR, 26 bytes

(\pL)(\PL*)(\pL?)
\u1\2\l3

Try it online!

Replace instances of "letter, 0 or more non-letters (greedy), optional letter" with the uppercase first letter, the non-letters, the lowercase last letter.

\$\endgroup\$
2
\$\begingroup\$

APL (Dyalog Extended), 8 bytes

⊢×≠\⍤|⍤×

Try it online!

 the argument

× case-adjusted by (1: uppercase; 0: lowercase)

≠\⍤… the XOR-scan of…

|⍤… the absolute value of…

× the case (1: uppercase; −1: lowercase)

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

PHP 5, 54 bytes

<?=preg_filter('/\pL/e','($0|" ")^a^aA[$i^=1]',$argn);
\$\endgroup\$
1
\$\begingroup\$

C#, 100 bytes

s=>{var r="";int m=0;foreach(var c in s)r+=char.IsLetter(c)?(char)(++m%2>0?c|32:c&~32):c;return r;};
\$\endgroup\$
1
\$\begingroup\$

Groovy, 79 bytes

{x=0;it.toUpperCase().collect{(it==~/\w/)?x++%2?it:it.toLowerCase():it}.join()}
\$\endgroup\$
1
\$\begingroup\$

Python 3, 192 bytes

x=list(input())
s=[]
for i in x[1::2]:
 s.append(i)
 x.remove(i)
s.reverse()
while len(x)<len(s):
 x.append("")
while len(x)>len(s):
 s.append("")
for i in range(len(x)):
 print(end=x[i]+s[i])

Try it online!

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

J, 40 bytes

(2|+/\@:e.&Alpha_j_)`(tolower,:toupper)}

Try it online!

This follows almost directly from the definition of Composite Item (}):

We stack the upper and lowercase version of the input for our two possibilities using (tolower,:toupper).

Next we create a boolean list to indicate whether each character is alphabetic: e.&Alpha_j_ and take the scan sum of that: +/\@: which creates a monotonically increasing list which increases only on alphabetic characters. Finally we turn that into a boolean list where evens are 0 and odds are 1: 2|.

Putting those parts together means we alternate between the lower and uppercase versions of our input whenever we encounter a new alphabetic character, and only then.

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

Japt v2.0a0, 11 10 bytes

r\lÈgYguiv

Try it

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

MUMPS, 98 bytes

 f i=1:1:$l(s) s c=$e(s,i) s:c?1A u=c?1U,f=$s(f="":u,1:'f),$e(s,i)=$c(2*f-1*-'(f=u)*32+$a(c))
 w s

Try it online!

  • f i=1:1:$l(s): Set i=1 and loop over this line of code until i reaches the length of the input string s (inclusive). i is incremented by 1 each loop.

  • s c=$e(s,i): Assign the ith character of s to c using the $extract function.

  • s:c?1A: Execute the following set statements if c is an alphabetical character (uppercase or lowercase). This line and the next use M's built-in string matching system.

  • u=c?1U: Make u a boolean storing whether c is an uppercase character. There is only one data type in M so u's value will be 1 for true or 0 for false.

  • f=$s(f="":u,1:'f): Make f a boolean storing whether c should be an uppercase character. f's value will also be 1 or 0. It's assigned u if this is the first alphabetic character because the first alphabetic character is in the right case by definition. Otherwise its value is flipped from its previous value using the not operator '.

  • $e(s,i)=$c(2*f-1*-'(f=u)*32+$a(c)): The left-hand side is the ith character of s again; we're setting it equal to the right-hand side which modifies s itself. $a (for $ascii) and $c (for $char) are inverses: the former converts characters to the corresponding ASCII number and the latter converts numbers back into characters. The argument of $c is a compact way to add 32 to $a(c) if c is lowercase but should be uppercase, subtract 32 from $a(c) if c is uppercase but should be lowercase, and add 0 if c is already in the right case. Note that M's operator precedence is strictly left to right, so 2*f-1*x is unintuitively the same as (2*f-1)*x.

  • Finally, w s prints the now-alternating s.

Both lines have a leading space so that their first characters are interpreted as commands and not labels.

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

SM83, 29 bytes

Input pointer in hl, output in de, trashes bc, a, flags.

06 55 2A 4F CB AF D6 41
38 0C FE 1A 30 08 CB A9
CB 08 38 02 CB E9 79 12
13 B7 20 E6 C9

Disassembled:

fun:
    ld  b,$55       ;; 06 55    ; set b to alternating bits
loop:
    ld  a,(hl+)     ;; 2A       ; load char
    ld  c,a         ;; 4F       ; and into c
    res 5,a         ;; CB AF    ; turn a-z into A-Z
    sub 65          ;; D6 41    ; subtract 'A'
    jr  c,store     ;; 38 0C    ; if was less, not a letter
    cp  26          ;; FE 1A    ; compare to 26
    jr  nc,store    ;; 30 08    ; if not less, not a letter
    res 5,c         ;; CB A9    ; it is a letter; make uppercase
    rrc b           ;; CB 08    ; rotate b and check low bit
    jr  c,store     ;; 38 02    ; every other time skip next bit
    set 5,c         ;; CB E9    ; actually, make lowercase
store:
    ld  a,c         ;; 79       ; store faster this way
    ld  (de),a      ;; 12       ; store
    inc de          ;; 13       ; and increment
    or  a           ;; B7       ; quick test against 0
    jr nz,loop      ;; 20 E6    ; if not 0 continue
    ret             ;; C9       ; else return
\$\endgroup\$
1
\$\begingroup\$

brev, 103 bytes

(define h(make-parameter #f))(over(if(char-alphabetic? x)((if(h(not(h)))char-upcase char-downcase)x)x))

Are the examples wrong? How do you get to InClUdE from AsCiI?

\$\endgroup\$
1
  • \$\begingroup\$ I think each example is independent of the previous input; and the case of the first letter doesn't matter as long as the following letters alternate cases. \$\endgroup\$
    – roblogic
    Commented Nov 7 at 5:23
1
\$\begingroup\$

Casio BASIC (casio fx-9750GIII), 128 bytes

?→Str 1
For 1→I To StrLen(Str 1
Isz H
StrSrc("ABCDEFGHIJKLMNOPQRSTUVWXYZ",StrMid(Str 1,I,1))=0⟹Dsz H
StrUpr(StrMid(Str 1,I,1))→Str 3
MOD(H,2⟹StrLwr(Str 3)→Str 3
Str 2+Str 3→Str 2
Next
Locate 1,1,Str 2

starts with lowercase

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

AWK, -F "" -vOFS="" 63 bytes

{for(;i++<NF;$i=x?tolower($i):toupper($i))$i~/[A-Za-z]/&&x=!x}1

Doesn't seem to work in TIO.

Try it online!

for(;i++<NF;                   # for each char
$i=x?tolower($i):toupper($i))  # switch by x
$i~/[A-Za-z]/                  # only letters
&&x=!x                         # flip x
}1                             # output default
\$\endgroup\$
0
\$\begingroup\$

Convex, 16 bytes

¯{_U&,R^:R{¬}&}%

Try it online!

Convex port of @Business Cat's answer.

\$\endgroup\$
0
\$\begingroup\$

Python 3, 95 bytes

Not nearly as golfed as @Rod's, but I'm posting it nevertheless.

lambda s:"".join([s[i],[s[i].lower(),s[i].upper()][i%2]][s[i].isalpha()]for i in range(len(s)))

Try it online!

\$\endgroup\$
0
\$\begingroup\$

C# (Visual C# Interactive Compiler), 84 bytes

int m,c;for(;(c=Read())>0;)Write((char)(c>64&c<91|c>96&c<123?m++%2>0?c|32:c&~32:c));

Try it online!

Modified version of The Lethal Coder's answer that takes advantage of some of the features of the interactive compiler.

\$\endgroup\$
0
\$\begingroup\$

Javascript, 104 bytes

I'm kind of new to this but wanted to submit anyway.

x=>x.split('').forEach((s,i)=>x+=i%2?s.toUpperCase():s.toLowerCase())||x.substring(x.length/2,x.length);

It takes in a string, splits it into an array so it can loop through with forEach and fit in as a one-liner, then goes through each character and index and adds the uppercase or lowercase version of the character depending on if the index is odd or not, then "or"s it with what I want to return (since otherwise it's undefined) and returns the second half of the string, so I don't have to clear the string to begin with or declare a new one.

However, this doesn't work with non-letter characters, so here's my pseudocode for something that would do that:

const sarcasticText = str=> {
    let newStr = '', numSkip = 0;
    for(let i=0; i<str.length; i++) {
        numSkip += str[i].match(/[a-z]/i) ? 0 : 1;
        newStr += (i + numSkip) % 2 ? str[i].toUpperCase() : str[i].toLowerCase();
    }
    return newStr;
};

Basically, I'd implement a counter to check how many characters to offset.

\$\endgroup\$
0
\$\begingroup\$

Zsh, 64 bytes

for x (${(Us::)1}){((64<#x&&#x<91&&++n%2))&&x=$x:l;printf %s $x}

Try it online!

Here we split and uppercase (Us::) the argument $1, and iterate for x each character. If the ASCII value of x lies in the range 65-90, and n is even(?), then change x to lowercase. Finally, print x.
++n%2 alternates between true/false for every letter.

Related; but I couldn't get $MATCH[1] and $MATCH[2] to alternate properly

\$\endgroup\$
1
2

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.