在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.searchdevise如此:

 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式。

posendpos历史

看起来pos的奇怪的“实际上并不是开始 – 开始的位置”的含义和参数本身一样古老:

  • Python 1.4的match 函数文档 (1996年10月25日 – 可能预先约会正则expression式对象)根本不显示posendpos参数。

  • Python 1.5 match 方法文档 (1998年2月17日)引入了正则expression式对象和posendpos参数。 它指出, ^ 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的实际开始处