【问题标题】:Regex to match years within 1980 and 2050正则表达式匹配 1980 年和 2050 年的年份
【发布时间】:2015-07-04 16:11:56
【问题描述】:

我希望使用正则表达式在句子中匹配 1980 年到 2050 年之间的年份。

到目前为止我使用的是:

def within_years(d):
    return re.search('20[0-5][0-9]', d) or re.search('19[89][0-9]', d)

现在的问题是我也匹配“22015”。

所以我想在前面加上[^0-9],但是如果它在句子的开头,它就不能匹配年份。

接下来是添加[ /-]*,但它仍然只是可选的。

一些例子:

should_match = ['2015 is a great year', 'best year: 2015']
should_not_match = ['22015 bogus', 'a2015 is not a year']

【问题讨论】:

  • 很好奇 - 为什么使用正则表达式而不是 <>?似乎它会更容易并且不太可能出现错误
  • 将其解析为 int 并使用简单的1980 <= x <= 2050

标签: python regex date


【解决方案1】:

你可以机械地处理它,只是构建一系列独家替代品:

>>> r'\b({})\b'.format('|'.join([str(x) for x in range(1980, 2051)]))
'\\b(1980|1981|1982|1983|1984|1985|1986|1987|1988|1989|1990|1991|1992|1993|1994|1995|1996|1997|1998|1999|2000|2001|2002|2003|2004|2005|2006|2007|2008|2009|2010|2011|2012|2013|2014|2015|2016|2017|2018|2019|2020|2021|2022|2023|2024|2025|2026|2027|2028|2029|2030|2031|2032|2033|2034|2035|2036|2037|2038|2039|2040|2041|2042|2043|2044|2045|2046|2047|2048|2049|2050)\\b'

但我个人会匹配四位数字并以整数形式与目标年份进行比较:

def within_years(txt, tgt=(1980, 2050)):
    # any valid year in the text
    digits=re.findall(r'\b(\d\d\d\d)\b', txt)
    return any(tgt[0]<= int(e) <= tgt[1] for e in digits)

或者:

def within_years0(txt, tgt=(1980, 2050)):
    # first four standalone digits only
    digits=re.search(r'\b(\d\d\d\d)\b', txt)
    return bool(digits and tgt[0]<= int(digits.group(1)) <= tgt[1])

【讨论】:

  • +1 这是最好的答案。如果你打算使用正则表达式来解决一个不适合正则表达式的问题,至少要聪明一点。
  • 嗯,我真的希望有一种简单的方法可以在正则表达式中定义数字范围,但这似乎不是快速代码?
  • 另外,这仍然匹配 22015,我猜是因为 \\b 而不是 \b?括号不见了...
  • 应该是r'\b({})\b'.format(…),这样\b就不会只属于第一年和最后一年。
  • 两个小点:(1)这种方法的一个缺点是,由于验证是事后发生的,如果你有“9999 2015”,它会找到9999并返回False,错过了2015. 为了避免这种情况,我通常会使用findall。 (2) if something: return True else: return False 只是 return bool(something) (有或没有 bool,取决于它是否已经是一个。)
【解决方案2】:

您可以使用单个正则表达式:

(19[89][0-9]|20[0-4][0-9]|2050)

您应该在其周围添加\b 边界,以确保它们周围没有任何东西:

\b(19[89][0-9]|20[0-4][0-9]|2050)\b
>>> valid_year = re.compile(r'\b(19[89][0-9]|20[0-4][0-9]|2050)\b')
>>> should_match = ['2015 is a great year', 'best year: 2015']
>>> should_not_match = ['22015 bogus', 'a2015 is not a year']
>>> for s in should_match:
        print(valid_year.search(s))

<_sre.SRE_Match object; span=(0, 4), match='2015'>
<_sre.SRE_Match object; span=(11, 15), match='2015'>
>>> for s in should_not_match:
        print(valid_year.search(s))

None
None

【讨论】:

  • 我很困惑...a2015 不会仍然将 'a' 算作单词的一部分吗?
  • 啊,我明白了,它需要一个单词边界作为“字符”。谢谢,这是一个很好的答案。
  • 这验证了 [1980-2049]。 2050 年发生了什么?
  • @PascalvKooten 正则表达式是这项工作的错误工具。我可怜可怜的人,他必须维护这段代码。
  • @NullUserException 我们不要夸大其词...... .
【解决方案3】:

您只需使用单词边界\b

return re.search(r'\b(?:2050|20[0-4][0-9]|19[89][0-9])\b', d)

【讨论】:

  • 这不是也验证“2059”作为范围内的输入吗?我的意思是,它可以被修复,但只是表明使用正则表达式进行这种验证是多么愚蠢。然后有人想将范围更改为 1980-2055,这是一堆代码更改而不是更改一个数字。
  • 已编辑。如果他想匹配2050,那么r'\b(?:2050|20[0-4][0-9]|19[89][0-9])\b'
猜你喜欢
  • 1970-01-01
  • 2015-12-25
  • 1970-01-01
  • 2011-02-08
  • 2023-04-02
  • 2013-05-27
  • 2019-09-27
  • 2014-08-20
相关资源
最近更新 更多