我希望能够将字符串文字与转义引用选项匹配.例如,我希望能够搜索"这是一个'转换''值'确定'的测试"并让它正确识别反斜杠作为转义字符.我尝试过如下解决方案:
import re regexc = re.compile(r"\'(.*?)(?看了这个之后,有一个简单的问题,即使用的转义字符"
\
"不能自行转义.我无法弄清楚如何做到这一点.我想要一个类似下面的解决方案,但负面的lookbehind断言需要固定长度:# ... re.compile(r"\'(.*?)(?任何正则表达式大师都能解决这个问题吗?谢谢.
1> ridgerunner..:re_single_quote = r"
'[^'\\]*(?:\\.[^'\\]*)*'"
首先请注意,MizardX的答案是100%准确的.我想补充一些关于效率的额外建议.其次,我想注意这个问题很久以前就已经解决和优化了 - 请参阅:掌握正则表达式(第3版),(非常详细地介绍了这个特定问题 - 强烈推荐).
首先让我们看一下子表达式,以匹配单个带引号的字符串,该字符串可能包含转义的单引号.如果你打算允许转义单引号,你最好至少允许转义转义(这是Douglas Leeder的回答).但是,只要你在它,它同样容易逃脱任何其他东西.有了这些要求.MizardX是唯一一个表达正确的人.这里有短格式和长格式(我已经自由地在
VERBOSE
模式中编写了这个,有很多描述性的注释 - 你应该总是为非平凡的正则表达式做):# MizardX's correct regex to match single quoted string: re_sq_short = r"'((?:\\.|[^\\'])*)'" re_sq_long = r""" ' # Literal opening quote ( # Capture group $1: Contents. (?: # Group for contents alternatives \\. # Either escaped anything | [^\\'] # or one non-quote, non-escape. )* # Zero or more contents alternatives. ) # End $1: Contents. ' """
这适用于所有以下字符串测试用例并正确匹配:
text01 = r"out1 'escaped-escape: \\ ' out2" test02 = r"out1 'escaped-quote: \' ' out2" test03 = r"out1 'escaped-anything: \X ' out2" test04 = r"out1 'two escaped escapes: \\\\ ' out2" test05 = r"out1 'escaped-quote at end: \'' out2" test06 = r"out1 'escaped-escape at end: \\' out2"
好的,现在让我们开始对此进行改进.首先,替代方案的顺序有所不同,应始终首先考虑最可能的替代方案.在这种情况下,非转义字符比转义字符更可能,因此反转顺序将略微提高正则表达式的效率:
# Better regex to match single quoted string: re_sq_short = r"'((?:[^\\']|\\.)*)'" re_sq_long = r""" ' # Literal opening quote ( # $1: Contents. (?: # Group for contents alternatives [^\\'] # Either a non-quote, non-escape, | \\. # or an escaped anything. )* # Zero or more contents alternatives. ) # End $1: Contents. ' """
"开卷环仿真":
这稍微好一些,但可以通过应用Jeffrey Friedl的"展开循环"效率技术(来自MRE3)进一步改进(显着).上面的正则表达式不是最优的,因为它必须将星形量化器精心地应用于两个备选方案的非捕获组,每个备选方案一次仅消耗一个或两个字符.通过认识到一遍又一遍地重复相似的模式,可以完全消除这种交替,并且可以制作等效的表达式来做同样的事情而无需交替.这是一个优化的表达式,用于匹配单个带引号的字符串并将其内容捕获到组中
$1
:# Better regex to match single quoted string: re_sq_short = r"'([^'\\]*(?:\\.[^'\\]*)*)'" re_sq_long = r""" ' # Literal opening quote ( # $1: Contents. [^'\\]* # {normal*} Zero or more non-', non-escapes. (?: # Group for {(special normal*)*} construct. \\. # {special} Escaped anything. [^'\\]* # More {normal*}. )* # Finish up {(special normal*)*} construct. ) # End $1: Contents. ' """
这个表达式在一个"gulp"中吞噬了所有非引号,非反斜杠(绝大多数大多数字符串),这大大减少了正则表达式引擎必须执行的工作量.你问多少钱?好吧,我将从这个问题中提出的每个正则表达式输入到RegexBuddy中,并测量了正则表达式引擎在以下字符串上完成匹配所采取的步骤(所有解决方案都正确匹配):
'This is an example string which contains one \'internally quoted\' string.'
以下是上述测试字符串的基准测试结果:
r""" AUTHOR SINGLE-QUOTE REGEX STEPS TO: MATCH NON-MATCH Evan Fosmark '(.*?)(?
这些步骤是使用RegexBuddy调试器函数匹配测试字符串所需的步骤数."NON-MATCH"列是从测试字符串中删除结束引号时声明匹配失败所需的步骤数.如您所见,对于匹配和不匹配的情况,差异很大.另请注意,这些效率改进仅适用于使用回溯的NFA引擎(即Perl,PHP,Java,Python,Javascript,.NET,Ruby和其他大多数.)DFA引擎不会通过此技术获得任何性能提升(请参阅:正则表达式匹配可以简单快速).
到完整的解决方案:
原始问题(我的解释)的目标是从较大的字符串中挑选出单引号子字符串(可能包含转义引号).如果已知引用的子字符串之外的文本将永远不会包含转义单引号,则上面的正则表达式将完成这项工作.但是,要正确匹配文本游泳海洋中的单引号子字符串与转义引号和转义转义符和转义符号(这是我对作者所追求的解释),
需要从头开始解析字符串No,(这是我最初的想法),但它没有 - 这可以使用MizardX非常聪明的(?表达来实现.以下是一些练习各种解决方案的测试字符串:
text01 = r"out1 'escaped-escape: \\ ' out2" test02 = r"out1 'escaped-quote: \' ' out2" test03 = r"out1 'escaped-anything: \X ' out2" test04 = r"out1 'two escaped escapes: \\\\ ' out2" test05 = r"out1 'escaped-quote at end: \'' out2" test06 = r"out1 'escaped-escape at end: \\' out2" test07 = r"out1 'str1' out2 'str2' out2" test08 = r"out1 \' 'str1' out2 'str2' out2" test09 = r"out1 \\\' 'str1' out2 'str2' out2" test10 = r"out1 \\ 'str1' out2 'str2' out2" test11 = r"out1 \\\\ 'str1' out2 'str2' out2" test12 = r"out1 \\'str1' out2 'str2' out2" test13 = r"out1 \\\\'str1' out2 'str2' out2" test14 = r"out1 'str1''str2''str3' out2"
鉴于此测试数据,让我们看看各种解决方案的表现如何('p'== pass,'XX'==失败):
r""" AUTHOR/REGEX 01 02 03 04 05 06 07 08 09 10 11 12 13 14 Douglas Leeder p p XX p p p p p p p p XX XX XX r"(?:^|[^\\])'(([^\\']|\\'|\\\\)*)'" cletus/PEZ p p p p p XX p p p p p XX XX XX r"(?
一个有效的测试脚本:
import re data_list = [ r"out1 'escaped-escape: \\ ' out2", r"out1 'escaped-quote: \' ' out2", r"out1 'escaped-anything: \X ' out2", r"out1 'two escaped escapes: \\\\ ' out2", r"out1 'escaped-quote at end: \'' out2", r"out1 'escaped-escape at end: \\' out2", r"out1 'str1' out2 'str2' out2", r"out1 \' 'str1' out2 'str2' out2", r"out1 \\\' 'str1' out2 'str2' out2", r"out1 \\ 'str1' out2 'str2' out2", r"out1 \\\\ 'str1' out2 'str2' out2", r"out1 \\'str1' out2 'str2' out2", r"out1 \\\\'str1' out2 'str2' out2", r"out1 'str1''str2''str3' out2", ] regex = re.compile( r"""(? 唷!
ps感谢MizardX的非常酷的
(?表达.每天学些新东西!
2> Douglas Leed..:我认为这会奏效:
import re regexc = re.compile(r"(?:^|[^\\])'(([^\\']|\\'|\\\\)*)'") def check(test, base, target): match = regexc.search(base) assert match is not None, test+": regex didn't match for "+base assert match.group(1) == target, test+": "+target+" not found in "+base print "test %s passed"%test check("Empty","''","") check("single escape1", r""" Example: 'Foo \' Bar' End. """,r"Foo \' Bar") check("single escape2", r"""'\''""",r"\'") check("double escape",r""" Example2: 'Foo \\' End. """,r"Foo \\") check("First quote escaped",r"not matched\''a'","a") check("First quote escaped beginning",r"\''a'","a")正则表达式
r"(?:^|[^\\])'(([^\\']|\\'|\\\\)*)'"
仅向前匹配字符串中我们想要的内容:
不反斜或引用的字符.
逃脱报价
逃避反斜杠
编辑:
在前面添加额外的正则表达式以检查转义的第一个报价.