RegEx:在引号之间抓取值

dea*_*bug 206 regex

我有这样的价值:

"Foo Bar" "Another Value" something else
Run Code Online (Sandbox Code Playgroud)

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

Ada*_*dam 329

我一直在使用以下成功:

(["'])(?:(?=(\\?))\2.)*?\1
Run Code Online (Sandbox Code Playgroud)

它也支持嵌套引号.

对于那些想要更深入解释其工作原理的人来说,这是用户ephemient的解释:

([""'])匹配报价; ((?=(\\?))\2.)如果存在反斜杠,则吞噬它,以及是否发生这种情况,匹配一个角色; *?匹配很多次(非贪婪,不吃关闭报价); \1匹配用于打开的相同引用.

  • 这也有效:`(["'])(\\ ?.)*?\ 1`更容易阅读. (43认同)
  • @steve:这也会错误地匹配"foo".前瞻性技巧使```量词占有欲(即使正则表达式不支持`?+`语法或原子分组) (6认同)
  • 这将返回包括匹配引号的值.根据要求,是否没有机会只返回引号之间的**内容? (5认同)
  • 使用命名变量的版本: `((?<openingQuote>["'])(?<contents>(?:(?=(?<escapedContent>\\?))(?P=escapedContent).)*?) (?P=开头语))` (4认同)
  • 对于 python,这会引发错误: sre_constants.error: 无法引用开放组 (2认同)
  • 将前瞻性作为所有格量词完全没有必要且令人困惑。只需使用替代:`([“”])(?:\\。| [^^ \])*?\ 1` (2认同)
  • 如何避免空字符串? (2认同)
  • 其修改版本仅匹配引号之间的内容,不包括引号本身: `(?<=(["']))(?:(?=(\\?))\2.)*?(? =\1)` (2认同)
  • 对于 Python 人员来说: `re.compile(r'(["\'])((?:\\.|[^\\])*?)(\1)').findall(data)`。已添加几个括号才能工作。从每个元组中取出第二项。 (2认同)

Gre*_*ill 297

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

"(.*?)"
Run Code Online (Sandbox Code Playgroud)

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

在Python中,您可以这样做:

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

  • 这很好,但它不处理带有转义引号的字符串.例如,"你好"世界"` (9认同)
  • 谢谢 - 如果您确定没有要处理的转义引号,这会更简单。 (4认同)
  • @robbyt我知道答案有点晚了,但负面的背后呢?' "(.*?(?<!\\))"` (2认同)

Mar*_*ork 80

我会去:

"([^"]*)"
Run Code Online (Sandbox Code Playgroud)

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

  • 这节省了我的理智.在.NET的RegEx实现中,"(.*?)"没有所需的效果(它不起作用非贪婪),但"([^"]*)"确实如此. (5认同)
  • 这在不同的正则表达式解释中也表现良好。 (3认同)

Cas*_*yte 25

让我们看看两种处理转义报价的有效方法.这些图案不是简洁而美观,而是高效.

这些方法使用第一个字符区分来快速查找字符串中的引号,而无需更改成本.(这个想法是在没有测试交替的两个分支的情况下快速丢弃不是引号的字符.)

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

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

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

模式避免使用捕获组和反向引用(我的意思是类似(["']).....\1)并使用简单的交替,但["']在开头,使用因子.

Perl喜欢:

["'](?:(?<=")[^"\\]*(?s:\\.[^"\\]*)*"|(?<=')[^'\\]*(?s:\\.[^'\\]*)*')
Run Code Online (Sandbox Code Playgroud)

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

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

ECMA脚本:

(?=["'])(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]*(?:\\[\s\S][^'\\]*)*')
Run Code Online (Sandbox Code Playgroud)

POSIX扩展:

"[^"\\]*(\\(.|\n)[^"\\]*)*"|'[^'\\]*(\\(.|\n)[^'\\]*)*'
Run Code Online (Sandbox Code Playgroud)

或者干脆:

"([^"\\]|\\.|\\\n)*"|'([^'\\]|\\.|\\\n)*'
Run Code Online (Sandbox Code Playgroud)

  • 这太棒了,很容易使您的 ECMA 能够在双引号内转义换行符和回车符。 (2认同)
  • @GwynethLlewelyn:由于 RE2 不是回溯引擎,因此您可以简单地编写 `"(?s:[^\\"]|\\.)*"|'(?s:[^\\']|\\ .)*'`。 (2认同)

Iri*_*Guy 15

特别是,这些答案都没有产生正则表达式,其中返回的匹配是引号内的文本,这就是要求的内容.MA-Madden尝试但仅将内线比赛作为一个被捕获的组而不是整场比赛.实际做到这一点的一种方法是:

(?<=(["']\b))(?:(?=(\\?))\2.)*?(?=\1)
Run Code Online (Sandbox Code Playgroud)

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

这里的关键是开始时的正面观察(the ?<=)和结束时的正向前瞻(the ?=).lookbehind正在查看当前字符后面以检查引用,如果找到则从那里开始,然后前瞻是检查前面的字符以获得引用,如果发现该字符停止.将lookbehind组(the ["'])包装在括号中以创建一个组,以便在开始时找到任何引用,然后在最后预测(?=\1)时使用它以确保它只在找到相应的引用时停止.

唯一的另一个困难是因为超前,实际上并不消耗最终报价,将再次开始回顾后引起结束和开始在同一线路报价进行匹配之间的文本中.在开头引号(["']\b)上加上一个单词边界有助于此,虽然理想情况下我想要超越前瞻但我不认为这是可能的.这个位允许中间的逃脱角色我直接从亚当的回答中获取.

  • 引号后空格错误,例如 https://regex101.com/r/ohlchh/1 (2认同)

Mar*_*der 10

接受的答案的RegEx返回值,包括其周围的引号:"Foo Bar""Another Value"匹配.

这里是RegEx,只返回引号之间(正如提问者所要求的):

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

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

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

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

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

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

-

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

  • 我非常喜欢这个,因为它很简单,但正如我发现的那样,它不能很好地处理引号之间的空值或无值 (2认同)

wp7*_*8de 10

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

(['"])(?:(?!\1|\\).|\\.)*\1
Run Code Online (Sandbox Code Playgroud)

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

演示(有更多的测试用例;随意使用它并对其进行扩展)。


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

(?<=(['"])\b)(?:(?!\1|\\).|\\.)*(?=\1)
Run Code Online (Sandbox Code Playgroud)

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

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

(['"])((?:(?!\1|\\).|\\.)*)\1
Run Code Online (Sandbox Code Playgroud)

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


Axe*_*man 6

这个版本


Eug*_*scu 6

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

这种模式"(.*?)"不完整.我对每个读这篇文章的建议就是不要使用它!

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

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

剩下的就像上面那样"好".

如果你真的关心性能和精度,那么从下面开始:

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

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

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

  • 我喜欢你的模式的简单性,但是性能方面的 Casimir et Hippolyte 的模式将所有扩展的解决方案都吹了出来。此外,看起来您的模式在扩展边缘情况下存在问题,例如句子末尾的转义引号。 (2认同)

mir*_*e2k 5

我喜欢 Axeman 的更广阔的版本,但遇到了一些麻烦(例如它不匹配

foo "string \\ string" bar
Run Code Online (Sandbox Code Playgroud)

或者

foo "string1"   bar   "string2"
Run Code Online (Sandbox Code Playgroud)

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

# 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
Run Code Online (Sandbox Code Playgroud)


小智 5

string = "\" foo bar\" \"loloo\""
print re.findall(r'"(.*?)"',string)
Run Code Online (Sandbox Code Playgroud)

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

\表示跳过字符


Jam*_*ton 5

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

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

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


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


nov*_*ice 5

我的解决方案如下

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

演示链接: https: //regex101.com/r/jlhQhV/1

解释:

(["'])-> 匹配 or'并在找到匹配后将"其存储在反向引用中\1

.*-> 贪婪方法继续匹配所有内容零次或多次,直到遇到字符串'"字符串末尾。遇到这种状态后,正则表达式引擎回溯到上一个匹配字符,此时正则表达式结束,并将移至下一个正则表达式。

\1-> 匹配之前与第一个捕获组匹配的字符或字符串。

(?![^\s])-> 负向前视以确保上一个匹配之后不应该有任何非空格字符