Python regex get在模式中出现次数为零或更多

2024-04-24 20:08:11 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个工作的正则表达式,它给了我想要的结果,但它不包含它需要的安全性。(防傻)

假设我有一个匹配路径部分的regex,大致如下:

import re
path = "C:/Projects/foo/dev/model/props/furniture/couch/data/fbx"
regex = re.compile("(.+)/dev/model/(.+)/(.+)/data/fbx")
m = regex.search(path)
if m:
    print m.groups()

# ('C:/Projects/foo', 'props/furniture', 'couch')

我希望能够替换匹配任何字符,直到regex的以下部分与一个或多个文件夹匹配。

假设为了简单起见,我们将文件夹定义为以斜线结尾的单词字符(一个或多个):

[\w]*/

我想把这些归为0到10组,我该怎么做?

在我的脑海里我有这样的想法(注意,这不起作用!)以下内容:

# match any number of word characters ending with a slash zero to ten times
([[\w]*/]{0,10})

# match any number of word characters ending with a slash zero to one time
([[\w]*/]?)

编辑:

根据RedBaron和jamylak的回答,我得出了以下结论:

((?:[:\w]+/){0,3})

这将把零到三个出现的字符组合成以斜线“/”结尾的[:\w]字符。和那个?:在组的开头,它不会被发送回匹配的组。所以,结合它们的外群是。因此我们只能得到完全分组的结果。

唯一的问题是我希望最后一部分也可能匹配一个文件。(所以不要以斜杠结尾)我甚至更喜欢从正则表达式中去掉尾部斜杠,但是我也可以很容易地去掉结果末尾的斜杠。

任何反馈都非常感谢。如果是这样的话,我会加上它作为答案。

编辑:

它与Finding folders back based on a predefined folder structure有关

更新/编辑:

基于目前给出的所有答案,我已经做了各种尝试,但最终都以极其缓慢的速度结束。

import re
path = "C:/Projects/foo/dev/model/props/furniture/couch/data/fbx"
regex = re.compile(r"""((?:^(?:[\w:]+/?)+)|(?:(?<=/)(?:[\w]+/?)+))/dev/model/""")
print 'search start'
m = regex.search(path)
print 'search done'
if m:
    print 'match', m, m.groups()
else:
    print 'no match'

我不知道怎么加快速度!


Tags: pathdevresearchdatamodelfoomatch
3条回答

regexp中的[]不会对regexp进行分组。它用于指定字符类。

也许这会奏效-

\w*/{0,10}

对于分组,只需使用()

(\w*/){0,10}

编辑

基于您编辑的问题,我认为您需要的是0-3次目录名匹配,然后一个文件名也匹配。

假设文件名中只有字母(并且可选的扩展名不超过三个字符)

^((?:[:\w]+/){0,3})(\w+(?:\.\w{1,3})?)?$

这个很大,但可以分成两部分

这是你已经有的

((?:[:\w]+/){0,3})

还有我要补充的

(\w+(?:\.\w{1,3})?)?

这是结尾的可选文件名。(如果不是可选的,可以删除最后一个?)。文件名本身可以只由字母组成,也可以有最多3个字符的扩展名

添加^$将停止虚假匹配

>>> pat=re.compile('^((?:[:\w]+/){0,3})(\w+(?:\.\w{1,3})?)?$')
>>> my_str='fwefw/wfwf/wefwf/dde.cdf'
>>> pat.search(my_str).groups()
('fwefw/wfwf/wefwf/', 'dde.cdf')
>>> my_str='fwefw/dde.cdf'
>>> pat.search(my_str).groups()
('fwefw/', 'dde.cdf')

相反,由于catastrophic backtracking的原因,这个过程非常缓慢

((?:^(?:[\w:]+/?)+)|(?:(?<=/)(?:[\w]+/?)+))/dev/model/

试试这个

(^[\w:]+(?:/\w+)*|(?<=/)\w+(?:/\w+)*)/dev/model/

或者这个

(^[\w:]+[\w/]*|(?<=/)[\w/]+)/dev/model/

您可能需要考虑一种方法,首先使用re.match(\w:)?(/\w+)+$等模式验证字符串

然后,当您已经可以期望某个结构时,可以使用更简单的regex来提取数据:

/?([^/]*(?:/[^/]+)*)/dev/model/

你不能像这里那样把[]放在[]里面。相反,你想用括号来分组。

试试这个:

>>> re.match(r'(\w*/){0,10}', 'abc/def/ghi/').group()
'abc/def/ghi/'

相关问题 更多 >