-
-
Save getify/3667624 to your computer and use it in GitHub Desktop.
// NOTE: only escapes a " if it's not already escaped | |
function escapeDoubleQuotes(str) { | |
return str.replace(/\\([\s\S])|(")/g,"\\$1$2"); // thanks @slevithan! | |
} | |
escapeDoubleQuotes(`ab`); // ab => ab (nothing escaped) | |
escapeDoubleQuotes(`a"b`); // a"b => a\"b | |
escapeDoubleQuotes(`a\\"b`); // a\"b => a\"b (nothing escaped) | |
escapeDoubleQuotes(`a\\\\"b`); // a\\"b => a\\\"b | |
escapeDoubleQuotes(`a\\\\\\"b`); // a\\\"b => a\\\"b (nothing escaped) | |
escapeDoubleQuotes(`a"b"c`); // a"b"c => a\"b\"c | |
escapeDoubleQuotes(`a""b`); // a""b => a\"\"b | |
escapeDoubleQuotes(`""`); // "" => \"\" | |
// don't unnecessarily escape: | |
escapeDoubleQuotes(escapeDoubleQuotes(escapeDoubleQuotes(`a"b`))); // a"b => a\"b |
@mathiasbynens i only want to escape a " if it's not already escaped.
This is cleaner, more readable/obvious (IMO, and more efficient: str.replace(/\\([\s\S])|(")/, "\\$1$2")
.
Oops, need to add the /g
flag to that, of course.
@slevithan yeah, i think yours actually works globally, where mine does not. mine fails on """", but yours works. O_o. thanks! :)
entirely based on missing group(s) ... nice one!
@slevithan for posterity sake, can you, in this thread, briefly explain how that regex works? I only sorta get it, having trouble wrapping my brain around it.
however ... is this expected? '\"'.replace(/([\s\S])|(")/, "$1$2") === '"'
the regexp works that if encountered anything with a \ before nothing happen, the second match will be empty, the first one will be after the \ in the replacement so .... (escaped)|(") will match (escaped) ? will put $1 and after an empty $2 while if the char is not escaped, after the "|" (or) the escaping is placed and match $1 will be empty ... (($1)|($2)) => $1$2 ... got it? I am notsure it works with my last test thought ...
let me try again semantically ... that regexp says:
is there an escaped (something) ? escape(something) : is the char a " ? escape(") ... the replace escapes in any case but only (soemthing) OR (quote) are actually placed there: about empty, ignored, matches ... maybe better ...
@WebReflection, the line should be this:
'\\"'.replace(/\\([\s\S])|(")/g, "\\$1$2") === '\"'
In which case the result is false
, which is both expected and correct, due to JavaScript string escaping rules.
@getify, the regex works by matching one of two alternatives:
- A backslash followed by any character (
[\s\S]
is used instead of a dot so that escaped newlines also count), or... - A double quote character, on its own.
If the first alternative matches, the matched string will always start with a backslash, and the match length is always 2. The escaped character at position 2 (not including the preceding backslash at position 1) is captured to backreference 1. In this case, capturing group 2 (surrounding the bare double-quote) did not participate. Because all escaped characters are matched this way (including escaped double quotes and escaped backslashes), that leaves us free to cleanly deal with the second regex alternative...
If a double quote is matched and stored in backreference 2, the match length is 1, and capturing group 1 (within the first regex alternative) did not participate. That also means that the double quote character is definitely unescaped, since escaped characters (including escaped double quotes) are always matched by the first regex alternative.
So at this point we know that all matches are either an escaped character and its preceding backslash, or an unescaped double quote. Either way, we want the character to be replaced by an escaped version of itself. The only concern is that we don't want to double-escape any characters that were already escaped and that were therefore matched by the first regex alternative. This ends up being easy to deal with, though, since we can simply exclude the escaping backslash that we matched using the first regex alternative from capturing group 1. That means that one of backreference 1 or 2 is always a single character that needs to be (or remain) escaped, and the other is always a nonparticipating group (which would be returned as undefined
by e.g. regexp.exec
, but which is an empty string when used in a replacement string). Therefore, by always including a literal backslash as the first character in the replacement string, we always get the correct output: an escaping backslash followed by the character it escapes.
@slevithan that was actually a typo, I meant '"'.replace(/([\s\S])|(")/g, "$1$2") === '"' is this correct?
actually is not a typo ... github keeps replacing stuff ... '\"'.replace(/([\s\S])|(")/g, "$1$2") === '\"' is this correct?
@WebReflection, you're still misquoting both the regex and the replacement string. To mark text as code in GitHub comments, put it between grave accent characters.
@getify, for the record, my solution can easily be adapted for other characters that need to be escaped, by simply changing the character or list of characters matched within capturing group 2. E.g., to escape unescaped letters:
str.replace(/\\([\s\S])|([a-z])/ig, "\\$1$2")
Wow, thanks for that wonderful explanation, @slevithan. That rocks!
@slevithan correct so ... '\\"'.replace(/\\([\s\S])|(")/, "\$1$2") === '\\"'
is this expected?
uhm .... '\\"'.replace(/\\([\s\S])|(")/g,"\\$1$2") === '\\"'
@WebReflection, you're still misquoting both the regex and the replacement string. To mark text as code in GitHub comments, put it between grave accent characters.
@getify, for the record, my solution can easily be adapted for other characters that need to be escaped, by simply changing the character or list of characters matched within capturing group 2. E.g., to escape unescaped letters:
str.replace(/\\([\s\S])|([a-z])/ig, "\\$1$2")
thanks for explanation, so we could use the same regex to escape any character or group of character, I used for single and double quotes escape.
str.replace(/\([\s\S])|(['"])/ig, "\$1$2")
Thanks for sharing @getify
However, If the escaped string would be injected into HTML markup, you need the following version of the function:
function encodeHTML(s) {
return s.split('&').join('&').split('<').join('<').split('"').join('"').split("'").join(''');
}
Source: Are single/double quotes allowed inside HTML attribute values? - Stack Overflow
Thanks this worked !!!
THanks this is a good one
When you need to use both single and double quotes in the string you can use the following solutions to escape the quotes:
- " becomes "
- ' becomes '
Keep in mind that you will never need to escape more than the following five special characters:
- & becomes &
- < becomes <
- becomes >
- " becomes "
- ' becomes '
Once you have these escaped you should never have an issue with broken values in HTML again.
Reference: https://jamilhallal.blogspot.com/2022/04/javascript-escape-quotes.html
Wait… Why not just
str.replace(/\x22/g, '\\\x22')
?