Alex
Alex

Reputation: 1606

Dumb quotes into smart quotes Javascript issue

I have some JavaScript code that transforms dumb quotes into smart quotes in a contenteditable.

The problem appears when you add dumb quotes at the beginning of the line they only close. For example you get this:

”dumb quotes” instead of “dumb quotes”

Try out the demo: http://jsfiddle.net/7rcF2/

The code I’m using:

function replace(a) {
    a = a.replace(/(^|[-\u2014\s(\["])'/g, "$1\u2018");       // opening singles
    a = a.replace(/'/g, "\u2019");                            // closing singles & apostrophes
    a = a.replace(/(^|[-\u2014/\[(\u2018\s])"/g, "$1\u201c"); // opening doubles
    a = a.replace(/"/g, "\u201d");                            // closing doubles
    a = a.replace(/--/g, "\u2014");                           // em-dashes
return a  };

Any ideas? Thanks!

P.S. I suck at regular expressions…

Upvotes: 0

Views: 3098

Answers (2)

aboutaaron
aboutaaron

Reputation: 5389

If you want everything done client side, you can use smartquotes.js library to convert all dumb quotes on the page to smart quotes. Alternatively, you can use the regex from the library itself.

Here's an implementation from an old version of the code:

function smartquotesString(str) {
  return str
  .replace(/'''/g, '\u2034')                                                   // triple prime
  .replace(/(\W|^)"(\S)/g, '$1\u201c$2')                                       // beginning "
  .replace(/(\u201c[^"]*)"([^"]*$|[^\u201c"]*\u201c)/g, '$1\u201d$2')          // ending "
  .replace(/([^0-9])"/g,'$1\u201d')                                            // remaining " at end of word
  .replace(/''/g, '\u2033')                                                    // double prime
  .replace(/(\W|^)'(\S)/g, '$1\u2018$2')                                       // beginning '
  .replace(/([a-z])'([a-z])/ig, '$1\u2019$2')                                  // conjunction's possession
  .replace(/((\u2018[^']*)|[a-z])'([^0-9]|$)/ig, '$1\u2019$3')                 // ending '
  .replace(/(\u2018)([0-9]{2}[^\u2019]*)(\u2018([^0-9]|$)|$|\u2019[a-z])/ig, '\u2019$2$3')     // abbrev. years like '93
  .replace(/(\B|^)\u2018(?=([^\u2019]*\u2019\b)*([^\u2019\u2018]*\W[\u2019\u2018]\b|[^\u2019\u2018]*$))/ig, '$1\u2019') // backwards apostrophe
  .replace(/'/g, '\u2032');
};

Upvotes: 1

Cerbrus
Cerbrus

Reputation: 72957

Try this:

var a = '"dumb quotes" instead -- of "dumb quotes", fixed it\'s';

 a = a.replace(/'\b/g, "\u2018")     // Opening singles
      .replace(/\b'/g, "\u2019")     // Closing singles
      .replace(/"\b/g, "\u201c")     // Opening doubles
      .replace(/\b"/g, "\u201d")     // Closing doubles
      .replace(/--/g,  "\u2014")     // em-dashes
      .replace(/\b\u2018\b/g,  "'"); // And things like "it's" back to normal.
// Note the missing `;` in these lines. I'm chaining the `.replace()` functions.  

Output:

'“dumb quotes” instead — of “dumb quotes”, fixed it's'

Basically, you were looking for the word boundary: \b

Here's an updated fiddle

Upvotes: 7

Related Questions