当使用开始/结束参数re.search?

时间:2017-03-30 04:24:46

标签: python regex

根据我的阅读,^应该匹配字符串的开头,$结束。但是,对于re.search(),看起来^的行为仍然可以正常工作,而$'会中断'。例如:

>>> a = re.compile( "^a" )
>>> print a.search( "cat", 1, 3 )
None

这对我来说似乎是对的 - 'a'不在字符串的开头,即使它在搜索的开头。

>>> a = re.compile( "a$" )
>>> print a.search( "cat", 0, 2 )
<_sre.SRE_Match object at 0x7f41df2334a8>

这对我来说似乎不对,或至少不一致。

re模块上的文档明确提到^的行为不会因re.search的开始/结束参数而改变,但$的行为没有变化。 1}}(我见过)。

任何人都可以解释为什么事情是这样设计的,和/或建议一个方便的解决方法吗?

通过解决方法,我想编写一个始终匹配字符串结尾的正则表达式,即使有人使用结束参数re.search

为什么re.search设计为:

s.search( string, endPos=len(string) - 1 )

相同
s.search( string[:-1] )

s.search( string, startPos=1 )

明确且有意与

不同
s.search( string[1:] )

似乎不再是^$之间的不一致问题,而是re.search函数中的更多不一致问题。

3 个答案:

答案 0 :(得分:28)

根据search()文档here

  

可选参数endpos限制字符串的搜索范围;它就好像字符串是endpos字符长,所以只搜索pos到endpos - 1的字符才能匹配。

因此,您的语法a.search("cat", 0, 2)等同于a.search("ca"),它与模式a$匹配。

答案 1 :(得分:21)

  

这对我来说似乎不对,或至少不一致。

不,endpos解释与Python的其余部分一致,它是起始pos位置,与the documentation解释不一致:

  

参数pos在搜索所在的字符串中给出索引   开始;它默认为0.这不完全等同于切片   字符串; '^'模式字符匹配真正的开头   字符串

答案 2 :(得分:19)

简答

使用\A\Z匹配字符串的字面开头或结尾。 re模块的文档中的相关行:

  

6.2.1. Regular Expression Syntax

     

\A   仅在字符串的开头匹配。

     

\Z   仅匹配字符串末尾的匹配。

关于endpos

的警告

即使有人使用re.search&#34;的结束参数,也不会工作。 不像&#34; start&#34;参数pos,它只是标记一个起点,endpos参数意味着搜索(或匹配)将仅在字符串的一部分上进行(强调添加):

  

6.2.3. Regular Expression Objects

     

regex.search(string[, pos[, endpos]])

     

可选参数endpos限制字符串的搜索范围;   就好像字符串长度为endpos个字符,   [...]   rx.search(string, 0, 50)相当于rx.search(string[:50], 0)

\Z匹配正在搜索的字符串的结尾,这正是endpos更改的内容。

背景

比较熟悉的^$不做你认为他们做的事情:

  

^   (Caret。)匹配字符串的开头,并且在MULTILINE模式下也会在每个换行符后立即匹配。

     

$   匹配字符串的结尾或在字符串末尾的换行符之前,并且MULTILINE模式也匹配换行符之前。   foo匹配“foo”和“foo”。和&#39; foobar&#39;,而正则表达式foo$仅匹配&#39; foo&#39;。   更有趣的是,在foo.$匹配&#39; foo2&#39;中搜索'foo1\nfoo2\n'通常,但是&#39; foo1&#39;在MULTILINE模式下;   在$中搜索单个'foo\n'会找到两个(空)匹配:   一个就在换行符之前,另一个在换行符的末尾。

Python的正则表达式受到Perl的严重影响,它使用自己的主机扩展了旧的grep能力。 这包括多行匹配,这引发了有关像^这样的元字符的问题: 它是否匹配字符串的开头或的开头? 当grep一次只匹配一行时,那些是等效的概念。

正如您所看到的,^$最终试图匹配所有内容&#34;类似于#34;和#34; end-ish&#34;。 Perl引入了新的转义序列\A\z(小写)以匹配字符串的开头和字符串结尾。

这些转义序列被Python采用,但有一点不同: Python 采用Perl的\Z(大写),它匹配字符串结尾和特殊情况换行符 - 字符串结束前... 。 使完全成为\A的合作伙伴。

(我假设Python上层为Perl&#39; \z以保持一致性,避免了像 Perl最佳实践这样的书中推荐的不平衡的'\Apattern\z'正则表达式。)

posendpos

的历史记录

看起来奇怪的&#34;实际上不是开始 - 开始位置&#34; pos的含义与参数本身一样古老:

  • Python 1.4 match function docs(1996年10月25日---可能在正则表达式对象之前)根本不显示posendpos参数。< / p>

  • Python 1.5 match method docs(1998年2月17日)引入了正则表达式对象以及posendpos参数。 它声明 ^ 匹配pos ,但后来的修订表明这是一个错字。 (说到错别字: ^字符本身缺失。 它来了又去,直到最终在Python 2.1中重新出现(?)。)

  • Python 1.5.1 match method docs(1998年4月14日)插入缺失的&#34;而不是&#34;,撤销以前的文档。

  • Python 1.5.1p1 match method docs(1998年8月6日)澄清pos的意外影响。 它们匹配pos ^逐字逐句的Python 3.6.1's描述 给予或采取那个讨厌的match错字。

我怀疑在几个月的错误修复版本中对文档进行的大量更改反映了文档追赶现实 - 而不是对{{1}}设计的更改 (虽然我没有让Python 1来解决这个问题)。

python-dev mailing list archives只能追溯到1999年,所以除非先前的消息被保存在其他地方,否则我想回答&#34;为什么&#34;问题需要猜测是谁写了那些代码,然后问他们。