javascript正则表达式选择带引号的字符串,但不选择转义引号

javascript regex to select quoted string but not escape quotes

本文关键字:选择 转义 字符串 正则表达式 javascript      更新时间:2023-09-26

原始字符串:

some text "some '"string'"right here "

想要获得:

"some '"string'"right here"

我正在使用以下正则表达式:

/'"(.*?)'"/g

使用解析器正确解析字符串

使用JavaScript正则表达式,不可能从正确的双引号开始匹配。您将匹配转义的,或者在引号之前的文本'之后无法匹配正确的双引号。因此,最安全的方法是使用解析器。这是一个示例:

var s = "some text '''"extras'" some '''"string '''" right'" here '"";
console.log("Incorrect (with regex): ", s.match(/"([^"'']*(?:''.[^"'']*)*)"/g));
var res = [];
var tmp = "";
var in_quotes = false;
var in_entity = false;
for (var i=0; i<s.length; i++) {
  if (s[i] === '''' && in_entity  === false) { 
     in_entity = true;
     if (in_quotes === true) {
       tmp += s[i];
     }
  } else if (in_entity === true) { // add a match
      in_entity = false;
      if (in_quotes === true) {
         tmp += s[i];
      }
  } else if (s[i] === '"' && in_quotes === false) { // start a new match
      in_quotes = true;
      tmp += s[i];
  } else if (s[i] === '"'  && in_quotes === true) { // append char to match and add to results
      tmp += s[i];
      res.push(tmp);
      tmp = "";
      in_quotes = false;
  } else if (in_quotes === true) { // append a char to the match
     tmp += s[i];
  } 
}
console.log("Correct results: ", res);

不太安全的regex方法

不可能用惰性点匹配模式匹配所需的字符串,因为它将在第一个"之前停止如果您知道您的字符串在带引号的子字符串之前永远不会有转义引号,并且如果您确定在双引号之前没有文字'(并且这些条件对于安全使用正则表达式非常严格),则可以使用

/"([^"'']*(?:''.[^"'']*)*)"/g

查看regex演示

  • "-匹配报价
  • ([^"'']*(?:''.[^"'']*)*)-0个或多个
    • [^"'']*-0+非'和非" s
    • (?:''.[^"'']*)*-零个或多个
      • ''.-任何转义符号
      • [^"'']*-0+非'和非" s
  • "-后引号

JS演示:

var re = /"([^"'']*(?:''.[^"'']*)*)"/g; 
var str = `some text "some ''"string''"right here " some text "another ''"string''"right here "`;
var res = [];
while ((m = re.exec(str)) !== null) {
   res.push(m[1]);
}
document.body.innerHTML = "<pre>" + JSON.stringify(res, 0, 4) + "</pre>"; // Just for demo
console.log(res); // or another result demo

安全正则表达式方法

作为@WiktorStribiżew答案的补充,有一种技术可以使用regex在正确的双引号处开始匹配。它包括匹配形式为的引用和未引用文本

/"(quoted)"|unquoted/g

正如你所看到的,引用的文本是由一个组匹配的,所以我们只考虑由match[1]反向引用的文本。

Regex

/"([^"'']*(?:''.[^"'']*)*)"|[^"'']*(?:''.[^"'']*)*/g

代码

var regex = /"([^"'']*(?:''.[^"'']*)*)"|[^"'']*(?:''.[^"'']*)*/g;
var s = "some text '''"extras'" some '''"string '''" right'" here '"";
var match;
var res = [];
while ((match = regex.exec(s)) !== null) {
    if (match.index === regex.lastIndex)
        regex.lastIndex++;
    if( match[1] != null )
        res.push(match[1]); //Append to result only group 1
}
console.log("Correct results (regex technique): ",res)

通用解决方案:

  • 引号类型:单引号、双引号、反引号
  • 检测每个引用的部分和引用类型
  • 允许转义引号位于带引号的部分内
  • 结果分为两组:<qType>(引号类型),<inQuotes>

(?<qType>["'`])(?&llt;inQuotes>(?:''''''1|.)*?)''1

或者,不带组命名:

([quot;'`])((?:''''''''1|.)*?)''1

您可以使用以下正则表达式:

/[^'']('".*?[^'']'")/g

[^'']捕获任何不同于''的特征。所以"不会被捕获作为比赛的开始或结束。

为了在忽略任何简单转义引号的情况下从一个引号匹配到另一个引号('"):

(:?[^'']|^)('"(:?.*?[^'']){0,1}'")

意味着(:?分组的开始没有提取[^'']匹配一个不是反斜杠的字符|匹配前一个字符或^是字符串的开始。(提取分组的开始'"查找引号(跟随非斜杠或字符串的开始),(:?.*?[^'']匹配以非斜杠结尾的最短子字符串,){0,1}零次或一次-这实际上意味着一次或空子字符串,后面跟着'"引号。

编辑:Wiktor Stribiżew正确地指出,在我的初始回答中,字符串中有正则表达式项的更多情况将失败。例如CCD_ 27,该CCD_。为了避免这个特定的问题,你可以使用

(:?[^'']|^)((:?'''')*'"(:?.*?[^'']){0,1}(:?'''')*'")

但对于regex的实际兼容性,您需要参考Wiktor的答案。