310

我有这样的价值:

"Foo Bar" "Another Value" something else

什么正则表达式将返回引号中的值(例如Foo BarAnother Value)?

4

20 回答 20

448

我一直在使用以下内容并取得了巨大成功:

(["'])(?:(?=(\\?))\2.)*?\1

它也支持嵌套引号。

对于那些想要更深入地解释它是如何工作的人,这里是来自用户ephemient的解释:

([""'])匹配报价;((?=(\\?))\2.)如果反斜杠存在,吞噬它,无论是否发生,匹配一个字符;*?匹配多次(非贪婪,不吃结束语);\1匹配用于打开的相同报价。

于 2008-10-05T04:40:14.453 回答
431

通常,您正在寻找以下正则表达式片段:

"(.*?)"

这使用了非贪婪 *? 运算符捕获直到但不包括下一个双引号的所有内容。然后,您使用特定于语言的机制来提取匹配的文本。

在 Python 中,你可以这样做:

>>> import re
>>> string = '"Foo Bar" "Another Value"'
>>> print re.findall(r'"(.*?)"', string)
['Foo Bar', 'Another Value']
于 2008-10-05T04:24:49.227 回答
114

我会去:

"([^"]*)"

[^"]是除 ' " '以外的任何字符的正则表达式,我
在非贪婪的 many 运算符上使用它的原因是我必须继续查找它以确保我得到正确。

于 2008-10-05T04:34:35.700 回答
33

让我们看看两种处理转义引号的有效方法。这些模式的设计不是为了简洁或美观,而是为了高效。

这些方法使用第一个字符区分来快速找到字符串中的引号,而无需进行替换。(这个想法是在不测试交替的两个分支的情况下快速丢弃不是引号的字符。)

引号之间的内容用展开的循环(而不是重复的交替)来描述,这样也更有效率:[^"\\]*(?:\\.[^"\\]*)*

显然,要处理没有平衡引号的字符串,您可以改用所有格量词:[^"\\]*+(?:\\.[^"\\]*)*+或者模拟它们的解决方法,以防止过多的回溯。您也可以选择带引号的部分可以是开始引号,直到下一个(非转义)引号或字符串结尾。在这种情况下,不需要使用所有格量词,您只需要将最后一个引号设为可选。

注意:有时引号不是用反斜杠转义的,而是通过重复引用来转义的。在这种情况下,内容子模式如下所示:[^"]*(?:""[^"]*)*

这些模式避免使用捕获组和反向引用(我的意思是类似的东西(["']).....\1并使用简单的交替,但["']在开始时,in factor。

Perl 喜欢:

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

(请注意,这(?s:...)是在非捕获组内打开 dotall/singleline 模式的语法糖。如果不支持此语法,您可以轻松地为所有模式打开此模式或将点替换为[\s\S]

(这种模式的编写方式完全是“手动驱动的”,没有考虑最终的引擎内部优化)

ECMA 脚本:

(?=["'])(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]*(?:\\[\s\S][^'\\]*)*')

POSIX 扩展:

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

或者简单地说:

"([^"\\]|\\.|\\\n)*"|'([^'\\]|\\.|\\\n)*'
于 2015-04-05T00:13:03.480 回答
27

奇怪的是,这些答案都不会产生一个正则表达式,其中返回的匹配是引号内的文本,这是所要求的。MA-Madden 尝试但仅将内部比赛作为一个被捕获的组而不是整个比赛。实际做到这一点的一种方法是:

(?<=(["']\b))(?:(?=(\\?))\2.)*?(?=\1)

在此演示中可以看到此示例https://regex101.com/r/Hbj8aP/1

这里的关键是开始时的正向后视 (the ?<=) 和结束时的正向前瞻 (the ?=)。向后查找是在当前字符后面查找引号,如果找到则从那里开始,然后向前查找正在检查前面的字符以查找引号,如果找到则停止该字符。后视组 (the ["']) 用括号括起来,以便为在开始时找到的任何引用创建一个组,然后在末尾使用前瞻(?=\1)来确保它仅在找到相应的引用时才停止。

唯一的其他复杂情况是,因为前瞻实际上并没有消耗结束引号,它会被起始后向再次找到,这会导致同一行上结束引号和开始引号之间的文本匹配。在开头的引号 ( ) 上放置一个单词边界["']\b有助于这一点,尽管理想情况下我想超越前瞻,但我认为这是不可能的。我直接从亚当的回答中获取了中间允许转义字符的位。

于 2017-11-10T01:22:45.203 回答
23

接受答案的正则表达式返回值,包括它们周围的引号:"Foo Bar""Another Value"作为匹配项。

这里是正则表达式,它只返回引号之间的值(正如提问者所要求的那样):

仅双引号(使用捕获组 #1 的值):

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

仅单引号(使用捕获组 #1 的值):

'(.*?[^\\])'

两者(捕获组#2的使用价值):

(["'])(.*?[^\\])\1

-

所有支持转义和嵌套引号。

于 2016-09-14T09:15:10.100 回答
12

一个很晚的答案,但喜欢回答

(\"[\w\s]+\")

http://regex101.com/r/cB0kB8/1

于 2014-10-29T15:18:07.337 回答
12

我喜欢Eugen Mihailescu 的解决方案,它可以匹配引号之间的内容,同时允许转义引号。但是,我发现了一些转义问题,并想出了以下正则表达式来修复它们:

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

它可以解决问题,并且仍然非常简单且易于维护。

演示(带有更多测试用例;随意使用并扩展它)。


PS:如果您只想要完整匹配中引号之间$0的内容( ),并且不怕性能损失,请使用:

(?<=(['"])\b)(?:(?!\1|\\).|\\.)*(?=\1)

不幸的是,如果没有引号作为锚点,我不得不\b在起始引号之后添加一个不能很好地处理空格和非单词边界字符的边界。

或者,通过简单地添加一个组并提取字符串形式$2来修改初始版本:

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

PPS:如果您只关注效率,请选择Casimir et Hippolyte 的解决方案;这是一个很好的。

于 2018-05-13T21:36:39.633 回答
8

上面的模式(["'])(?:(?=(\\?))\2.)*?\1可以完成工作,但我担心它的表现(它还不错,但可能会更好)。低于它的我的速度要快约 20%。

模式"(.*?)"只是不完整的。我对每个阅读本文的人的建议就是不要使用它!!!

例如,它无法捕获许多字符串(如果需要,我可以提供详尽的测试用例),如下所示:

$string = '你好吗?我\'很好,谢谢';

其余的和上面的一样“好”。

如果您真的关心性能和精度,请从以下开始:

/(['"])((\\\1|.)*?)\1/gm

在我的测试中,它涵盖了我遇到的每一个字符串,但如果你发现一些不起作用的东西,我很乐意为你更新它。

在在线正则表达式测试器中检查我的模式

于 2015-12-10T10:08:08.220 回答
6

这个版本

  • 解释转义引号
  • 控制回溯

    /(["'])((?:(?!\1)[^\\]|(?:\\\\)*\\[^\\])*)\1/
    
于 2008-10-06T01:42:52.377 回答
5

我喜欢 Axeman 更广泛的版本,但遇到了一些问题(例如,它不匹配

foo "string \\ string" bar

或者

foo "string1"   bar   "string2"

正确,所以我尝试修复它:

# opening quote
(["'])
   (
     # repeat (non-greedy, so we don't span multiple strings)
     (?:
       # anything, except not the opening quote, and not 
       # a backslash, which are handled separately.
       (?!\1)[^\\]
       |
       # consume any double backslash (unnecessary?)
       (?:\\\\)*       
       |
       # Allow backslash to escape characters
       \\.
     )*?
   )
# same character as opening quote
\1
于 2013-10-01T19:41:10.133 回答
5

更多答案!这是我使用的解决方案

\"([^\"]*?icon[^\"]*?)\"

TLDR;用您在所述引号中查找的内容
替换单词图标,瞧!


它的工作方式是查找关键字,而不关心引号之间的其他内容。EG:
id="fb-icon"
id="icon-close"
id="large-icon-close"
正则表达式查找引号,"
然后查找任何可能的字母组,"
直到找到为止icon
,任何可能的字母组不是"
它,然后查找结束"

于 2016-11-10T03:06:42.320 回答
4
string = "\" foo bar\" \"loloo\""
print re.findall(r'"(.*?)"',string)

试试这个,就像一个魅力!

\表示跳过字符

于 2014-02-12T07:28:34.067 回答
2

与亚当的回答不同,我有一个简单但有效的答案:

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

如果您想在引号中获取内容,只需添加括号:

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

然后$1匹配引号字符并$2匹配内容字符串。

于 2018-05-06T03:32:28.623 回答
1
echo 'junk "Foo Bar" not empty one "" this "but this" and this neither' | sed 's/[^\"]*\"\([^\"]*\)\"[^\"]*/>\1</g'

这将导致:>Foo Bar<><>但这<

在这里,为了清楚起见,我在 >< 之间显示了结果字符串,还使用带有这个 sed 命令的非贪婪版本,我们首先在“”之前和之后扔掉垃圾,然后用“”之间的部分替换它's 并用 ><'s 包围它。

于 2008-10-05T12:45:42.447 回答
1

从 Greg H. 我能够创建这个正则表达式来满足我的需要。

我需要匹配一个在引号内限定的特定值。它必须是完全匹配,没有部分匹配会触发命中

例如,“test”不能匹配“test2”。

reg = r"""(['"])(%s)\1"""
if re.search(reg%(needle), haystack, re.IGNORECASE):
    print "winning..."

猎人

于 2011-11-29T15:59:09.190 回答
1

如果您尝试查找仅具有特定后缀的字符串,例如点语法,您可以尝试以下操作:

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

.localized后缀在哪里。

例子:

print("this is something I need to return".localized + "so is this".localized + "but this is not")

它会捕获"this is something I need to return".localized"so is this".localized但不会"but this is not"

于 2018-03-02T16:51:53.627 回答
1

Microsoft VBA 编码器子集的补充答案只有一个使用该库Microsoft VBScript Regular Expressions 5.5,这给出了以下代码

Sub TestRegularExpression()

    Dim oRE As VBScript_RegExp_55.RegExp    '* Tools->References: Microsoft VBScript Regular Expressions 5.5
    Set oRE = New VBScript_RegExp_55.RegExp

    oRE.Pattern = """([^""]*)"""


    oRE.Global = True

    Dim sTest As String
    sTest = """Foo Bar"" ""Another Value"" something else"

    Debug.Assert oRE.test(sTest)

    Dim oMatchCol As VBScript_RegExp_55.MatchCollection
    Set oMatchCol = oRE.Execute(sTest)
    Debug.Assert oMatchCol.Count = 2

    Dim oMatch As Match
    For Each oMatch In oMatchCol
        Debug.Print oMatch.SubMatches(0)

    Next oMatch

End Sub
于 2018-05-04T13:35:27.327 回答
1

上面的所有答案都很好......除了它们不支持所有的Unicode字符!在 ECMA 脚本 (Javascript)

If you are a Node users, you might want the the modified version of accepted answer that support all unicode characters :

/(?<=((?<=[\s,.:;"']|^)["']))(?:(?=(\\?))\2.)*?(?=\1)/gmu

Try here.

于 2020-05-24T12:08:34.433 回答
0

对我来说,这是一个:

|([\'"])(.*?)\1|i

我用过这样的一句话:

preg_match_all('|([\'"])(.*?)\1|i', $cont, $matches);

效果很好。

于 2011-10-02T16:52:31.937 回答