正则expression式:在引号之间抓取值
我有这样的价值:
"Foo Bar" "Another Value" something else
什么正则expression式将返回引号中包含的值(例如Foo Bar
和Another Value
)?
我一直在使用以下巨大的成功:
(["'])(?:(?=(\\?))\2.)*?\1
它也支持嵌套的引号。
对于那些想要更深入地解释这个如何工作的人来说,下面是用户ephemient的解释:
([""'])
匹配一个报价;((?=(\\?))\2.)
如果反斜杠存在,将其吞噬,并且是否发生这种情况,匹配一个字符;*?
匹配多次(非贪婪,至于不吃最后的报价);\1
匹配用于打开的相同报价。
一般来说,下面的正则expression式片段就是你正在寻找的东西:
"(.*?)"
这使用非贪婪*? 操作员捕捉所有内容,但不包括下一个双引号。 然后,您使用语言特定的机制来提取匹配的文本。
在Python中,你可以这样做:
>>> import re >>> string = '"Foo Bar" "Another Value"' >>> print re.findall(r'"(.*?)"', string) ['Foo Bar', 'Another Value']
我会去的:
"([^"]*)"
[^“]是除了” “之外的任何字符的正则expression式
我在非贪心许多操作符上使用这个的原因是,为了确保正确,我必须继续查找。
让我们看看处理转义报价的两种有效方法。 这些模式的devise不是简洁而不美观,而是高效。
这些方法使用第一个字符歧视来快速查找string中的引号,而不需要交替的成本。 (这个想法是在没有testing交替的两个分支的情况下快速丢弃不是引号的字符。)
引号之间的内容用一个展开的循环来描述(而不是重复的交替),以便更高效: [^"\\]*(?:\\.[^"\\]*)*
显然,要处理没有均衡引号的string,您可以使用所有格量词: [^"\\]*+(?:\\.[^"\\]*)*+
或者一个解决方法来模拟它们,防止回溯太多。 您也可以select引用的部分可以是开始引号,直到下一个(未转义的)引号或string结尾。 在这种情况下,不需要使用占有量词,只需要使最后一个引用是可选的。
注意:有时引号不会用反斜杠转义,而是重复引号。 在这种情况下,内容子模式看起来像这样: [^"]*(?:""[^"]*)*
模式避免使用捕获组和反向引用(我的意思是像(["']).....\1
),并使用一个简单的替代,但在开始时使用["']
,因子。
Perl像:
["'](?:(?<=")[^"\\]*(?s:\\.[^"\\]*)*"|(?<=')[^'\\]*(?s:\\.[^'\\]*)*')
(注意(?s:...)
是一个语法糖,用于打开非捕获组内的dotall / singleline模式。如果不支持此语法,则可以轻松地在所有模式中打开此模式,或者replace与[\s\S]
)
(这种模式写的方式完全是“手动的”,并没有考虑到最终的引擎内部优化)
ECMA脚本:
(?=["'])(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]*(?:\\[\s\S][^'\\]*)*')
POSIX扩展:
"[^"\\]*(\\(.|\n)[^"\\]*)*"|'[^'\\]*(\\(.|\n)[^'\\]*)*'
或者干脆:
"([^"\\]|\\.|\\\n)*"|'([^'\\]|\\.|\\\n)*'
这个版本
- 帐户逃脱报价
-
控制回溯
/(["'])((?:(?!\1)[^\\]|(?:\\\\)*\\[^\\])*)\1/
上面的模式(["'])(?:(?=(\\?))\2.)*?\1
做了这个工作,但是我担心它的performance(这不坏,但可能会更好)。低于它快20%。
模式"(.*?)"
只是不完整的。 我的build议,每个人阅读这只是不要使用它!
例如,它不能捕获许多string(如果需要,我可以提供一个详尽的testing用例),如下所示:
$ string ='你好吗? 我很好,谢谢你。
其余的和上面的一样“好”。
如果你真的关心性能和精度,那么从下面的开始:
/(['"])((\\\1|.)*?)\1/gm
在我的testing中,它覆盖了我遇到的每一个string,但是如果你发现一些不起作用的东西,我会很乐意为你更新它。
在线正则expression式testing中检查我的模式 。
我喜欢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
已接受答案的正则expression式返回值包括它们的引用引号: "Foo Bar"
和"Another Value"
作为匹配。
这里是RegEx,它只返回两个引号之间的值 (正如提问者所要求的那样):
仅双引号 (使用捕获组#1的值):
"(.*?[^\\])"
仅单引号 (使用捕获组#1的值):
'(.*?[^\\])'
两者 (使用捕获组#2的值):
(["'])(.*?[^\\])\1
–
所有的支持逃脱和嵌套报价。
更多答案! 这是我使用的解决scheme
\"([^\"]*?icon[^\"]*?)\"
TLDR;
用你在报价中寻找的单词replace图标 ,瞧!
它的工作方式是寻找关键字,并不在乎引号之间的其他内容。 例如:
id="fb-icon"
id="icon-close"
id="large-icon-close"
正则expression式寻找一个引号"
那么它寻找任何可能的一组字母那不是"
直到findicon
以及任何可能的不是"
然后它寻找一个closures"
Greg H.我能够创build这个正则expression式来满足我的需求。
我需要匹配一个特定的值,通过在报价中被限定。 它必须是一个完整的匹配,没有部分匹配可能会触发一个命中
例如“test”不能匹配“test2”。
reg = r"""(['"])(%s)\1""" if re.search(reg%(needle), haystack, re.IGNORECASE): print "winning..."
猎人
string = "\" foo bar\" \"loloo\"" print re.findall(r'"(.*?)"',string)
试试这个,就像一个魅力!
\
表示跳过字符
对我来说这是一个:
|([\'"])(.*?)\1|i
我用过这样一句话:
preg_match_all('|([\'"])(.*?)\1|i', $cont, $matches);
而且效果很好。
奇怪的是,这些答案都没有产生一个正则expression式,其中返回的匹配是引号内的文本,这就是要求的。 MA-Madden尝试,但只获得内部比赛作为一个被捕获的组,而不是整场比赛。 实际做到这一点的一个方法是:
(?<=(["']\b))(?:(?=(\\?))\2.)*?(?=\1)
这个例子可以在这个演示https://regex101.com/r/Hbj8aP/1中看到;
这里的关键是开始时的积极向后看( ?<=
)和结束时的积极向前看( ?=
)。 后视是看当前字符后面检查一个报价,如果find,然后从那里开始,然后向前检查字符提前报价,如果发现停止该字符。 lookbehind组( ["']
)用方括号括起来,以便在开始时发现引用中的任何引用,然后在结尾lookahead (?=\1)
处使用它,以确保只有当它find相应的报价。
唯一的另一个复杂因素是,因为前瞻并没有真正消耗结束引号,所以它将会被同样的行中结尾和开始引号之间的文本匹配。 在开头引号( ["']\b
)上加上一个单词边界是有帮助的,尽pipe理想情况下我想移过去,但是我不认为这是可能的。直接从亚当的回答中拿出来。
echo 'junk "Foo Bar" not empty one "" this "but this" and this neither' | sed 's/[^\"]*\"\([^\"]*\)\"[^\"]*/>\1</g'
这将导致:> Foo Bar <> <>,但是这个<
在这里,为了清楚起见,我在<>之间显示了结果string,在这个sed命令中也使用了非贪婪版本,我们首先在这个“”之前和之后扔掉垃圾,然后用“并且围绕这个> <的。