0

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…

Alex
  • 1,576
  • 3
  • 17
  • 35
  • Looks like this was taken from https://leancrew.com/all-this/2010/11/smart-quotes-in-javascript/ – Dan May 08 '20 at 22:31

2 Answers2

7

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

Cerbrus
  • 70,800
  • 18
  • 132
  • 147
  • This isn't a very good solution at all. It converts apostrophes in things like "it's" as well. – Fake Name Dec 23 '13 at 01:58
  • It's worth noting that I'm using the actionscript regex library, which apparently has a (possibly) crap implementation of `\b`. – Fake Name Dec 23 '13 at 02:18
  • @FakeName, `it's` is incorrect punctuation. @Cerbrus was correct to convert them to `it’s` — see http://practicaltypography.com/straight-and-curly-quotes.html – Kevin Jantzer Jul 28 '14 at 17:07
  • @KevinJantzer - It's not *incorrect*, using curly quotes just makes it look a little nicer. – Fake Name Jul 29 '14 at 02:46
  • @FakeName, right, but your comment said "This isn't a very good solution at all." It if makes it look "nicer" how is it not a good solution? – Kevin Jantzer Jul 29 '14 at 16:09
  • @KevinJantzer - It's a nice *improvement*, but it doesn't make `it's` *incorrect*, just *not as nice*. Neither one is actually **wrong**. – Fake Name Jul 30 '14 at 02:04
  • 1
    @KevinJantzer: Your edit was way out of scope of the question. The OP doesn't mention using HTML in the contenteditable anywhere. If you feel this question really needs an answer that doesn't replace quotes inside HTML tags (And that isn't broken), you should add an answer of your own. – Cerbrus Sep 15 '14 at 21:50
1

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');
};
aboutaaron
  • 4,869
  • 3
  • 36
  • 30
  • What about feet/inches or lat/long, e.g., ```"He's 5'11" tall," she said.``` – Dan May 08 '20 at 22:34
  • @Dan that's not a valid string in JavaScript. You could use backticks if you needed to replaced non-terminated quotes characters or escape them ahead of time before replacing. – aboutaaron May 08 '20 at 23:24
  • Yes, I am using backticks. I just wrote the actual string contents. `\`"He's 5'11" tall," she said.\`` – Dan May 09 '20 at 00:31