Replace double quotes by quotation marks

后端 未结 3 844
臣服心动
臣服心动 2021-02-19 06:15

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

3条回答
  •  耶瑟儿~
    2021-02-19 06:35

    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.

提交回复
热议问题