在re.search中使用start / end参数时,在正则expression式中$和^之间的不一致?
从我读过的, ^
应该匹配一个string的开始, $
结束。 但是,使用re.search()
,看起来^
的行为继续正常工作,而$
'中断'。 例:
>>> a = re.compile( "^a" ) >>> print a.search( "cat", 1, 3 ) None
这对我来说似乎是正确的 – 即使是在search的开始, 'a'
不在string的开头。
>>> a = re.compile( "a$" ) >>> print a.search( "cat", 0, 2 ) <_sre.SRE_Match object at 0x7f41df2334a8>
这对我来说似乎是错误的,或至less是不一致的。
关于re
模块的文档明确提到^
的行为不会因为re.search
开始/结束参数而改变,但是没有提到$
(我见过)的行为改变。
任何人都可以解释为什么这样devise的东西,和/或build议一个方便的解决方法?
通过解决方法,我想编写一个总是匹配string结尾的正则expression式,即使有人使用re.search
的结尾参数。
为什么 re.search
devise如此:
s.search( string, endPos=len(string) - 1 )
是相同的
s.search( string[:-1] )
什么时候
s.search( string, startPos=1 )
明确和故意不一样的
s.search( string[1:] )
这似乎不是^
和$
之间不一致的问题,而是re.search
函数中更多不一致的问题。
简答
使用\A
到和\Z
匹配string的字面开始或结尾。 来自re
模块文档的相关行:
6.2.1。 正则expression式语法
\A
仅匹配string的开头。
\Z
仅匹配string的末尾。
警告关于endpos
即使有人使用re.search
的结尾参数,这也不起作用。 与刚刚标记起点的“start”参数pos
不同, endpos
参数意味着search(或匹配)仅在string的一部分上进行(添加了重点):
6.2.3。 正则expression式对象
regex.search(string[, pos[, endpos]]
)可选参数
endpos
限制string将被search多远; 它会像string是endpos
字符一样长 ,rx.search(string, 0, 50)
等价于rx.search(string[:50], 0)
。
\Z
匹配正在search的string的末尾,这正是endpos
变化的结果。
背景
更熟悉的^
和$
不会做你认为他们做的事情:
^
(插入符号)匹配string的开头,并且在MULTILINE
模式下,每个换行符之后也立即匹配。
$
匹配string的末尾或紧挨在string末尾的换行符之前,在MULTILINE
模式下也匹配换行符之前。foo
匹配'foo'和'foobar',而正则expression式foo$
只匹配'foo'。 更有趣的是,在'foo1\nfoo2\n'
中searchfoo.$
通常与'foo2'匹配,而在MULTILINE
模式下search'foo1' 在'foo\n'
search单个$
将会find两个(空的)匹配:一个在换行符之前,另一个在string末尾。
Python的正则expression式很大程度上受到Perl的影响,它使用它自己的主机扩展了旧的grep
能力。 这包括多行匹配,这提出了一个关于元字符的问题,比如^
:它是匹配string的开头,还是行的开头? 当grep
一次只匹配一行时,这些是相同的概念。
正如你所看到的, ^
和$
最终试图匹配“开始”和“结束”的一切。 Perl引入了新的转义序列\A
和\z
(小写),以仅匹配string的开始和string的结束。
这些转义序列被Python采用,但有一点不同:Python没有采用Perl的\Z
(大写),它匹配了string结尾和特殊情况下的新行结束string…使它不是那个人所期望的合作伙伴。
(为了保持一致性,我假定Python是高级Perl的\z
,避免了像Perl最佳实践这样的书中推荐的不正确的'\Apattern\z'
expression式。
pos
和endpos
历史
看起来pos
的奇怪的“实际上并不是开始 – 开始的位置”的含义和参数本身一样古老:
-
Python 1.4的
match
函数文档 (1996年10月25日 – 可能预先约会正则expression式对象)根本不显示pos
或endpos
参数。 -
Python 1.5
match
方法文档 (1998年2月17日)引入了正则expression式对象和pos
和endpos
参数。 它指出,^
将在pos
匹配 ,虽然后来的修订表明这是一个错字。 (说到拼写错误:^
字符本身就不存在了,它来了又去,直到在Python 2.1中最终重现为好(?))。 -
Python 1.5.1
match
方法文档 (1998年4月14日)插入缺less的“不”,颠倒了以前的文档。 -
Python 1.5.1p1
match
方法docs (1998年8月6日)阐明了pos
的意外效应。 它们匹配Python 3.6.1对pos
一词的描述…给予或采取那个讨厌的错字。
我怀疑在几个月的bug修复版本中对文档进行的大量修改反映了文档追赶现实 – 而不是改变match
的devise(尽pipe我没有用Python 1来validation)。
python-dev
邮件列表的存档只能追溯到1999年,所以除非先前的邮件保存在其他地方,否则我认为回答“为什么”这个问题需要猜测谁写了这个代码,并询问他们。
根据这里的search()
文档:
可选参数endpos限制string将被search多远; 就好像string是endpos字符一样长,所以只有从pos到endpos – 1的字符才会被search到匹配。
所以你的语法a.search("cat", 0, 2)
等同于a.search("ca")
,它与模式a$
匹配。
这对我来说似乎是错误的,或至less是不一致的。
不, endpos
解释与Python的其他部分是一致的,正如文档解释的那样,它的起始位置是不一致的 :
参数pos在search要开始的string中给出一个索引; 它默认为0.这不完全等同于切分string; '^'模式字符匹配string的实际开始处