正则表达式用于带引号的引号字符串


120

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

s = ' function(){  return " It\'s big \"problem  ";  }';     

1
如何在仅包含“ Is”的字符串中找到“ It's”?我会为您修复它,但我不知道哪种单引号/转义约定适用于您使用的语言。
乔纳森·勒夫勒


2
实际上,查看日期,我发现另一个问题是该问题的重复。无论哪种方式,请务必查看我的答案
ridgerunner 2011年

@ridgerunner:我投票按照你的建议关闭它。的确,另一个问题是较新的,但是它也要好得多(主要感谢您的回答)。
艾伦·摩尔

Answers:


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

在Regex Coach和PCRE Workbench中工作。

JavaScript测试示例:

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


23
说得通。普通英语:用两个引号引起来的零个或多个“任何不是引号或反斜杠的字符”或“反斜杠后跟任何字符”。我不敢相信我没有想到要这么做...
Ajedi32

7
我会自己回答。=)(?:...)是被动或不捕捉的组。这意味着它以后不能被反向引用。
magras 2014年

经过大量的测试和测试之后,这才是我发现这个常见问题的唯一真正的解决方案。谢谢!
Cancerbero 2015年

9
谢谢你 我也想匹配单引号,所以我最终对其进行了调整:/(["'])(?:[^\1\\]|\\.)*?\1/
leo 2015年


32

这来自许多Linux发行版中的nanorc.sample。它用于C样式字符串的语法突出显示

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


1
c.nanorc是我去的第一个地方。直到将这样的所有内容都进行两次转义,才能使它作为C字符串文字的一部分工作" \"(\\\\.|[^\\\"])*\" "
hellork

这可以与libc中的egrep和re_comp / re_exec函数一起使用。
fk0

19

正如ePharaoh提供的那样,答案是

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

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

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

2
这是唯一对我有用的,带有单个大的1.5 KB引号的包含99个转义符的字符串的设置。该页面上的所有其他表达式在我的文本编辑器中都出现了溢出错误。尽管此处大多数功能都可以在浏览器中运行,但请记住一些注意事项。小提琴:jsfiddle.net/aow20y0L
Beejor 2015年

3
请参阅下面的@MarcAndrePoulin的答案以获取解释。
凌晨



7
/"(?:[^"\\]++|\\.)*+"/

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


4
/(["\']).*?(?<!\\)(\\\\)*\1/is

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


1
不错,但是对于请求来说太灵活了(将匹配单引号...)。并且可以简化为/".*?(?<!\)"/,除非我错过了什么。哦,有些语言(例如JavaScript)a不理解负向后的表达式。
PhiLho's

1
@PhiLho仅使用单个(?<!\\)会在字符串末尾的转义反斜杠上失败。不过,关于JavaScript的回溯确实如此。
Markus Jarderot

4

这一点在PCRE上可以完美地工作,并且不适合StackOverflow。

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

说明:

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

这不是世界上最有效的模式,但是这个想法很有趣。请注意,您可以像这样缩短它:"(.*?[^\\])?(\\\\)*"
Casimir et Hippolyte

2

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

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

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

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


这是一个非常好的解决方案,但是[^\1]应该替换为它,.因为没有反引用的东西,也没关系。在发生任何不良情况之前,第一个条件将始终匹配。
瑟夫·里德

@SephReed -更换[^\1].将有效地改变这一正则表达式("|').*?\1,然后将匹配"foo\""foo \" bar"。就是说,[^\1]要真正开始工作是困难的。@ mathiashansen -你是用笨重和昂贵的更好(?!\1).(所以整个正则表达式,一些效率清理,会(["'])(?:\\.|(?!\1).)*+\1的。+是可选的,如果您的引擎不支持它。
亚当·卡茨

2

之前未涉及的选项是:

  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"']

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

# 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

必须记住,正则表达式不是所有字符串Y的灵丹妙药。使用游标和线性,手动,搜索可以简化一些工作。一个CFL会做的伎俩很平凡,但不会有太多的CFL实现(据我所知)。


3
的确如此,但是这个问题完全在正则表达式的能力范围内,并且有很多实现。
艾伦·摩尔


0

在正则表达式中陷入困境,并得到了这个正则表达式:(不要问我它是如何工作的,即使我写了它,我也几乎不明白)

"(([^"\\]?(\\\\)?)|(\\")+)+"

0

如果从头开始进行搜索,也许可以正常工作吗?

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

0

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

我最终提出了一个两步解决方案,它可以击败您可以想到的任何复杂的正则表达式:

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

更容易阅读,可能更有效。


0

如果您的IDE是IntelliJ Idea,则可以忘记所有这些麻烦,并将正则表达式存储在String变量中,并且在将其复制粘贴到双引号中时,它将自动更改为正则表达式可接受的格式。

Java中的示例:

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

现在您可以在regexp或任何地方使用此变量。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.