If you ignore the content-dependent problem, then it is possible to do replacement with PCRE regex. (It is possible to patch it on case-by-case basis, if the $ which doesn't denote the portion to preserve \ has a non-ambiguous form).
Assumes that $ always starts and ends a non-replacement region, except for the case of the odd last $ in the string.
Pattern (the first line is RAW regex, the second line is quoted string literal):
\G((?:[^$\\]|\$[^$]*+\$|\$(?![^$]*+\$))*+)\\
"\\G((?:[^$\\\\]|\\$[^$]*+\\$|\\$(?![^$]*+\\$))*+)\\\\"
Replace string:
\1"
"\\1\""
DEMO 1
DEMO 2
Explanation
The idea is to find the next \ in the string that is not contained within 2 $. This is achieved by make sure the match always starts from where the last match left off \G, to ensure we don't skip over any literal $ and match the \ inside.
There are 3 forms of sequences that we don't replace:
- Is NOT either literal
$ or literal \: [^$\\]
- Any text in between 2
$ (this doesn't take into account escaping mechanism, if any): \$[^$]*+\$
- Allow replacement of
\ after the odd last $: \$(?![^$]*+\$)
So we just march through any combination of the 3 forms of sequences above, and match the nearest \ for replacement.
Same assumption as above, except that $<digit> will not start a non-replacement region.
This will work even with this kind of string:
I have $50 to \spend\. I just $\bar$ remembered that I have another $30 dollars $\left$ from my last \paycheck\. Lone $ \at the end\
Pattern:
\G((?:[^$\\]|\$\d|\$(?![^$]*\$)|\$[^$]*+\$)*+)\\
"\\G((?:[^$\\\\]|\\$\\d|\\$(?![^$]*\\$)|\\$[^$]*+\\$)*+)\\\\"
DEMO
\$\d is added in front of the \$[^$]*+\$ in alternation to make the engine check for that case first.