views:

445

answers:

4

I have an application which uses a javascript based rules engine. I need a way to convert regular straight quotes into curl (or smart) quotes. It'd be easy to just do a string.replace for ["], only this will only insert one case of the curly quote.

The best way I could think of was replace the first occurrence of a quote with a left curly quote and every other one following with a left, and the rest right curly.

Is there a way to accomplish this using javascript?

+1  A: 
'foo "foo bar" "bar"'.replace(/"([-a-zA-Z0-9 ]+)"/g, function(wholeMatch, m1){
    return "“" + m1 + "”";
});
Luca Matteis
This does not answer the question.
SLaks
@SLaks: I edited it, that works.
Luca Matteis
How would it handle `"John was 6' 4""`?
Anon.
@Anon, how would any program handle that without being smart enough to know what inches and feet are?
Earlz
Stuff I've seen normally curlies the quote mark in the correct direction, but also curlies the inch mark the same way. What it *doesn't* do is curly the inch mark, and then curly every single other quote mark the opposite way from what it's supposed to do.
Anon.
@Anon: then maybe you should post a solution.
Luca Matteis
I was typing one up, but Renesis ninja'd me. I saw no need to duplicate it.
Anon.
+8  A: 

You could replace all that preceed a word character with the left quote, and all that follow a word character with a right quote.

str = str.replace(/"(?=\w|$)/g, "“");
str = str.replace(/(?<=\w|^)"/g, "&#8221;"); // IF the language supports look-
                                             // behind. Otherwise, see below.

As pointed out in the comments below, this doesn't take punctuation into account, but easily can:

/(?<=[\w,.?!\)]|^)"/g

[Edit:] For languages that don't support look-behind, like Javascript, as long as you replace all the front-facing ones first, you have two options:

str = str.replace(/"/g, "&#8221;"); // Replace the rest with right curly quotes
// or...
str = str.replace(/\b"/g, "&#8221;"); // Replace any quotes after a word
                                      // boundary with right curly quotes

(I've left the original solution above in case this is helpful to someone using a language that does support look-behind)

Renesis
+1 for actually answering the question. Though users of this should take into account that it's not perfect in every situation - for example, the dashes indicating feet and inches.
Anon.
... or punctuation that ends a quotation.
Pointy
Thank you! This is what I was looking for. One note, copying the code exactly gave me an error. the '?<=' portion was changed to '?='. Also, I had to remove the quotation character from the end case for it to match correctly. The code:s = s.replace(/"(?=\w|$)/g, "“");s = s.replace(/(?=[\w,.?!\-")]|^)"/g, "”");
BlueVoid
@BlueVoid - You are correct about the error, I discovered this and was updating my answer as you commented :) Be careful with your code - `?=` is a look-ahead, which matches because it looks ahead and sees the quote, which is in your character class. I would go with the first "alternative" solution in my edited answer -- just replace all of them with **right** curly quotes *after* replacing the **left** curly quotes.
Renesis
@Renesis Good point. This simplifies things anyway. It's working great.
BlueVoid
A: 

I don't think something like that in general is easy at all, because you'd have to interpret exactly what each double-quote character in your content means. That said, what I'd do is collect all the text nodes I was interested in, and then go through and keep track of the "on/off" (or "odd/even"; whatever) nature of each double quote instance. Then you can know which replacement entity to use.

Pointy
+2  A: 

You might want to look at what Pandoc does—apparently with the --smart option, it handles quotes properly in all cases (including e.g. ’tis and ’twere).

I recently wrote a Javascript typography prettification engine that does, among other things, quote replacement; I wound up using basically the algorithm suggested by Renesis, but there’s currently a failing test up waiting for a smarter solution.

If you’re interested in cribbing my code (and/or submitting a patch based on work you’ve done), check it out: jsPrettify. jsprettify.prettifyStr does what you’re looking for. If you don’t want to deal with the Closure dependency, there’s an older version that runs on its own—it even works in Rhino.

Steven Dee