【问题标题】:How can i extract month and year from a string in python?如何从python中的字符串中提取月份和年份?
【发布时间】:2020-09-18 10:40:02
【问题描述】:

输入文本

text = "Wipro Limited | Hyderabad, IN                Dec 2017 – Present
Project Analyst 

Infosys | Delhi, IN                Apr 2017 – Nov 2017 
Software Developer 

HCL Technologies | Hyderabad, IN                Jun 2016 – Mar 2017 
Software Engineer  
"

我为此编写了一个代码,但它显示在每个提取的单词的列表中,并且无法执行任何操作。

regex = re.compile('(?P<month>[a-zA-Z]+)\s+(?P<year>\d{4})\s+\–\s+(?P<month1>[a-zA-Z]+)\s+(?P<year1>\d{4})')
mat = re.findall(regex, text)
mat

查看代码:https://regex101.com/r/mMlgYp/1。 我希望像下面这样的输出来预览日期并做出改变,然后计算总经验: 此处“当前”或“截止日期”应考虑当前月份和年份。

import time
Present = time.strftime("%m-%Y")
Present 
# output: '05-2020'
#Desired output
Extracted dates: 
[('Dec 2017 - Present'),
 ('Apr 2017 - Nov 2017'),
 ('Jun 2016 - Mar 2017')]# and so on ...should display all the search results 

First experience: 1.9 years 
second experience: 8 months
third experience: 7 months
# and so on ...should display all the search results 
Total experience: 3.4 years

请帮我解决这个问题,我是编程语言和 NLP、正则表达式的新手。

【问题讨论】:

    标签: python regex pandas datetime nlp


    【解决方案1】:

    您可能最终希望在数据框中使用它,因为您将它标记为 pandas(请参阅Andrej's answer),但无论哪种方式,您都可以使用插值从字符串中解析日期:

    fr"(?i)((?:{months}) *\d{{4}}) *(?:-|–) *(present|(?:{months}) *\d{{4}})"
    

    其中{months} 是所有可能的月份名称和缩写的交替组。

    import calendar
    import re
    from datetime import datetime
    from dateutil.relativedelta import relativedelta
    
    text = """Wipro Limited | Hyderabad, IN                Dec 2017 – Present
    Project Analyst 
    
    Infosys | Delhi, IN                Apr 2017 – Nov 2017 
    Software Developer 
    
    HCL Technologies | Hyderabad, IN                Jun 2016 – Mar 2017 
    Software Engineer  
    """
    
    def parse_date(x, fmts=("%b %Y", "%B %Y")):
        for fmt in fmts:
            try:
                return datetime.strptime(x, fmt)
            except ValueError:
                pass
    
    months = "|".join(calendar.month_abbr[1:] + calendar.month_name[1:])
    pattern = fr"(?i)((?:{months}) *\d{{4}}) *(?:-|–) *(present|(?:{months}) *\d{{4}})"
    total_experience = None
    
    for start, end in re.findall(pattern, text):
        if end.lower() == "present":
            today = datetime.today()
            end = f"{calendar.month_abbr[today.month]} {today.year}"
    
        duration = relativedelta(parse_date(end), parse_date(start))
    
        if total_experience:
            total_experience += duration
        else: 
            total_experience = duration
    
        print(f"{start}-{end} ({duration.years} years, {duration.months} months)")
    
    if total_experience:
        print(f"total experience:  {total_experience.years} years, {total_experience.months} months")
    else:
        print("couldn't parse text")
    

    输出:

    Dec 2017-May 2020 (2 years, 5 months)
    Apr 2017-Nov 2017 (0 years, 7 months)
    Jun 2016-Mar 2017 (0 years, 9 months)
    total experience:  3 years, 9 months
    

    【讨论】:

    • 嗨@ggorlen,非常感谢您的快速响应。它非常适合上面的代码,但是当我将简历解析为文本并将这个文本文件传递给上面的代码时,它会抛出一个错误。 ibb.co/w42sQ6m。 (附图片)。错误:AttributeError:“NoneType”对象没有属性“years”。提前致谢。
    • 你能把文字发到s吗?可能的原因是恢复字符串与此处显示的不同导致正则表达式失败,因此re.findall 未返回任何结果,total_experience 从未设置。
    • @ggorlen,请查看附件图片。 ibb.co/9p36RHG
    • 请发帖as text。我无法复制和粘贴此内容或查看空格等。尽管如此,很明显添加在原始格式上运行良好的^(.+?) *\| *(.+?) * 不适用于此版本。如果您将其连同与 companylocation 相关的任何内容一起删除,它应该可以工作。
    • 好的,谢谢。看我的更新。请记住,正则表达式无法解析任意格式的文本,因此编写可以从一堆随机 pdf 中提取日期范围的代码有点困难(不可能?)。它们必须具有相当良好的格式,并且尝试在所有边缘情况下编写可能是一项无休止的任务(两位数年份而不是四位数年份,'05 而不是 2005,不同的空格和分隔符。 ..).
    【解决方案2】:
    import re
    import numpy as np
    import pandas as pd
    
    text = '''Wipro Limited | Hyderabad, IN                Dec 2017 – Present
    Project Analyst
    
    Infosys | Delhi, IN                Apr 2017 – Nov 2017
    Software Developer
    
    HCL Technologies | Hyderabad, IN                Jun 2016 – Mar 2017
    Software Engineer
    '''
    
    def pretty_format(monthts):
        return f'{monthts/12:.1f} years' if monthts > 11 else f'{monthts:.1f} months'
    
    data = []
    for employer, d1, d2 in re.findall(r'(.*?)\s*\|.*([A-Z][a-z]{2} [12]\d{3}) – (?:([A-Z][a-z]{2} [12]\d{3})|Present)', text):
        data.append({'Employer': employer, 'Begin': d1, 'End': d2 or np.nan})
    
    df = pd.DataFrame(data)
    df['Begin'] = pd.to_datetime(df['Begin'])
    df['End'] = pd.to_datetime(df['End'])
    
    df['Experience'] = ((df['End'].fillna(pd.to_datetime('now')) - df['Begin']) / np.timedelta64(1, 'M')).apply(pretty_format)
    print(df)
    
    total = np.sum(df['End'].fillna(pd.to_datetime('now')) - df['Begin']) / np.timedelta64(1, 'M')
    print()
    print(f'Total experience = {pretty_format(total)}')
    

    打印:

               Employer      Begin        End  Experience
    0     Wipro Limited 2017-12-01        NaT   2.5 years
    1           Infosys 2017-04-01 2017-11-01  7.0 months
    2  HCL Technologies 2016-06-01 2017-03-01  9.0 months
    
    Total experience = 3.8 years
    

    【讨论】:

    • OP 有 3.4 年,你有 3.8 年,我有 3.9 年。
    • @ggorlen 我认为这是四舍五入的问题,当我在格式中使用.2f 时,我得到3.83 years也死了
    • 哦,等等,我得到了 3 年零 9 个月,这与小数点不同。我觉得一年的小部分很奇怪,所以我会坚持使用月份格式。
    • 嗨@Andrej Kesely,非常感谢您的快速回复。感谢您应用后期阶段所需的数据框。对于上面的代码,它工作得很好,但是当我将简历解析为文本并将文本文件传递到上面的代码中时,它会抛出一个错误。 ibb.co/FwyQRmS。 (附图片)。错误:KeyError: 'Begin' 在处理上述异常的过程中,发生了另一个异常:
    猜你喜欢
    • 1970-01-01
    • 2021-09-11
    • 2021-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-17
    • 2021-01-30
    相关资源
    最近更新 更多