正则表达式匹配字符串中最后一次出现的年份
Regular expression match last occurence of year in string
我编写了一个 python 脚本,其中包含以下函数,它以包含多个日期的文件名作为输入。
代码
import re
from datetime import datetime
def ExtractReleaseYear(title):
rg = re.compile('.*?([\[\(]?((?:19[0-9]|20[01])[0-9])[\]\)]?)', re.IGNORECASE|re.DOTALL)
match = rg.search(title) # Using non-greedy match on filler
if match:
releaseYear = match.group(1)
try:
if int(releaseYear) >= 1900 and int(releaseYear) <= int(datetime.now().year) and int(releaseYear) <= 2099: # Film between 1900-2099
return releaseYear
except ValueError:
print("ERROR: The film year in the file name could not be converted to an integer for comparison.")
return ""
print(ExtractReleaseYear('2012.(2009).3D.1080p.BRRip.SBS.x264'))
print(ExtractReleaseYear('Into.The.Storm.2012.1080p.WEB-DL.AAC2.0.H264'))
print(ExtractReleaseYear('2001.A.Space.Odyssey.1968.1080p.WEB-DL.AAC2.0.H264'))
输出
Returned: 2012 -- I'd like this to be 2009 (i.e. last occurrence of year in string)
Returned: 2012 -- This is correct! (last occurrence of year is the first one, thus right)
Returned: 2001 -- I'd like this to be 1968 (i.e. last occurrence of year in string)
问题
可以看出,正则表达式将只针对一年中的第一次出现而不是最后一次出现。这是有问题的,因为有些标题(例如此处包含的标题)以年份开头。
在寻找获得年度最后一次出现的方法后,我找到了像 negative lookahead, and 、none 这样的资源,其中的 none 让我离实现预期的结果更近了一步。目前没有任何现有问题可以回答这个独特的案例。
预期结果
- 我想从给定的文件名中提取一年的最后一次出现(而不是第一次出现),并 return 它使用上面输出引用中所述的现有 definition/function 。
虽然我使用过在线 regex 参考资料,但我是 regex 的新手,如果有人向我展示如何实现此过滤器以处理上述文件名,我将不胜感激。伙计们干杯。
您需要更改两件事:
- 第一个
.*?
惰性模式必须转为贪婪模式 .*
(在这种情况下,.*
之后的子模式将匹配字符串中的最后一次出现)
- 您需要使用的组是组 2,而不是组 1(因为它是存储年份数据的组)。或者将第一个捕获组设为非捕获。
参见this demo:
rg = re.compile('.*([\[\(]?((?:19[0-9]|20[01])[0-9])[\]\)]?)', re.IGNORECASE|re.DOTALL)
...
releaseYear = match.group(2)
或:
rg = re.compile('.*(?:[\[\(]?((?:19[0-9]|20[01])[0-9])[\]\)]?)', re.IGNORECASE|re.DOTALL)
...
releaseYear = match.group(1)
考虑使用 findall() 而不是 search()?
它会将找到的所有值从左到右放入列表中,只需访问最右边的值即可获得所需内容。
import re
from datetime import datetime
def ExtractReleaseYear(title):
rg = re.compile('.*?([\[\(]?((?:19[0-9]|20[01])[0-9])[\]\)]?)', re.IGNORECASE|re.DOTALL)
match = rg.findall(title)
if match:
try:
releaseYear = match[-1][-1]
if int(releaseYear) >= 1900 and int(releaseYear) <= int(datetime.now().year) and int(releaseYear) <= 2099: # Film between 1900-2099
return releaseYear
except ValueError:
print("ERROR: The film year in the file name could not be converted to an integer for comparison.")
return ""
print(ExtractReleaseYear('2012.(2009).3D.1080p.BRRip.SBS.x264'))
print(ExtractReleaseYear('Into.The.Storm.2012.1080p.WEB-DL.AAC2.0.H264'))
print(ExtractReleaseYear('2001.A.Space.Odyssey.1968.1080p.WEB-DL.AAC2.0.H264'))
根据@kenyanke 的回答,选择 findall()
而不是 search()
将是一个更好的选择,因为以前的 returns 所有非重叠匹配模式。您可以选择最后一个匹配模式为 releaseYear
。这是我找到 releaseYear
的正则表达式
rg = re.compile(r'[^a-z](\d{4})[^a-z]', re.IGNORECASE)
match = rg.findall(title)
if match:
releaseYear = match[-1]
以上正则表达式假设 releaseYear
之前或之后的直接字母是非字母字符。三个字符串的结果(match
)是
['2009']
['2012']
['1968']
我编写了一个 python 脚本,其中包含以下函数,它以包含多个日期的文件名作为输入。
代码
import re
from datetime import datetime
def ExtractReleaseYear(title):
rg = re.compile('.*?([\[\(]?((?:19[0-9]|20[01])[0-9])[\]\)]?)', re.IGNORECASE|re.DOTALL)
match = rg.search(title) # Using non-greedy match on filler
if match:
releaseYear = match.group(1)
try:
if int(releaseYear) >= 1900 and int(releaseYear) <= int(datetime.now().year) and int(releaseYear) <= 2099: # Film between 1900-2099
return releaseYear
except ValueError:
print("ERROR: The film year in the file name could not be converted to an integer for comparison.")
return ""
print(ExtractReleaseYear('2012.(2009).3D.1080p.BRRip.SBS.x264'))
print(ExtractReleaseYear('Into.The.Storm.2012.1080p.WEB-DL.AAC2.0.H264'))
print(ExtractReleaseYear('2001.A.Space.Odyssey.1968.1080p.WEB-DL.AAC2.0.H264'))
输出
Returned: 2012 -- I'd like this to be 2009 (i.e. last occurrence of year in string)
Returned: 2012 -- This is correct! (last occurrence of year is the first one, thus right)
Returned: 2001 -- I'd like this to be 1968 (i.e. last occurrence of year in string)
问题
可以看出,正则表达式将只针对一年中的第一次出现而不是最后一次出现。这是有问题的,因为有些标题(例如此处包含的标题)以年份开头。
在寻找获得年度最后一次出现的方法后,我找到了像 negative lookahead,
预期结果
- 我想从给定的文件名中提取一年的最后一次出现(而不是第一次出现),并 return 它使用上面输出引用中所述的现有 definition/function 。 虽然我使用过在线 regex 参考资料,但我是 regex 的新手,如果有人向我展示如何实现此过滤器以处理上述文件名,我将不胜感激。伙计们干杯。
您需要更改两件事:
- 第一个
.*?
惰性模式必须转为贪婪模式.*
(在这种情况下,.*
之后的子模式将匹配字符串中的最后一次出现) - 您需要使用的组是组 2,而不是组 1(因为它是存储年份数据的组)。或者将第一个捕获组设为非捕获。
参见this demo:
rg = re.compile('.*([\[\(]?((?:19[0-9]|20[01])[0-9])[\]\)]?)', re.IGNORECASE|re.DOTALL)
...
releaseYear = match.group(2)
或:
rg = re.compile('.*(?:[\[\(]?((?:19[0-9]|20[01])[0-9])[\]\)]?)', re.IGNORECASE|re.DOTALL)
...
releaseYear = match.group(1)
考虑使用 findall() 而不是 search()?
它会将找到的所有值从左到右放入列表中,只需访问最右边的值即可获得所需内容。
import re
from datetime import datetime
def ExtractReleaseYear(title):
rg = re.compile('.*?([\[\(]?((?:19[0-9]|20[01])[0-9])[\]\)]?)', re.IGNORECASE|re.DOTALL)
match = rg.findall(title)
if match:
try:
releaseYear = match[-1][-1]
if int(releaseYear) >= 1900 and int(releaseYear) <= int(datetime.now().year) and int(releaseYear) <= 2099: # Film between 1900-2099
return releaseYear
except ValueError:
print("ERROR: The film year in the file name could not be converted to an integer for comparison.")
return ""
print(ExtractReleaseYear('2012.(2009).3D.1080p.BRRip.SBS.x264'))
print(ExtractReleaseYear('Into.The.Storm.2012.1080p.WEB-DL.AAC2.0.H264'))
print(ExtractReleaseYear('2001.A.Space.Odyssey.1968.1080p.WEB-DL.AAC2.0.H264'))
根据@kenyanke 的回答,选择 findall()
而不是 search()
将是一个更好的选择,因为以前的 returns 所有非重叠匹配模式。您可以选择最后一个匹配模式为 releaseYear
。这是我找到 releaseYear
rg = re.compile(r'[^a-z](\d{4})[^a-z]', re.IGNORECASE)
match = rg.findall(title)
if match:
releaseYear = match[-1]
以上正则表达式假设 releaseYear
之前或之后的直接字母是非字母字符。三个字符串的结果(match
)是
['2009']
['2012']
['1968']