RegEx:在引号之间获取值


Answers:


361

我一直在成功使用以下内容:

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

它也支持嵌套引号。

对于那些想要更深入地解释其工作原理的用户,以下是来自用户的解释:

([""'])匹配报价;((?=(\\?))\2.)如果存在反斜杠,请对其进行吞噬,并确定是否匹配字符;*?多次匹配(非贪婪,以免吃掉最后的报价);\1匹配用于打开的相同报价。


6
@steve:这也将错误地匹配"foo\"。前瞻性技巧使?量词具有所有格(即使正则表达式不支持?+语法或原子分组)
Robin Robin

1
使用python会引发错误:sre_constants.error:无法引用开放组
a1an

9
这将返回包含匹配引号的值。是否没有机会按要求返回引号之间内容
马丁·施耐德

4
将前瞻性作为所有格量词完全没有必要且令人困惑。只需使用一种替代方法:(["'])(?:\\.|[^\\])*?\1
阿兰·菲

2
如何避免空字符串?
Vikas Bansal

333

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

"(.*?)"

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

在Python中,您可以执行以下操作:

>>> import re
>>> string = '"Foo Bar" "Another Value"'
>>> print re.findall(r'"(.*?)"', string)
['Foo Bar', 'Another Value']

11
很好,但是它不能处理带有转义引号的字符串。例如,"hello \" world"
robbyt

使用JavaScript的match,这也将匹配引号。它将与迭代工作在EXEC如下所述:stackoverflow.com/questions/7998180/...
Kiechlus

4
@robbyt我知道现在回复有点晚了,但是,负面的回望如何?"(.*?(?<!\\))"
Mateus

4
谢谢-如果您确定没有转义的引号可以处理,这会更简单。
squarecandy

一个词。太棒了!
Shiva Avula

89

我会去:

"([^"]*)"

[^“]是除任何字符正则表达式'
我用这个在非贪婪多的运营商的原因是,我要继续找,最多只是为了确保我得到它纠正。


1
在不同的正则表达式解释中,这也表现良好。
Phil Bennett

5
这节省了我的理智。在正则表达式实现.NET的“(。*?)”没有收到预期的效果(但不作为非贪婪),但“([^”] *)”一样。
延斯·纽鲍尔

这是imo的最佳答案。谢谢
Lmao 123

28

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

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

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

显然,要处理没有平衡引号的字符串,可以改用所有格修饰符:[^"\\]*+(?:\\.[^"\\]*)*+或一种变通方法来模仿它们,以防止回溯过多。您也可以选择将加引号的部分用作下一个引号,直到下一个(非转义)引号或字符串的结尾为止。在这种情况下,无需使用所有格修饰符,只需将最后一个引号设为可选。

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

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

Perl喜欢:

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

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

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

ECMA脚本:

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

POSIX扩展:

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

或者简单地:

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

1
Python接受原始字符串格式的ECMA脚本,即r“”“ ECMA脚本”“”
2015年1

1
这太妙了,很容易使您的ECMA适应转义新行和双引号内的回车符。
Douglas Gaskell

@ douglasg14b:谢谢。请注意,如果要在Javascript中使用它,则只需要使用文字符号/pattern/而不转义任何内容(而不是对象符号new RegExp("(?=[\"'])(?:\"[^\"\\\\]*...");
Casimir et Hippolyte

@ a1an:是的,但是如果您删除了shere:(?s:并且(?s)在模式中的某个位置,则可以使用Perl版本。
Casimir et Hippolyte

16

接受的答案的RegEx返回值,包括其环绕引号:"Foo Bar""Another Value"作为匹配项。

这是RegEx,仅返回引号之间(如发问者所要求的):

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

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

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

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

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

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

--

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


拜托,为什么这行得通?我正在使用,src="(.*)"但显然它选择了最后一个“”之前的所有内容,但是您的REGEX只选择了src =“”内容,但我不知道如何?
Lucas Bustamante

我很喜欢这个,因为它很简单,但是正如我发现的那样,它不能很好地处理引号之间的空值或空值
RedactedProfile

16

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

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

有关示例,请参见此演示https://regex101.com/r/Hbj8aP/1

此处的关键是开始处的正向后视(?<=)和结束处的正向前视(?=)。向后看是在当前字符后方检查报价,如果找到,则从那里开始,然后向前看,检查前面的字符以获取报价,如果找到则停止在该字符上。后面的组(["'])括在方括号中,以创建一个针对在开头找到的引用的组,然后在结尾处使用该组,以(?=\1)确保仅在找到相应的引用时才停止。

唯一的其他复杂性是,由于前瞻实际上并没有消耗结束引号,因此将通过后面的开始查找再次找到它,这将导致同一行的结束和开始引号之间的文本匹配。在开头的引号(["']\b)上放置单词边界可以帮助解决此问题,尽管理想情况下,我希望超越前瞻性,但我认为这是不可能的。我直接从亚当的答案中得到了一点,让中间出现了转义字符。



8

(["'])(?:(?=(\\?))\2.)*?\1上面的模式可以完成工作,但我担心它的性能(虽然不错,但可能会更好)。低于它的矿井快20%。

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

例如,它不能捕获很多字符串(如果需要,我可以提供一个详尽的测试用例),如下所示:

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

它们的其余部分与上面的那些一样“好”。

如果您确实关心性能和精度,那么请从以下内容开始:

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

在我的测试中,它涵盖了我遇到的每个字符串,但是如果您发现不起作用的内容,我会很乐意为您更新。

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


1
我喜欢您的模式的简单性,但是性能方面的Casimir et Hippolyte的模式将所有扩展的解决方案从水中吹了出来。此外,您的模式似乎在扩展大写情况时遇到了问题,例如句子结尾处的转义引号。
wp78de

7

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

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

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

演示(带有更多测试用例;可以随时使用它并对其进行扩展)。


PS:如果您只想在完全匹配()中的引号之间包含内容$0,并且不担心使用性能下降,请使用:

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

不幸的是,没有引号作为锚,我不得不\b在起始引号之后添加一个边界,该边界不能很好地与空格和非单词边界字符配合使用。

或者,只需添加一个组并提取字符串形式$2,即可修改初始版本:

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

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


观察:第二个正则表达式会错过带有负号的值-,例如在经度坐标中。
Crowcoder,

我什么都没改变。如果您没有发现问题,那可能就是我使用的正则表达式的味道。我使用的是regex101site,我认为是php样式的regex。
Crowcoder,

这是我正在谈论的演示。我期望它与经度(-96.74025)相匹配,但事实并非如此。
Crowcoder,

@Crowcoder谢谢。是的,这是由字边界引起的,该字边界起锚点的作用,有助于避免匹配重叠,但对您的输入效果不佳。如更新的答案中所述,附加组实际上是更好的选择。
wp78de

6

这个版本

  • 转义报价的帐户
  • 控制回溯

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

这跨越多个字符串,并且似乎不能正确处理双反斜杠,例如字符串: foo'stri \\ ng 1'bar'string
miracle2k

您不能在字符类中使用反向引用。
HamZa 2014年

5

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

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

TLDR;
将单词图标替换为您在引号中看到的内容,瞧!


它的工作方式是它查找关键字,而不关心引号之间的其他内容。EG:
id="fb-icon"
id="icon-close"
id="large-icon-close"
正则表达式先查找引号,"
然后再查找"
直到找到的icon
所有可能的字母组,"
然后再查找不存在的所有可能的字母组"


1
非常感谢你。能够用替换每次出现的name="value"name={"value"}因为此答案的正则表达式返回icon/ value作为第二组(与接受的答案不同)。找到=\"([^\"]*?[^\"]*?)\" 更换={"$1"}
Palisand

介意解释反对票?在某些情况下它运作良好。
詹姆斯·哈灵顿'18

你在回复我吗?
帕里桑德18'July

@Palisand前几天没有人不加解释地拒绝了这篇文章。
詹姆斯·哈灵顿

这似乎是在引号内找到特定文本的唯一答案
Top-Master

4

我喜欢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

3
string = "\" foo bar\" \"loloo\""
print re.findall(r'"(.*?)"',string)

只是尝试一下,就像一个魅力!

\ 表示跳过字符


如果第一行是实际的Python代码,它将创建string " foo bar" "loloo"。我怀疑您打算像使用regex:一样将其包装在原始字符串中r'"\" foo bar\" \"loloo\""'。请在适当的时候利用SO出色的格式化功能。不只是化妆品 如果您不使用它们,我们几乎无法说出您要说的话。欢迎使用Stack Overflow
艾伦·摩尔

感谢alan的建议,我实际上是这个社区的新手,下次我一定会牢记所有这些……真诚的歉意。
mobman 2014年

2

与亚当的答案不同,我有一个简单但可行的方法:

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

如果您想获得这样的引号中的内容,只需添加括号即可:

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

然后$1匹配报价char和$2匹配内容字符串。


1
echo 'junk "Foo Bar" not empty one "" this "but this" and this neither' | sed 's/[^\"]*\"\([^\"]*\)\"[^\"]*/>\1</g'

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

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


1

从Greg H.开始,我能够创建此正则表达式来满足我的需要。

我需要匹配一个用引号引起来的特定值。它必须是完全匹配,任何部分匹配都不能触发匹配

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

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

猎人


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"


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


0

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

如果您是Node用户,则可能需要支持所有unicode字符的接受答案的修改版本:

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

试试这里


1
什么是非Unicode字符?AFAIK unicode涵盖所有字符。
多托

1
为什么您认为这是一个JavaScript问题?而且,并非所有浏览器都支持lookbehind,regex101引发? The preceding token is not quantifiable
Toto

@Toto,我的意思是“不支持所有的unicode字符”。谢谢。尽管问题通常是关于正则表达式的,但我只是不想强调单词边界声明的使用会在Javascript中引起不良行为。当然,虽然Javascript通常用于浏览器,但也有Node。
Donovan P
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.