g | x | w | all
Bytes Lang Time Link
085Python240524T140835ZJulian F
192Go220923T143057Zbigyihsu
117Python 3220922T051219ZPandu
014Japt220919T142007ZShaggy
001Vyxal220919T134902Zlyxal
019Vim210413T135704ZAaroneou
076C gcc200516T085751ZNoodle9
081Red200518T054539ZGalen Iv
033perl p200516T142627ZAbigail
013Retina200516T102041ZJarmex
019Retina 0.8.2200516T113553ZNeil
101JavaScript Node.js200516T084653ZYaroslav
077Erlang escript200516T002928Zuser9206
067Python 3200516T002520Zdingledo
00305AB1E200516T002027Zlyxal

Python, 85 bytes

(No regex)

(With an improvement suggested by emanresu A)

lambda s,a=0:' '.join([s.replace(' ','').title()[a:(a:=a+len(x))]for x in s.split()])

Attempt This Online!

Here is an 85-byte solution for making the sentence case capitalization in Python. It is diffent from the other Python answers because it does not use regular expressions, but relies on the title function. Here even some difficult cases including the capitalization of the letters with the diacritics - Österreich, for instance, are treated correctly. Also, apparently, no problems with the combinations of several punctuation symbols (.!?) and, particularly, numbers.

How this works.

As mentioned before, the solution makes use of the function title, which converts the first letter of each word to the uppercase and the rest to the lowercase. We don't want each word, but only the first one, so, let's convert the sentence to a single word by removing the spaces. Once the spaces are removed, the title() is applied and then the spaces are reintroduced again (a verbose part, unfortunately!) - their positions are taken from the original sentence.

Go, 192 bytes

import(y"bytes";."regexp";u"unicode")
type k=[]byte
func f(s k)k{return MustCompile(`\w[\w ]+`).ReplaceAllFunc(s,func(b k)k{return append(k{byte(u.ToUpper(rune(b[0])))},y.ToLower(b[1:])...)})}

A port of @dingledooper's answer.

Attempt This Online!

Python 3, 117 bytes

import re
f=lambda s:''.join(map(lambda p:re.sub(r'[a-z]',lambda m:m[0].upper(),p.lower(),1),re.split(r'([.?!])',s)))

Try it online!

For some reason, I made a solution that handles a few extra test cases that OP may or may not have cared about :) This is much longer than the current shortest Python solution, but I'd be sad to just throw this code away, so here it is!

Extra test cases:

"a.b.c" //  "A.B.C"
(no space after punctuation)

"hello.  goodbye" // "Hello.  Goodbye"
(more than one space after punctuation)

"I'M A ROBOT" // "I'm a robot"
(punctuation other than sentence terminator)

Commented solution:

f = (
  lambda string:
    ''.join(map(

      # Capitalize first letter in part
      lambda part: re.sub(
        r'[a-z]',
        lambda match: match[0].upper(),
        part.lower(),
        1
      ),

      # Split on punctuation
      re.split(r'([.?!])',string)

    ))
)

Japt, 14 bytes

v r"^.|%W ."_u

Try it

Vyxal, 1 byte

¡

Try it Online!

"Nothing like a good old built-in answer!" I suppose not younger lyxal, I suppose not.

Alternatively, a non-trivial 24 byte answer:

`([.?!])`ṡλ⇩⌈:Th~iǐȦṄ;Ẇṅ

Try it Online!

Explained

`([.?!])`ṡλ⇩⌈:Th~iǐȦṄ;Ẇṅ
`       `ṡ               # Split the input on the regex "[.?!]", keeping the thing that causes splits (wrapping something in `()` when regex splitting keeps it in the split list)
          λ          ;Ẇ  # To each second item of that list (guaranteed to not be punctuation), starting at index 0:
           ⇩⌈             #   Split the lowercase version of the string on spaces
             :Th~i        #   Get the first word by getting the first truthy index in the splitted string (because it may contain `""`s) and get the item at that index
                  ǐȦṄ     #   Replace the word at that index with a title-cased version of the string, and join the list on spaces.
                      ṅ   # Join the result on nothing

Vim, 20 19 bytes

Saved 1 byte by using ~ to toggle casing instead of vU.

v$uqq~/[.!?]
w@qq@q

Try it online!

Explanation:

v$u                 # Selects whole line and changes it to lowercase
   qq               # Starts recording macro q
     ~              # Toggles uppercase on current character
      /[.!?]        # Jumps to next . ! or ?
            w       # Jumps to next non-whitespace character
             @q     # Calls macro q recursively
               q@q  # Ends macro q and calls it

C (gcc), 80 \$\cdots\$ 87 76 bytes

Added 13 bytes to fix a bug kindly pointed out by Abigail.

c;b;f(char*s){for(b=1;c=*s;b|=ispunct(c))*s++=isalpha(c)?b?b=0,c&95:c|32:c;}

Try it online!

How

Capitalises the first letter and every letter after a punctuation mark. Every other letter is converted to lower case. Simply prints everything else.

Red, 81 bytes

func[s][parse lowercase s[any[any" "p: change skip(p/1 - 32)thru["."|"!"|"?"]]]s]

Try it online!

perl -p, 33 bytes

$_=lc=~s/(^|\pP)\s*\K\pL/uc$&/erg

Try it online!

This lowercases the string, then upper cases any letter following either the beginning of the string, or after a punctuation character (skipping any whitespace in between). This does turn a string "foo, bar, baz" into "Foo, Bar, Baz", but that's how I read the requirement about all punctuation.

Retina, 13 bytes

.+
$T
\b .
$L

Try it online!

Explanation

General approach is to convert every word to title-case, then un-convert the words that shouldn't have been converted

.+ Matches the entire string, $T converts it to title case (every word lowercase with an uppercase first character

\b . - \b Matches the position between a word-character and a non-word character (i.e. the end of a word without a full stop) followed by a space and any other character .

$L converts this to lowercase

Retina 0.8.2, 19 bytes

T`L`l
T`l`L`^.|\W .

Try it online! Link includes test cases. Explanation:

T`L`l

Lowercase everything.

T`l`L`^.|\W .

Uppercase the first character and any character that follows a non-word character and a space. It might not be the world's best heuristic but it works on the test case.

JavaScript (Node.js), 101 bytes

s=>(s.reduce((a,c)=>c=='.'?(r+=c,'Upp'):c>' '?(r+=c['to'+a+'erCase'](),'Low'):(r+=c,a),'Upp',r=''),r)

Try it online!

Erlang (escript), 77 bytes

If non-periods are allowed... well, that greatly golfs my program!

g(H)->[string:titlecase(string:lowercase(I))||I<-re:split(H,"(\\W[\\W ]+)")].

Try it online!

Explanation

g(H)->                      % Define a function.

re:split(H,"(\\W[\\W ]+)")  % Split the operand on "sentences", keeping the items reserved for splitting.

                            % I.e. none of the items from the string is missing after the split

||I<-   ]                   % For every item in a sentence,
[string:titlecase(string:lowercase(I))

                            %     Title case the sentence.
.                           % End the function.                            

Python 3, 67 bytes

-7 bytes thanks to Surculose Sputum

If other punctuation like ! or ? are allowed.

lambda s:re.sub(r'\w[\w ]+',lambda x:x[0].capitalize(),s)
import re

Try it online!


Python 2, 53 bytes

lambda s:'. '.join(map(str.capitalize,s.split('. ')))

Try it online!

05AB1E, 3 bytes

l.ª

Try it online!

Nothing like a good old built-in answer! This converts the string to lowercase and then performs sentence case.