admin 管理员组

文章数量: 1086019

I am trying to replace non-consecutive single quotes in a string with two consecutive quotes.

Examples (in/out)

  • "abc'def" --> "abc''def"
  • "abc''de'f" --> "abc''de''f"
  • etc.

Javascript doesn't support lookbehinds, so the following regular expression I'd use with Java (well, more or less) will not pile:

myString.replace(/(?<!)'(?!'))/g, "''");

I have looked around SO and some answers advise using a non-capturing group containing a custom character class negating the character that would otherwise be in the negative lookbehind:

myString.replace(/(?:[^'])'(?!'))/g, "''");

However, that will not do either: it will successfully not replace the two consecutive single quotes, but in the "abc''de'f" example, it will "eat" the f when replacing the next single quote with two consecutive single quotes, ending up in:

"abc''de''gh" (see it's missing the f!)

Questions

  • Is there a suitable regex-based solution for this problem?
  • If not, should I just go with a barbaric iteration and indexing of all the input string's characters and painfully build another string from it (please no)?

I am trying to replace non-consecutive single quotes in a string with two consecutive quotes.

Examples (in/out)

  • "abc'def" --> "abc''def"
  • "abc''de'f" --> "abc''de''f"
  • etc.

Javascript doesn't support lookbehinds, so the following regular expression I'd use with Java (well, more or less) will not pile:

myString.replace(/(?<!)'(?!'))/g, "''");

I have looked around SO and some answers advise using a non-capturing group containing a custom character class negating the character that would otherwise be in the negative lookbehind:

myString.replace(/(?:[^'])'(?!'))/g, "''");

However, that will not do either: it will successfully not replace the two consecutive single quotes, but in the "abc''de'f" example, it will "eat" the f when replacing the next single quote with two consecutive single quotes, ending up in:

"abc''de''gh" (see it's missing the f!)

Questions

  • Is there a suitable regex-based solution for this problem?
  • If not, should I just go with a barbaric iteration and indexing of all the input string's characters and painfully build another string from it (please no)?
Share Improve this question asked Nov 16, 2016 at 10:55 MenaMena 48.5k11 gold badges89 silver badges109 bronze badges 3
  • 1 How would you handle triple quotes? Are they an issue? If not match '+ and replace with '' – Sebastian Proske Commented Nov 16, 2016 at 10:57
  • @SebastianProske that is actually working for me, triple quotes can be ignored in my use case. Can I invite you to put this into an answer - unless there's a duplicate I haven't found? – Mena Commented Nov 16, 2016 at 11:00
  • Thanks all for answering. I'm accepting Sebastian's answer because it is the simplest in my use case, but I can see the merit in the other answers, especially anubhava's for the cool lookbehind "workaround" and Wiktor's for the powerful callback idiom. – Mena Commented Nov 16, 2016 at 11:23
Add a ment  | 

5 Answers 5

Reset to default 3

You can use this regex:

str = str.replace(/(^|[^'])'(?!')/g, "$1''"));
  • It matches line start or non single quote character before a single quote and captures it in a group #1.
  • Using a negative lookahead it also asserts that matched single quote is not followed by another single quote.
  • In replacement we use back-reference of captured group #1 and two ''

Full code:

var arr = ["abc'def", "abc''de'f"];

for (i=0; i<arr.length; i++) {
   console.log( arr[i] + ' => ' + arr[i].replace(/(^|[^'])'(?!')/g, "$1''") );
}

Output:

abc'def => ab''def
abc''de'f => abc''d''f

You may also match 2 or more occurrences of single apostrophes into a capturing group and just match all other single apostrophes, and use a callback to use the right replacement in either cases:

var ss = ["abc'def" , "abc''de'f", "abc''''''def'g"];
for (var s of ss) {
  console.log(s.replace(/('{2,})|'/g, function($0,$1) { return $1 ? $1 : "''"; }));
}

This solution won't shrink ''''' to '' as replace(/'+/g, "''") would.

Details:

  • ('{2,}) - matches and captures into Group 1 two or more occurrences of '
  • | - or
  • ' - a single apostrophe is matched in all other contexts.

The callback method accepts $0 (the whole match) and $1 (Group 1). If $1 is not undefined, then its value is reinserted, else ' (the whole match) is replaced with ''.

As multiple (=more than 2) quotes are not an issue for you, you don't actually need to take that much care, if there are one or two quotes at a given place, just - so just replace every occurence of quotes with the wanted double quotes. The regex for this would be /'+/g and can be replaced by "''"

How about the humble chained replace?

str = "abc'def --> abc''def abc''de'f --> abc''de''f"
console.log(str)
console.log(str.replace(/''/g,"|").replace(/'/g,"''").replace(/\|/g,"''"))

I had success with this regular expression:

/([^\'])\'([^\'])/g

Example:

var afterRegex = document.getElementsByClassName('after')[0];
var listItems = afterRegex.getElementsByTagName('li');

for (var i = 0; i < listItems.length; i++) {

var string = listItems[i].textContent;
var convertedString = string.replace(/([^\'])\'([^\'])/g, "$1''$2");
listItems[i].textContent = convertedString;

}
div {
float: left;
width: 200px;
}
<div>
<h2>Before:</h2>
<ul class="before">
<li>"abc'def"</li>
<li>"abc''de'f"</li>
</ul>
</div>

<div>
<h2>After:</h2>
<ul class="after">
<li>"abc'def"</li>
<li>"abc''de'f"</li>
</ul>
</div>

本文标签: javascriptReplace character if not preceded nor followed by same characterStack Overflow