15
\$\begingroup\$

Challenge :

Given a string split at specific positions and capitalize the first character of the given word. Capitalize the first word's first char if and only if it was already capitalized

Input :

A string s and a character c.

Ouput :

The string with each occurrence of c replaced with the first char capitalized

Examples :

STRING(s)             CHARACTER(c)  RESULT
Hello_world           _             HelloWorld
me,no,like            ,             meNoLike
you-got-it            -             youGotIt
Am^I^clear            ^             AmIClear
go!full!caps          !             goFullCaps
weird&but&tRue        &             weirdButTRue
ProbleM1fixed1no      1             ProbleMFixedNo
!prob!!lem!s!Olved!!  !             ProbLemSOlved

Note :

  • Given input will always be valid. i.e : The first will always be a string with at least one instance of the character to replace at. The second will always will be a single character.
  • The length of the input string will be greater 4.
  • There will be at least one occurrence of the character to split at.

  • The input is guaranteed to contain only letters and the separator (Thanks @Arnauld)

  • Separator is anything that is not an alphabet (a-z / A-Z) (suggested by @Dennis)

Winning criteria :

This is so shortest code in bytes for each language wins.


  1. Thanks to @JonathanAllan for pointing out two mistakes.
\$\endgroup\$
16
  • 7
    \$\begingroup\$ Tips when creating test cases: Make each one cover at least one corner case. All your test cases are basically identical (maybe except the one with 1). Try to think about how solutions might fail, and make a test case for such situations. Some examples: Letters as separators, the separator being the last character, consecutive separators and so on. There's no need to have many test cases that doesn't test different things. \$\endgroup\$ May 12, 2018 at 16:11
  • \$\begingroup\$ You're missing a delimiter in the last test case - there should be a ! there. I would edit it myself, but there's not enough characters for me to do it. \$\endgroup\$
    – ollien
    May 13, 2018 at 13:11
  • 1
    \$\begingroup\$ I've downvoted this due to the multiple changes to the spec. On a sidenote, you need to make mention a lot sooner than the last test case that the string may contain 2 or more consecutive "separators" and that we are not guaranteed that a letter will always follow a "separator". \$\endgroup\$
    – Shaggy
    May 13, 2018 at 15:55
  • 2
    \$\begingroup\$ I looked it up: Stewie didn't suggest any test cases, but he asked whether the first or last character could be a separator and whether there could be consecutive separators. In the future, please consider using the sandbox to get all these details sorted out before going live. It's frustrating to get your answer invalidated because of changes in the specification. The most surprising of all is the restriction to take the character as input, even if the program doesn't need it. That makes no sense at all. \$\endgroup\$
    – Dennis
    May 13, 2018 at 16:22
  • 1
    \$\begingroup\$ Can we have a test-case with separator ., I can imagine some string splitting functions struggling with that one. \$\endgroup\$
    – JAD
    May 14, 2018 at 8:15

31 Answers 31

7
\$\begingroup\$

Python 3, 63 bytes

lambda s,c:''.join(map(min,s,s[0]+s.title()[1:])).replace(c,'')

Try it online!

\$\endgroup\$
5
\$\begingroup\$

C (gcc), 61 53 55 bytes

-8 bytes thanks to Dennis!

f(s,c)char*s;{for(;*s;putchar(*s++))if(*s==c)*++s&=95;}

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ Suggest *s==c?*++s&=95:0; instead of if(*s==c)*++s&=95; \$\endgroup\$
    – ceilingcat
    Dec 7, 2018 at 20:44
5
\$\begingroup\$

JavaScript (ES6), 58 56 bytes

Saved 2 bytes thanks to @l4m2 / @Downgoat

Takes input in currying syntax (s)(c).

s=>c=>s.replace(u=/./g,x=>u=x==c?'':u?x:x.toUpperCase())

Try it online!

Commented

s => c =>                  // given s and c
  s.replace(u = /./g, x => // initialize u to a RegExp; replace each character x in s with,
    u =                    // and update u to:
      x == c ?             //   if x is the separator:
        ''                 //     an empty string
      :                    //   else:
        u ?                //     if u is not an empty string:
          x                //       x unchanged
        :                  //     else:
          x.toUpperCase()  //       x capitalized
  )                        // end of replace()
\$\endgroup\$
11
  • \$\begingroup\$ consolation 56 bytes for s=>c=>s.replace(RegExp(c+".","g"),m=>m[1].toUpperCase()), since it doesn't work for special regex characters \$\endgroup\$ May 13, 2018 at 4:20
  • \$\begingroup\$ 50 bytes. Or 47 if you don't bother taking the second input, which is irrelevant. \$\endgroup\$
    – Shaggy
    May 13, 2018 at 15:06
  • 1
    \$\begingroup\$ @Shaggy Thanks! I've added it as a separate version, since the new rules are quite different from the original ones. \$\endgroup\$
    – Arnauld
    May 13, 2018 at 15:20
  • 1
    \$\begingroup\$ fail !prob!!lem!s!Olved!! \$\endgroup\$
    – l4m2
    May 13, 2018 at 15:32
  • \$\begingroup\$ @l4m2, that's a new test case which changes the spec yet again. A + before the . in the RegEx will get around it. \$\endgroup\$
    – Shaggy
    May 13, 2018 at 15:53
3
\$\begingroup\$

APL (Dyalog Classic), 22 bytes

{⍵~⍨1(819⌶@(⍵=¯1⌽⊢))⍺}

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Why Dyalog Classic for this answer? \$\endgroup\$
    – Razetime
    Sep 11, 2020 at 3:04
  • 1
    \$\begingroup\$ at the time, unicode dyalog answers were required to link to a single-byte encoding (or else scoring would default to utf8), so it was easier to post in classic dyalog \$\endgroup\$
    – ngn
    Sep 11, 2020 at 11:38
3
\$\begingroup\$

Perl 6 -p, 19 bytes

s:g[<:!L>(.)]=$0.uc

Try it online!

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

sed 4.2.2 (-r), 21

s/[^a-z]+(.)?/\u\1/gi

I tried \W instead of [^a-z], but unfortunately that doesn't match _.

Try it online!

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

Jelly, 8 bytes

Œt⁸1¦«⁸ḟ

Try it online!

How it works

Œt⁸1¦«⁸ḟ  Main link. Left argument: s (string). Right argument: c (character).

Œt        Title case; capitalize the first character of each word.
  ⁸1¦     Replace the first character of the result with the first character of s.
     «⁸   Take the character-wise minimum of the result and s.
          Note that uppercase letters have lower code points than lowercase ones.
       ḟ  Filterfalse; remove all occurrences of c.
\$\endgroup\$
3
\$\begingroup\$

Octave, 83, 66, 64 bytes

Saved 2 bytes thanks to Luis Mendo. upper instead of toupper.

@(s,c,k=upper(s(i=find(s==c)+1)))[strsplit({s(i)=k,s}{2},c){:}];

Try it online!

Wow, that's probably the messiest piece of Octave-code I've ever written! This uses two of the tricks posted in this tips question, namely Argument list, and cell arrays.

Explanation:

Argument list input:

@(s,c,k        % An anonymous function that may take three input variables, s, c, k
               % where the third argument has the default value:
 k=upper(s(i=find(s==c)+1))

k is here the first character in s after each separator c, converted to upper case. The index of each capitalized character is stored in i.

Cell array body:

We create a cell array with two elements, one were we say that all i'th characters should be substituted by its counterpart in k, and the other one with s, that is now already updated. We index this using {2} so that we only get the whole, modified string back. This is fed to strsplit, which splits it into cells at the separator character. We convert it to a comma-separated list using {:}, and concatenates it back to a string using square brackets [].

Apologies if that didn't make any sense to you... It barely makes sense to me :P

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

Retina 0.8.2, 20 bytes

T`lLp`LL_`[\W\d_]+.?

Try it online! Takes the string only, separator optional. All non-alphabetic characters are deleted but any following alphabetic character is uppercased. Previous 34-byte version accepted arbitrary input:

T`l`L`(?=.*(.)$)\1+.
(?=.*(.)$)\1

Try it online! Link includes test suite. Assumes the input consists of the string and character concatenated together. Explanation: The first stage transliterates all characters immediately following occurrences of the end character from lower to upper case and the second stage then deletes all occurrences of the end character.

For both solutions, using a right-to-left match instead of a + also works.

\$\endgroup\$
1
  • \$\begingroup\$ Since the input is guaranteed to only contain alphabetic characters and the separator, you can use [^a-z] instead of the lookaheads Try it online! \$\endgroup\$
    – user41805
    May 13, 2018 at 9:23
2
\$\begingroup\$

Röda, 57 54 bytes

-3 bytes thanks to Cows quack

{(_/`\Q$_`)|{pull;[upperCase(_[:1]),_1[1:]]if[#_1>0]}}

Try it online!

Explanation:

{
  (_/`\Q$_`)| /* Pull two strings and split the first with the second */
  {
    pull;                /* Pull one string and print it */
                         /* For each string _1 in the stream: */
                         /*   If _1 is not empty: */
    [                    /*     Print: */
      upperCase(_[:1]),  /*       The first character capitalized */
      _1[1:]             /*       The rest of characters */
    ]if[#_1>0]           /*   End if */
  }
}
\$\endgroup\$
1
  • \$\begingroup\$ You can leave out the \E from the regex, and _[0:1]_[:1] \$\endgroup\$
    – user41805
    May 12, 2018 at 17:49
2
\$\begingroup\$

V, 6 7 bytes

1 byte saved by not using argument

ÓÁˆ/õ±

Try it online!

The program takes in the text as input and the char as an argument.

Hexdump:

00000000: d3c1 882f f5b1                           .../..

This is a simple substitution. Uncompressed, it looks like the following

:s/\A(.)/\u\1/g

Perform a global substitution in which \A, a non-alphabetic character, followed by a character (.) is replaced with uppercased \u first capture group \1

\$\endgroup\$
2
  • \$\begingroup\$ Doesn't work for input where c is a special regex character \$\endgroup\$ May 13, 2018 at 4:24
  • 1
    \$\begingroup\$ @ConorO'Brien Fixed, and thanks to this I found a shorter solution :D \$\endgroup\$
    – user41805
    May 13, 2018 at 9:06
2
\$\begingroup\$

Scala, 83 bytes

def f(s:String)={val w=s.split("[^a-zA-Z]");w(0)+w.tail.map(_.capitalize).mkString}

Try it online!

Explanation:

def f(s: String) = {                        // takes a String "s" as input
  val w = s.split("[^a-zA-Z]");             // split on non-alpha chars
  w(0) + w.tail.map(_.capitalize).mkString  // upper case first letter of all words except first one and join array into a String
}                                           //
\$\endgroup\$
0
1
\$\begingroup\$

Red, 87 bytes

func[s c][b: split s c prin b/1 foreach w next b[if w <>""[w/1: uppercase w/1 prin w]]]

Try it online!

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

05AB1E, 9 bytes

¡ćsvyćusJ

Try it online!

Explanation

¡           # split the string on the char
 ć          # extract the head of the resulting list
  s         # swap the head to the bottom of the stack
   vy       # for each string y in the rest of the list
     ću     # extract the head and capitalize it
       s    # swap it below the rest of the string
        J   # join everything to one string
\$\endgroup\$
0
1
\$\begingroup\$

PHP, 91 83 bytes

$a=explode($argv[2],$argv[1]);echo array_shift($a);foreach($a as$i)echo ucfirst($i);

Run with -r. Was 2 bytes shorter using split instead of explode, but ^ test fails due to regex.

-8 thanks to Med

\$\endgroup\$
2
  • 1
    \$\begingroup\$ You can remove {and } from the for loop, it will only treat the next statement as body of the condition. \$\endgroup\$
    – Med
    May 14, 2018 at 10:01
  • 1
    \$\begingroup\$ You can even do the echo inside the loop: $a=explode($argv[2],$argv[1]);echo array_shift($a);foreach($a as$i)echo ucfirst($i); \$\endgroup\$
    – Med
    May 14, 2018 at 10:15
1
\$\begingroup\$

LaTeX, 97 bytes

The function

\def~#1#2{{\seq_set_split:Nnn~{#2}{#1}\seq_map_function:NN~"}}\def"{\let"\text_titlecase_first:n}

Complete document with test cases

\documentclass[preview,border=3.14]{standalone}

\ExplSyntaxOn
\catcode`\~13
\catcode`\"13

\def~#1#2{{\seq_set_split:Nnn~{#2}{#1}\seq_map_function:NN~"}}\def"{\let"\text_titlecase_first:n}

\ExplSyntaxOff

\begin{document}
~{Hello_world}_

~{me,no,like},

~{you-got-it}-

~{Am^I^clear}^

~{go!full!caps}!

~{weird&but&tRue}&

~{ProbleM1fixed1no}1

~{!prob!!lem!s!Olved!!}!
\end{document}

Results (in PDF)

enter image description here

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

R, 64 bytes

Pure regular expression solution using https://www.regular-expressions.info/replacecase.html. Unfortunately separators can be underscores so I couldn't use \w to capture letters. Improved version taking advantage of gsub's ignore.case parameter to save on [a-zA-Z]. Correction thanks to https://codegolf.stackexchange.com/users/95126/dominic-van-essen, who has a 25% shorter solution in the comments.

function(s,c)gsub('[^a-z]([a-z]?)([a-z]*)','\\U\\1\\E\\2',s,T,T)

Try it online!

https://codegolf.stackexchange.com/users/95126/dominic-van-essen 's solution, with an extra character removed (by using ? for optional):

R, 47 bytes

function(s,c)gsub("[^a-z]+(.)?","\\U\\1",s,T,T)

Try it online!

\$\endgroup\$
7
  • \$\begingroup\$ Your TIO link shows that this doesn't work for the last test case... \$\endgroup\$ Sep 11, 2020 at 8:47
  • \$\begingroup\$ ...but you can fix it for 48 bytes... \$\endgroup\$ Sep 11, 2020 at 8:55
  • 1
    \$\begingroup\$ Would you like to add your (growing number of) R golfs to the Language of the month page (edit the first 'answer' there...). It's nice for other R-golfers (and would-be-R-golfers) to be able to easily find examples to learn from... \$\endgroup\$ Sep 11, 2020 at 9:00
  • 1
    \$\begingroup\$ Thanks for the correction @DominicvanEssen, much better than mine! I'm amused that not using the argument is still better! \$\endgroup\$
    – Cong Chen
    Sep 11, 2020 at 9:01
  • 1
    \$\begingroup\$ Well done on shaving another byte off my attempt! By the way, if you're embedding links, you can make your text more readable by using a link-label in square-brackets [ ] immediately followed by the link itself in parentheses ( ). \$\endgroup\$ Sep 11, 2020 at 10:07
1
\$\begingroup\$

Pinecone, 314 bytes

s:String.input;p:String.input;k:IntArray:s.len;k.set:0,-1;o:"";n:1;i:0|i<s.len|i:i+1@((s.sub:i,i+1)=p?(k.set:n,i;n:n+1))k.set:n,s.len;i:1|i<n+1|i:i+1@(x:k.get:i-1;y:k.get:i;x:x+1;j:s.sub:x,y;e:1|e<256|e:e+1@((j.sub:0,1)=e.ascii?(e<96?(o:o+(e.ascii)+(j.sub:1,(j.len)))|(o:o+(e-32).ascii+(j.sub:1,(j.len))))))print:o

This was extremely fun....

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

Vyxal, 5 bytes

/ḣǐJṅ

Try it Online!

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

Groovy, 43 bytes, 45 bytes

s.replaceAll(/\$c(.)/){it[1].toUpperCase()}

Try it online. Test suite included excluding the last item as it lacks the separator char c.

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

Go, 138 92 87 bytes

Dropped 46 bytes thanks to @Dennis' title case idea.

func f(s,d string){p:=Split(s,d);Print(p[0]+Replace(Title(Join(p[1:]," "))," ","",-1))}

Try it online!

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

Husk, 10 bytes

ΣΓ·:mΓo:ax

Try it online!

Explanation

ΣΓ·:mΓ(:a)x  -- example inputs: 'x' "abxbcxcdxdex"
          x  -- split on character: ["ab","bc","cd","de"]
 Γ           -- pattern match (x = head) (xs = tail) and do..
  ·:         -- | construct list (x:xs) but with the second argument do..
    m        -- | | map (eg. "bc")
     Γ(  )   -- | | | pattern match on first character
      ( a)   -- | | | | upper-case it
      (: )   -- | | | | and join again
             -- | | | : "Bc"
             -- | | : ["Bc","Cd","De"]
             -- : ["ab","Bc","Cd","De"]
Σ            -- concatenate: "abBcCdDe"
\$\endgroup\$
0
\$\begingroup\$

F# (Mono), 122 bytes

let f(s:string)c=s|>Seq.mapi(fun i x->if i>0&&s.[i-1]=c then Char.ToUpper(x)else x)|>Seq.where((<>)c)|>Seq.toArray|>String

Try it online!

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

Java 10, 141 bytes

s->c->{var r=s.split("\\"+c);var r=a[0],t;for(int i=0;++i<a.length;r+=t.isEmpty()?"":(char)(t.charAt(0)&~32)+t.substring(1))t=a[i];return r;}

Try it online.

Explanation:

s->c->{                    // Method with String and character parameters and String return-type
  var r=s.split("\\"+c);   //  Split String by character (with potential regex char)
  var r=a[0],              //  Result-String, starting at the first item
      t;                   //  Temp-String to reduce bytes
  for(int i=0;++i<a.length;//  Loop in the range [1, length_of_array)
      r+=                  //    After every iteration: append the result-String with:
         t.isEmpty()?      //     If the current item empty:
          ""               //      Append nothing
         :                 //     Else:
          (char)(t.charAt(0)&~32)
                           //      Capitalize the first character
          +t.substring(1)) //     And append the other characters as is
    t=a[i];                //   Set `t` to the current String-item of the array
  return r;}               //  Return the result-String
\$\endgroup\$
0
\$\begingroup\$

R, 87 bytes

g<-function(s,x,z=strsplit(s,x,T)[[1]])cat(z[1],capwords(z[-1]),sep="")
example(chartr)

Try it online!

Uses this trick can can not be properly executed in TIO so I simulated it.

We need the T otherwise one of the test cases fails.

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

Stax, 11 bytes

óKo{cplòüö\

Run and debug it

Explanation

/BsF1:/s^s|dl                 # Full Program, unpacked, Implicit Input
/                             # Split on substrings (Split input with symbol to split on)
 B                            # Remove first element from array. Push the tail of the array, then the removed element.
  s                           # Swap first two elements of stack
   F                          # Start for loop
    1:/                       # Split array at index; push both parts.
       s^s                    # Swap first two elements of stack, capitalize character, swap first two elements 
         |dl                  # Get length of stack, listify that amount (entire stack), implicit output of array

There's a few parts I would really like to fix somehow. I can get it down to about 8 bytes, but it fails on the last test case >.<

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

Ruby -pl, 36 bytes

$_.gsub!(/[^a-z]+(.|$)/i){$1.upcase}

Try it online!

Takes only the string without second argument. Uses the block version of gsub! method because with common gsub! x,y syntax $1 is not readily filled with match data. |$ in regex is necessary for the test case with separator in the end.

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

Python 3, 77 bytes

o=[]
for x in s.split(c): o.append(chr(ord(x[0])-32)+x[1:])
print(''.join(o))

Try it online!

This assumes that the string is ASCII encoded and assumes that s and c are preloaded variables containing the input.

for x in s.split(x)       #loop through items in the string s split by x
    o.append(             #add the following to c
        chr(              #turn the following number into a character
            ord(          #turn the following character into a number
                x[0]      #the first character in string x
            )-32          #subtract 32 from this number
        +x[1:]            #add everything past and including the second character in string x

This solution works on the fact that in ASCII encoding, lowercase letters are positioned 32 entries after capitalised letters

Edit: i just realised that this also capitalises the first character in the string, which it shouldn't. but i'm quite proud of my nonsense, so i'll leave this up if that's allowed

\$\endgroup\$
6
  • \$\begingroup\$ What is s supposed to be ? \$\endgroup\$ Jun 6, 2018 at 9:52
  • \$\begingroup\$ @MuhammadSalman A string s and a character c. \$\endgroup\$ Jun 6, 2018 at 9:53
  • \$\begingroup\$ Lovely, make it work, Go here and see if it works or not : TIO. When it does tell me ? \$\endgroup\$ Jun 6, 2018 at 9:55
  • \$\begingroup\$ oops! i just realised i made a mistake when changing the variable names, c=[] is supposed to be any other variable \$\endgroup\$ Jun 6, 2018 at 9:57
  • \$\begingroup\$ @MuhammadSalman here \$\endgroup\$ Jun 6, 2018 at 10:00
0
\$\begingroup\$

Pip, 23 bytes

Ya^by@0AL(UC@_.@>_M@>y)

might be shorter with regex substitution.

Try it online!

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

Wolfram Language (Mathematica), 45 bytes

""<>MapAt[Capitalize,##~StringSplit~All,2;;]&

Try it online!

\$\endgroup\$

Your Answer

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

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