【问题标题】:Extracting text from dataset从数据集中提取文本
【发布时间】:2020-03-04 07:57:35
【问题描述】:

我正在处理一个需要提取所有可用日期的数据集。日期可以是以下格式:

04/20/2009; 04/20/09; 4/20/09; 4/3/09
Mar-20-2009; Mar 20, 2009; March 20, 2009; Mar. 20, 2009; Mar 20 2009;
20 Mar 2009; 20 March 2009; 20 Mar. 2009; 20 March, 2009
Mar 20th, 2009; Mar 21st, 2009; Mar 22nd, 2009
Feb 2009; Sep 2009; Oct 2010
6/2008; 12/2009
2009; 2010

我写了以下代码:

df['dates'] = df['text'].str.extract(r'((?:\d{1,2}[/ ])?(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec[a-z.,]*[- ])?(?:\d{1,2}[a-z-, /]{1,4})?(?:\d{2,4}))')

它给了我正确的结果,除了一些文本,例如:

文本输出

实验室:B12 969 2007\n 12 969 #应该给 2007

35 年,1985 年卖出\n 35 #应该给 1985

x 14 岁去世的人... 14 #不应该考虑

我尝试将提取代码更改为

r'((?:\d{1,2}[/ ])?(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec[a-z.,]*[- ])?(?:\d{1,2}[a-z-, ]{1,4})?(?:[/]\d{2})?(?:\d{4})?)' 

但是整个结果都变坏了

【问题讨论】:

  • 尝试对月份模式进行分组 - regex101.com/r/Uebj4g/1 您想要涵盖的可能日期模式有多大?
  • 还是一样
  • 怎么都一样?你看过在线演示吗?另见分组版本:regex101.com/r/Uebj4g/2
  • 是的,我看到了,请检查块引用中提到的字符串。对于那些不匹配的字符串,或匹配不正确的第一次出现
  • Lab: B12 969 2007\n 这应该输出为 2007

标签: python regex pandas


【解决方案1】:

尝试使用pandas.to_datetime(),它将最常见的日期格式转换为日期时间对象。

【讨论】:

  • 我在从数据集中提取日期后使用它
【解决方案2】:

尝试this 模式。我的建议是,您应该将问题分解为多个部分,并尝试一次匹配一个模式。因为这个问题的正则表达式有点混乱,很难用一个表达式覆盖所有的边缘情况。

我已经包含了子正则表达式,因此您可以优化它们以验证边缘情况。

【讨论】:

  • ValueError: 传递的项目数错误 2,位置暗示 1
【解决方案3】:

您的正则表达式的问题在于它的成分都是可选的,并且它匹配实际上与日期无关的数字。您需要构建一个带有强制性部分的正则表达式,以避免匹配任意部分。

这很棘手:您的示例输入中有不同类型的日期。对于这些输入,我建议:

(?<!\d)((?<!\d[ \t])(?:A(?:pr(?:il)?|ug(?:ust)?)|Dec(?:ember)?|Feb(?:ruary)?|J(?:an(?:uary)?|u(?:ly|ne|[ln]))|Ma(?:rch|[ry])|Nov(?:ember)?|Oct(?:ober)?|Sep(?:tember)?)(?:-\d{1,2}-\d{4}|(?:\.?\s*\d{1,2}(?:st|[rn]d|th)?,?)?\s*\d{4})|\d{1,2}\s+(?:A(?:pr(?:il)?|ug(?:ust)?)|Dec(?:ember)?|Feb(?:ruary)?|J(?:an(?:uary)?|u(?:ly|ne|[ln]))|Ma(?:rch|[ry])|Nov(?:ember)?|Oct(?:ober)?|Sep(?:tember)?)\.?,?\s*\d{4}|(?:\d{1,2}/)?\d{1,2}/\d{2}(?:\d{2})?|(?:19|20)\d{2})(?!\d)

请参阅regex demo。它匹配:

  • (?&lt;!\d) - 否定的后视:当前位置左侧不允许有数字
  • ( - 外部捕获组的开始(.str.extract 必需)
    • (?&lt;!\d[ \t]) - 当前位置左侧不允许有数字后跟空格或制表符
    • (?:A(?:pr(?:il)?|ug(?:ust)?)|Dec(?:ember)?|Feb(?:ruary)?|J(?:an(?:uary)?|u(?:ly|ne|[ln]))|Ma(?:rch|[ry])|Nov(?:ember)?|Oct(?:ober)?|Sep(?:tember)?) - 月份名称及其缩写
    • (?:-\d{1,2}-\d{4}|(?:\.?\s*\d{1,2}(?:st|[rn]d|th)?,?)?\s*\d{4}) - 两种选择之一:
      • -\d{1,2}-\d{4} - -,1 位或 2 位,-,然后是 4 位
      • | - 或
      • (?:\.?\s*\d{1,2}(?:st|[rn]d|th)?,?)? - 一个可选的非捕获组,匹配 1 次或 0 次出现:
      • \.? - 可选.
      • \s* - 0+ 个空格
      • \d{1,2} - 1 位或 2 位数字
      • (?:st|[rn]d|th)? - 可选的字符序列:strn 后跟 dth
      • ,? - 可选逗号
      • \s*\d{4} - 0+ 个空格,然后是 4 位数字
  • | - 或
    • \d{1,2}\s+ - 1 或 2 个数字,然后是 1+ 个空格
    • (?:A(?:pr(?:il)?|ug(?:ust)?)|Dec(?:ember)?|Feb(?:ruary)?|J(?:an(?:uary)?|u(?:ly|ne|[ln]))|Ma(?:rch|[ry])|Nov(?:ember)?|Oct(?:ober)?|Sep(?:tember)?) - 月份名称及其缩写(同上)
    • \.? - 一个可选的点
    • ,? - 可选逗号
    • \s* - 0+ 个空格
    • \d{4} - 四位数字
  • | - 或
    • (?:\d{1,2}/)? - 可选的 1 位或 2 位数字序列,然后是 /
    • \d{1,2} - 1 位或 2 位数字
    • / - /
    • \d{2}(?:\d{2})? - 2 位数字和可选的 2 位数字序列(允许 2 位或 4 位数字,但不允许 3 位)
  • | - 或
    • (?:19|20) - 1920
    • \d{2} - 两位数
  • ) - 计算机捕获组结束
  • (?!\d) - 否定前瞻:当前位置右侧不允许有数字。

在 Python 中,您可以为模式定义块并动态构建它:

months = r'(?:A(?:pr(?:il)?|ug(?:ust)?)|Dec(?:ember)?|Feb(?:ruary)?|J(?:an(?:uary)?|u(?:ly|ne|[ln]))|Ma(?:rch|[ry])|Nov(?:ember)?|Oct(?:ober)?|Sep(?:tember)?)'
pattern = rf'(?<!\d)((?<!\d[ \t]){months}(?:-\d{{1,2}}-\d{{4}}|(?:\.?\s*\d{{1,2}}(?:st|[rn]d|th)?,?)?\s*\d{{4}})|\d{{1,2}}\s+{months}\.?,?\s*\d{{4}}|(?:\d{{1,2}}/)?\d{{1,2}}/\d{{2}}(?:\d{{2}})?|(?:19|20)\d{{2}})(?!\d)'

【讨论】:

    猜你喜欢
    • 2021-08-09
    • 1970-01-01
    • 2014-11-29
    • 2018-03-08
    • 2020-12-20
    • 1970-01-01
    • 2011-04-18
    • 1970-01-01
    相关资源
    最近更新 更多