带转义引号的带引号的字符串的正则表达式

Regex for quoted string with escaping quotes

提问人: 提问时间:10/30/2008 最后编辑:David 更新时间:2/23/2023 访问量:227762

问:

如何使用正则表达式获取子字符串?" It's big \"problem "

s = ' function(){  return " It\'s big \"problem  ";  }';     
正则表达式 转义 报价

评论

1赞 Jonathan Leffler 11/1/2008
如何在仅包含“Is”的字符串中找到“It's”?我会为您修复它,但我不知道您使用的语言中适用哪些单引号/转义约定。
3赞 ridgerunner 10/8/2011
重复项:PHP:正则表达式忽略引号内的转义引号
3赞 ridgerunner 10/8/2011
实际上,查看日期,我发现另一个问题是这个问题的重复。无论哪种方式,请务必查看我的答案
1赞 Alan Moore 7/17/2014
@ridgerunner:我投票决定按照你的建议关闭它。确实,其他问题最近才出现,但也要好得多(主要归功于您的回答)。

答:

11赞 sirnotappearingonthissite 10/30/2008 #1
/(["\']).*?(?<!\\)(\\\\)*\1/is

应该与任何带引号的字符串一起使用

评论

1赞 PhiLho 10/30/2008
不错,但对于请求来说太灵活了(将匹配单引号......并且可以简化为/“.*?(?<!\)“/除非我错过了什么。哦,还有一些语言(例如。JavaScript)唉,不理解否定的后视表达式。
2赞 Markus Jarderot 11/1/2008
@PhiLho,仅使用单个 (?<!\\) 在字符串末尾的转义反斜杠上会失败。不过,JavaScript 中的后视确实如此。
0赞 Swivel 5/8/2021
@PhiLho 您使用此输入 : 的简化将导致此匹配:,这是不正确的。匹配组很重要,以确定使用哪种类型的报价来打开它。"Martha's""Martha'
0赞 PhiLho 6/4/2021
@Swivel 注 1:我的答案中有一个双反斜杠,不知何故 SO 丢失了第二个(因为 Markdown?应该在反引号中受到保护。注2:马库斯是对的......所以它是有缺陷的。不像我的(流行的)答案...... :-)注3:我的表达中没有单引号,我没有看到你提到的问题,我无法重现。(我说我不处理单引号作为分隔符,因为它不是主题。
1赞 Swivel 8/5/2021
@PhiLho 呵呵......奇怪。不知道我第一次是怎么误解它的。你是绝对正确的。我不确定我是怎么误解你的原始评论的。
0赞 Henrik Paul 10/30/2008 #2

人们必须记住,正则表达式并不是解决所有字符串问题的灵丹妙药。有些东西用光标和线性、手动、搜索更简单。CFL 可以非常轻松地解决问题,但 CFL 实现 (afaik) 并不多。

评论

4赞 Alan Moore 10/31/2008
没错,但这个问题完全在正则表达式的能力范围内,并且有很多正则表达式的实现。
209赞 PhiLho 10/30/2008 #3
/"(?:[^"\\]|\\.)*"/

在 The Regex Coach 和 PCRE Workbench 中工作。

JavaScript 测试示例:

    var s = ' function(){ return " Is big \\"problem\\", \\no? "; }';
    var m = s.match(/"(?:[^"\\]|\\.)*"/);
    if (m != null)
        alert(m);

评论

35赞 Ajedi32 1/4/2014
意义。简明英语:两个引号围绕着“任何不是引号或反斜杠的字符”或“后跟任何字符的反斜杠”的零个或多个引号。我简直不敢相信我没有想过要这样做......
7赞 magras 10/3/2014
我会回答自己。=) 是被动或非捕获组。这意味着以后不能回溯引用它。(?:...)
0赞 cancerbero 3/17/2015
经过大量搜索和测试,这是我找到的解决这个常见问题的真正且唯一的解决方案。谢谢!
13赞 leo 5/3/2015
谢谢你。我也想匹配单引号,所以我最终将其调整为:/(["'])(?:[^\1\\]|\\.)*?\1/
1赞 PhiLho 7/26/2016
@WiktorStribiżew 您的字符串不符合描述:包含双引号之间的部分的字符串,可以包含转义的双引号。不确定您的期望...
40赞 Darrell 6/19/2009 #4

这个来自许多 linux 发行版中可用的 nanorc.sample。它用于 C 样式字符串的语法高亮显示

\"(\\.|[^\"])*\"

评论

0赞 Wiktor Stribiżew 7/25/2016
使用 var s = ' my \\“new\\” string 和 \“this should be matched\”';,这种方法将导致意想不到的结果。
1赞 hellork 11/28/2018
c.nanorc是我去的第一个地方。无法让它作为 C 字符串文字的一部分工作,直到像这样双重转义所有内容" \"(\\\\.|[^\\\"])*\" "
0赞 Kirill Frolov 1/14/2019
这适用于 libc 中的 egrep 和 re_comp/re_exec 函数。
9赞 Tosh Afanasiev 12/15/2010 #5
"(?:\\"|.)*?"

交替使用 和 传递转义的引号,而惰性量词可确保不会超过带引号的字符串的末尾。适用于 .NET Framework RE 类\".*?

评论

0赞 Ian 12/12/2014
但失败了"\\"
0赞 dave 5/29/2018
/"(?:(?:\\"|[^"])*)"/g这应该可以解决
23赞 Guy Bedford 5/28/2012 #6

正如 ePharaoh 所提供的,答案是

/"([^"\\]*(\\.[^"\\]*)*)"/

要使上述内容适用于单引号或双引号字符串,请使用

/"([^"\\]*(\\.[^"\\]*)*)"|\'([^\'\\]*(\\.[^\'\\]*)*)\'/

评论

2赞 Beejor 6/4/2015
这是唯一一个适合我的集合,其中包含一个包含 99 个转义的 1.5 KB 大引号字符串。此页面上的所有其他表达式在我的文本编辑器中都因溢出错误而中断。虽然这里的大多数人都在浏览器中工作,但要记住一些事情。小提琴:jsfiddle.net/aow20y0L
3赞 shaunc 8/8/2015
有关解释,请参阅下面的 @MarcAndrePoulin 的回答。
0赞 user2267983 4/11/2013 #7

如果从一开始就搜索,也许这可以工作?

\"((\\\")|[^\\])*\"
0赞 Rvanlaak 12/3/2013 #8

https://stackoverflow.com/a/10786066/1794894 的更广泛版本

/"([^"\\]{50,}(\\.[^"\\]*)*)"|\'[^\'\\]{50,}(\\.[^\'\\]*)*\'|“[^”\\]{50,}(\\.[^“\\]*)*”/   

此版本还包含

  1. 最小报价长度为 50
  2. 额外类型的报价(打开和关闭)
-1赞 Petter Thowsen 9/21/2014 #9

在正则表达式上搞砸了,最终得到了这个正则表达式:(不要问我它是如何工作的,即使我写了它,我也几乎不明白哈哈)

"(([^"\\]?(\\\\)?)|(\\")+)+"
11赞 Marc-André Poulin 6/10/2015 #10

此处提供的大多数解决方案都使用替代重复路径,即 (A|B)*.

您可能会在大型输入上遇到堆栈溢出,因为某些模式编译器使用递归来实现这一点。

例如,Java:http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6337993

像这样: ,或者 Guy Bedford 提供的那个将减少解析步骤的数量,避免大多数堆栈溢出。"(?:[^"\\]*(?:\\.)?)*"

8赞 ack 11/10/2015 #11
/"(?:[^"\\]++|\\.)*+"/

直接从安装了 Perl 5.22.0 的 Linux 系统上获取。 作为优化,此正则表达式使用两者的“posessive”形式,并防止回溯,因为事先知道没有结束引号的字符串在任何情况下都不会匹配。man perlre+*

5赞 Vadim Sayfi 4/25/2017 #12

这个在 PCRE 上工作得很好,不会与 StackOverflow 一起使用。

"(.*?[^\\])??((\\\\)+)?+"

解释:

  1. 每个带引号的字符串都以 Char 开头:" ;
  2. 它可以包含任意数量的任何字符:{Lazy match};以非转义字符结尾.*?[^\\];
  3. 语句 (2) 是 Lazy(!) 可选的,因为字符串可以是空的(“”)。所以:(.*?[^\\])??
  4. 最后,每个带引号的字符串都以 Char() 结尾,但它前面可以有偶数个转义符号对;它是 Greedy(!) 可选的: {Greedy matching}, bacause string 可以是空的,也可以没有结束对!"(\\\\)+((\\\\)+)?+

评论

1赞 Casimir et Hippolyte 3/18/2018
这不是世界上最有效的模式,但这个想法很有趣。请注意,您可以像这样缩短它:"(.*?[^\\])?(\\\\)*"
2赞 mathias hansen 8/6/2017 #13

这是一个同时使用“ 和 ' 的,您可以在开始时轻松添加其他的。

("|')(?:\\\1|[^\1])*?\1

它使用反向引用 (\1) 与第一组(“或”)中的内容完全匹配。

http://www.regular-expressions.info/backref.html

评论

2赞 Seph Reed 11/2/2017
这是一个非常好的解决方案,但应该替换为,因为没有反向引用这样的东西,反正也没关系。在发生任何不好的事情之前,第一个条件总是匹配的。[^\1].
0赞 Adam Katz 1/9/2019
@SephReed – 替换为 将有效地将此正则表达式更改为 ,然后它将匹配 。也就是说,真正开始工作是很困难的。@mathiashansen – 你最好使用笨拙且昂贵的正则表达式(所以整个正则表达式,加上一些效率清理,将是 .如果您的引擎不支持它,则它是可选的。[^\1].("|').*?\1"foo\""foo \" bar"[^\1](?!\1).(["'])(?:\\.|(?!\1).)*+\1+
3赞 scagood 1/9/2018 #14

以前没有涉及的一个选项是:

  1. 反转字符串。
  2. 对反转的字符串执行匹配。
  3. 重新反转匹配的字符串。

这还有一个额外的好处,即能够正确匹配转义的打开标签。

假设您有以下字符串; 在这里,不应该匹配,应该匹配。 最重要的是,应该匹配,不应该匹配。String \"this "should" NOT match\" and "this \"should\" match"\"this "should" NOT match\""should"this \"should\" match\"should\"

首先举个例子。

// The input string.
const myString = 'String \\"this "should" NOT match\\" and "this \\"should\\" match"';

// The RegExp.
const regExp = new RegExp(
    // Match close
    '([\'"])(?!(?:[\\\\]{2})*[\\\\](?![\\\\]))' +
    '((?:' +
        // Match escaped close quote
        '(?:\\1(?=(?:[\\\\]{2})*[\\\\](?![\\\\])))|' +
        // Match everything thats not the close quote
        '(?:(?!\\1).)' +
    '){0,})' +
    // Match open
    '(\\1)(?!(?:[\\\\]{2})*[\\\\](?![\\\\]))',
    'g'
);

// Reverse the matched strings.
matches = myString
    // Reverse the string.
    .split('').reverse().join('')
    // '"hctam "\dluohs"\ siht" dna "\hctam TON "dluohs" siht"\ gnirtS'

    // Match the quoted
    .match(regExp)
    // ['"hctam "\dluohs"\ siht"', '"dluohs"']

    // Reverse the matches
    .map(x => x.split('').reverse().join(''))
    // ['"this \"should\" match"', '"should"']

    // Re order the matches
    .reverse();
    // ['"should"', '"this \"should\" match"']

好的,现在来解释正则表达式。 这是正则表达式可以很容易地分成三部分。如下:

# Part 1
(['"])         # Match a closing quotation mark " or '
(?!            # As long as it's not followed by
  (?:[\\]{2})* # A pair of escape characters
  [\\]         # and a single escape
  (?![\\])     # As long as that's not followed by an escape
)
# Part 2
((?:          # Match inside the quotes
(?:           # Match option 1:
  \1          # Match the closing quote
  (?=         # As long as it's followed by
    (?:\\\\)* # A pair of escape characters
    \\        # 
    (?![\\])  # As long as that's not followed by an escape
  )           # and a single escape
)|            # OR
(?:           # Match option 2:
  (?!\1).     # Any character that isn't the closing quote
)
)*)           # Match the group 0 or more times
# Part 3
(\1)           # Match an open quotation mark that is the same as the closing one
(?!            # As long as it's not followed by
  (?:[\\]{2})* # A pair of escape characters
  [\\]         # and a single escape
  (?![\\])     # As long as that's not followed by an escape
)

这在图像形式上可能要清晰得多:使用 Jex 的 Regulex 生成

github 上的图片(JavaScript 正则表达式可视化工具。对不起,我的声誉不够高,无法包含图像,所以,它现在只是一个链接。

下面是使用此概念的示例函数的要点,该函数更高级一些: https://gist.github.com/scagood/bd99371c072d49a4fee29d193252f5fc#file-matchquotes-js

0赞 Bigger 3/15/2018 #15

我遇到了类似的问题,试图删除可能会干扰某些文件解析的带引号的字符串。

我最终得到了一个两步解决方案,它击败了你能想到的任何复杂的正则表达式:

 line = line.replace("\\\"","\'"); // Replace escaped quotes with something easier to handle
 line = line.replaceAll("\"([^\"]*)\"","\"x\""); // Simple is beautiful

更易于阅读,可能更有效率。

0赞 Aramis NSR 7/12/2020 #16

如果你的IDE是IntelliJ Idea,你可以忘记所有这些麻烦,把你的正则表达式存储到一个字符串变量中,当你把它复制粘贴到双引号中时,它会自动变成一个正则表达式可接受的格式。

Java 中的示例:

String s = "\"en_usa\":[^\\,\\}]+";

现在,您可以在正则表达式或任何地方使用此变量。

0赞 ShenRuijie 2/23/2023 #17
(?<="|')(?:[^"\\]|\\.)*(?="|')

“这是个大问题” 比赛结果: 这是个大问题

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

“这是个大问题” 比赛结果: “这是个大问题”