使用re/search的开始/结束参数时,正则表达式中$和^之间的不一致性?

bgu*_*t3r 36 python regex

从我读过的,^应该匹配字符串的开头和$结束.然而,re.search()看起来,行为^继续正常,而$"休息".例:

>>> a = re.compile( "^a" )
>>> print a.search( "cat", 1, 3 )
None
Run Code Online (Sandbox Code Playgroud)

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

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

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

re模块上的文档明确提到^由于开始/结束参数re.search而没有改变行为,但是$(我见过)没有提到行为的改变.

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

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

为什么re.search设计成:

s.search( string, endPos=len(string) - 1 )
Run Code Online (Sandbox Code Playgroud)

是相同的

s.search( string[:-1] )
Run Code Online (Sandbox Code Playgroud)

什么时候

s.search( string, startPos=1 )
Run Code Online (Sandbox Code Playgroud)

显然和故意不一样

s.search( string[1:] )
Run Code Online (Sandbox Code Playgroud)

这似乎是不太不一致的问题^,并$和更多内的不一致的re.search功能.

Gre*_*ers 28

根据这里search()文件:

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

所以你的语法a.search("cat", 0, 2)相当于a.search("ca"),它与模式匹配a$.


cdl*_*ane 21

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

不,endpos解释与Python的其余部分一致,它是起始pos位置,如文档所解释的那样不一致:

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


Kev*_*ase 21

简答

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

6.2.1.正则表达式语法

\A 仅匹配字符串的开头.

\Z 仅匹配字符串末尾的匹配项.

警告一下 endpos

即使有人使用结束参数,这也不会起作用re.search.与"start"参数pos(仅标记起点)不同,endpos参数表示搜索(或匹配)仅在字符串的一部分上进行(强调添加):

6.2.3.正则表达式对象

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

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

\Z匹配字符串的结束被搜索,而这正是endpos改变.

背景

更熟悉^,$不做你认为他们做的事情:

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

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

Python的正则表达式受到Perl's的严重影响grep,它通过自己的主机扩展了旧的功能.这包括多行匹配,这提出了一个关于类似的元字符的问题^:是不是匹配的开始,或者一开始?当grep一次只匹配一行时,那些是等效的概念.

正如你所看到的,^$最终试图匹配所有"开始"和"结束".Perl引入了新的转义序列\A\z(小写)以匹配字符串的开头和字符串的结尾.

这些转义序列是由Python的通过,但有一点不同:Python中也没有采用Perl的\Z(大写),它相匹配的特殊情况,新行之前,结束串...使其既结束串和没有相当的合作伙伴\A是人们所期望的.

(我假设Python上层Perl是\z为了保持一致性,避免了'\Apattern\z'Perl Best Practices这样的书中推荐的不平衡的正则表达式.)

pos和的历史endpos

似乎奇怪的"实际上并不是起始位置"的含义pos与参数本身一样古老:

我怀疑在几个月的bug修复版本中对文档进行的大量更改反映了文档追赶现实 - 而不是对设计的更改match (尽管我没有Python 1来验证这一点).

python-dev邮件列表归档只回到1999年,因此,除非先前的消息被保存在其他地方,我想回答"为什么"的问题,就需要猜测谁写的代码,并要求他们.

  • @ bgutt3r:我添加了`pos`和`endpos`的一些历史记录...恐怕没有启发性。 (3认同)