EDIT: Rewritten to cover more cases of edges.
It can be done, but it is a bit complicated.
result = subject.match(/(?:(?=(?:(?:\\.|"(?:\\.|[^"\\])*"|[^\\'"])*'(?:\\.|"(?:\\.|[^"'\\])*"|[^\\'])*')*(?:\\.|"(?:\\.|[^"\\])*"|[^\\'])*$)(?=(?:(?:\\.|'(?:\\.|[^'\\])*'|[^\\'"])*"(?:\\.|'(?:\\.|[^'"\\])*'|[^\\"])*")*(?:\\.|'(?:\\.|[^'\\])*'|[^\\"])*$)(?:\\.|[^\\'"]))+/g);
will return
, he said. , she replied. , he reminded her. ,
from this line (added lines and added quotes for clarity):
"Hello", he said. "What up, \"doc\"?", she replied. 'I need a 12" crash cymbal', he reminded her. "2\" by 4 inches", 'Back\"\'slashes \\ are OK!'
Explanation: (sort of, this is a bit legible)
Regular Expression Break:
(?: (?= # Assert even number of (relevant) single quotes, looking ahead: (?: (?:\\.|"(?:\\.|[^"\\])*"|[^\\'"])* ' (?:\\.|"(?:\\.|[^"'\\])*"|[^\\'])* ' )* (?:\\.|"(?:\\.|[^"\\])*"|[^\\'])* $ ) (?= # Assert even number of (relevant) double quotes, looking ahead: (?: (?:\\.|'(?:\\.|[^'\\])*'|[^\\'"])* " (?:\\.|'(?:\\.|[^'"\\])*'|[^\\"])* " )* (?:\\.|'(?:\\.|[^'\\])*'|[^\\"])* $ ) (?:\\.|[^\\'"]) # Match text between quoted sections )+
Firstly, you can see that there are two similar parts. Both of these statements look like there is an even number of single / double quotes ahead of the line, not including screened quotes and quotes of the opposite kind. I will show it with a separate quote:
(?= # Assert that the following can be matched: (?: # Match this group: (?: # Match either: \\. # an escaped character | # or "(?:\\.|[^"\\])*" # a double-quoted string | # or [^\\'"] # any character except backslashes or quotes )* # any number of times. ' # Then match a single quote (?:\\.|"(?:\\.|[^"'\\])*"|[^\\'])*' # Repeat once to ensure even number, # (but don't allow single quotes within nested double-quoted strings) )* # Repeat any number of times including zero (?:\\.|"(?:\\.|[^"\\])*"|[^\\'])* # Then match the same until... $ # ... end of string. ) # End of lookahead assertion.
Some double quotes work the same way.
Then, at each position in the line where these two statements are successful, the next part of the regular expression actually tries to match something:
(?: # Match either \\. # an escaped character | # or [^\\'"] # any character except backslash, single or double quote ) # End of non-capturing group
Everything is repeated one or more times, how many times. The /g modifier ensures that we get all matches in the string.
Take a look in action here at RegExr .