Don't be impressed by a pattern. Format it to something readable:
[.!?] (?! ['"]? \s | $ )
[.!?]? ['"]? (?= \s | $ )
There are three simple parts. No madness here, this pattern isn't complicated, but
before assuming parts are useless you have to fully understand what they do.
The first part
[^.!?\s] [^.!?\n]* search a character that isn't a white-space or a punctuation mark, and then it consumes greedily all eventual following characters that aren't punctuation marks too or newlines.
Why newlines? This last point may seem surprising but is eventually related to the context: the way the text is formatted. In other words, sentences are perhaps on one line only.
[^.!?\s] is the only thing that isn't optional in the pattern. Note also that since
[^.!?\n]* is greedy, the next character after it can only be a punctuation mark, a newline or the end of the string.
The second part is an optional non-capturing group eventually repeated. Its goal is to accept punctuation marks that don't end the sentence, for instance things like:
3.14, bestcatpics.maowmaow, bad enc?ding.
[.!?] should not be followed by a space or a "closing" quote and a space or the end of the string as the negative lookahead
(?! ['"]? \s | $ ) expresses it.
[^.!?]* will only reach the last position before the next punctuation mark (or the end of the string). Note that this time the newline isn't excluded: it's inconsistent with the first part.
The non-capturing group is repeated until there's no more "fake" punctuation mark.
The third and last part finishes the job consuming the punctuation mark that ends the sentence and the "closing" quote before a white-space or the end of the string. Punctuation mark and quote are optional.
From a technical point of view.
The pattern is well-designed to reduce the backtracking as possible:
(A|B)* is unrolled to
A* (BA*)*, where A is
[^.!?] (with or without
\n) and B is
[.!?] with its lookahead assertion
(?! ['"]? \s | $ ).
( [^.!?] | [.!?] (?! ['"]? \s | $ ) )* is shorter than
[^.!?]* (?: [.!?] (?! ['"]? \s | $ ) [^.!?]* )* (about 9 chars) but is from far less efficient for a backtracking regex engine.
Other good point, all quantifiers are greedy and applied over restricted sets of characters, that is also more efficient than using reluctant quantifiers over permissive character classes (like the dot,
The only thing to deplore is the inconsistency between
[^.!?\n] in the first part and
[^.!?] in the second part. I really doubt there's a good reason behind. Also,
(?=\s|$) is IMO better written like that:
(?!\S) even if it looks less explicit.
const pat = String.raw`
[^.!?\s] [^.!?\n]* # start of the sentence
(?: # "fake" punctuation mark
[.!?] (?! ['"]? \s | $ )
[.!?]? ['"]? (?!\S) # end of the sentence`;
const re = RegExp.compile(pat.replace(/\s+|#.*/g, ''), 'g');
This pattern may be the right solution in the specific context in which it is used. Nevertheless, and under no circumstances can it be considered a viable solution for isolating sentences from a plain text in natural language.
The analysis of natural language (NLP: Natural Language Processing) is a whole part of computing with these own tools like NLTK. While sentence breaking may seem like a basic task, it may require tools such as dictionaries, such as statistics (Machine Learning), and even, who would have thought, regex.