编辑:我可能已经解决了我的问题,使用一个消极的向后看,但我担心我只是偶然发现了一个特殊的情况下,这一工作,或b)有它~正确,但非常stilted/低效。非常感谢任何反馈,我真的很想知道为什么原来的模式不起作用。下面是现在似乎正在工作的正则表达式模式:qtD = re.compile('qt[^cy].*?(?<!\<|\>|\d)(\d{3})(?:\D|$)', re.I)
以下是原始消息:
我试图在Python(3.2)中使用标准正则表达式包re来完成以下操作。这看起来不应该很复杂,但我不知道出了什么问题。
下面是一个示例字符串:s = 'EKG done this AM with QT 560 and QTC wnl at 535ms, higher than on exam performed 5/3/2015 which showed...
在本例中,我试图通过re.findall()
返回的只是数字'560'-也就是说,在'QT'之后的某个时刻出现的第一个数字,并且是一个3位整数。
下面是我目前使用的正则表达式模式:qtD = re.compile('qt[^cy].*?[^\<\>\d](\d{3})(?:\D|$)', re.I)
所以,基本上:
- 查找QT(但不是QTC或QTY)
- 。。。后面可能跟任意数量的字符
- ...并返回找到的前3位整数(\d {3})
- ...但仅当该3位整数前面不紧接“<”、“>”或其他数字时
- ...并且紧跟行尾$或非数字\D
我是这样搜索的:re.findall(qtD, s)
上面的工作很好,但只有在'QT'和数字之间有一个长度至少为2的字符串(字符或空格)的情况下。换句话说,“QT560”返回560。“QT间期在560处正常”返回560。“QT:560”返回560。
但是,如果字符串如上所示,“... QT 560...”,那么正则表达式将继续读取并返回下一个3位数,535。
我尝试过其他的方法,比如让[^\<\>\d]
变懒,比如[^\<\>\d]?
,或者重复0或1次[^\<\>\d]{0,1}
,但是如果它没有找到任何3位数之前的数字,比如560和535,那么它就会开始做一些事情,比如返回2015年5月3日的“015”,在这种情况下,我希望返回一个空列表。
谢谢你的帮助。
2条答案
按热度按时间r1zk6ea11#
在您的模式中,您至少匹配2个字符
[^cy]
和[^\<\>\d]
相反,你可以使用2个lookaroundAssert:
模式匹配:
\bqt
防止部分字匹配的字边界,然后匹配qt
(?![cy])
负向前看,不直接向右侧Assertc
或y
.*?
匹配任何字符,尽可能少(?<![\d<>])
负向后查找,不向左Assert数字或<
或>
(\d{3})
捕获组1中的3位数字(由re.findall返回)(?:\D|$)
匹配非数字或Assert字符串的结尾Regex demo
这也将匹配
QT560
中的560
后面可能跟有任意数量的字符
或者先匹配3个数字,然后是lookbehindAssert:
Regex demo
iszxjhcz2#
一般来说,问题就出在这一节
在
qt
和\d[3]
之间至少需要2个字符而这个
在
qt
和\d[3]
之间至少需要1个字符由于
QT 560
之间只有一个字符,因此此正则表达式qt[^cy].*?[^<>\d](\d{3})(?:\D|$)
将仅与QT 560 and QTC wnl at 535m
匹配在示例字符串中,其中
535
在捕获组1中。如果在
QT 560
之间添加另一个空格,则可以看到此结果https://regex101.com/r/yMMjtD/1
这可能更好地解决问题,或类似
qt(?![cy]).+?(?<![<>\d])(\d{3})(?:\D|$)
https://regex101.com/r/JjB7kL/1