I am looking for a way to replace the quotes with “corrected” quotations marks in an user input.
The idea
Here is a snippet briefly showing the
I got a solution that finally fits all my needs.
I admit it is a lot more complicated than T.J.'s one, which can be perfect for simple cases.
Remember, my main problem was the impossilibity to use \b
because of the accented characters.
I was able to get rid of that issue by using the solution from this topic:
Remove accents/diacritics in a string in JavaScript
After that, I used a modified function highly inspired from the answer here…
How do I replace a character at a particular index in JavaScript?
… and had a very hard time, playing a lot with RegEx to finally get to that solution:
var str_orig = `· I'm "happy" ! Ça y est, j'ai "osé", et mon "âme sœur" était au rendez-vous…
· The sign says: "Some text "some text" some text." and "Note the space here !"
⋅ "Inc"or"rect" quo"tes should " not be replaced.
· I said: "If it works on 'singles' too, I'd love it even more!"
word1" word2"
word1 word2"
"word1 word2
"word1" word2
"word1" word2"
"word1 word2"`;
// Thanks, exactly what I needed!
var str_norm = str_orig.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
// Thanks for inspiration
String.prototype.replaceQuoteAt = function(index, shift) {
const replacers = "“‘”’";
var offset = 1 * (this[index] == "'") + 2 * (shift);
return this.substr(0, index) + replacers[offset] + this.substr(index + 1);
}
// Opening quote: not after a boundary, not before a space or at the end
var re_start = /(?!\b)["'](?!(\s|$))/gi;
while ((match = re_start.exec(str_norm)) != null) {
str_orig = str_orig.replaceQuoteAt(match.index, false);
}
// Closing quote: not at the beginning or after a space, not before a boundary
var re_end = /(?
And below is a snippet of a working example with a textarea
.
I've just created a function of the code of the first snippet, and I'm using a substring around the caret position to filter the calling of the function (that avoids calling it on every character input):
String.prototype.replaceQuoteAt = function(index, offset) {
const replacers = "“‘”’";
var i = 2 * (offset) + 1 * (this[index] == "'");
return this.substr(0, index) + replacers[i] + this.substr(index + 1);
}
function replaceQuotes(str) {
var str_norm = str.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
var re_quote_start = /(?!\b)["'](?!(\s|$))/gi;
while ((match = re_quote_start.exec(str_norm)) != null) {
str = str.replaceQuoteAt(match.index, false);
}
var re_quote_end = /(?
#myInput {
width: 90%;
height: 100px;
}
It seems to work with all I can imagine right now.
The function correctly replaces the quotes when:
⋅ typing regularly,
⋅ adding quotes after we typed the text,
⋅ pasting text.
It replaces both the double and the singles quotes.
Anyway, as I am not a RegEx expert at all, please feel free to comment if you notice a behaviour that may be unwanted, or a way to improve the expressions.