使用正则表达式提取不同格式的日期并对其进行排序 - 熊猫

Posted

技术标签:

【中文标题】使用正则表达式提取不同格式的日期并对其进行排序 - 熊猫【英文标题】:Extracting dates that are in different formats using regex and sorting them - pandas 【发布时间】:2018-02-14 07:00:34 【问题描述】:

我是文本挖掘的新手,我需要从 *.txt 文件中提取日期并对其进行排序。日期在句子之间(每行),它们的格式可能如下:

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

如果缺少这一天,请考虑 1 日,如果缺少月份,请考虑 1 月。

我的想法是提取所有日期并将其转换为 mm/dd/yyyy 格式。但是,我对如何查找和替换模式有点怀疑。这就是我所做的:

import pandas as pd

doc = []
with open('dates.txt') as file:
    for line in file:
        doc.append(line)

df = pd.Series(doc)

df2 = pd.DataFrame(df,columns=['text'])

def myfunc(x):
    if len(x)==4:
        x = '01/01/'+x
    else:
        if not re.search('/',x):
            example = re.sub('[-]','/',x)
            terms = re.split('/',x)
            if (len(terms)==2):
                if len(terms[-1])==2:
                    x = '01/'+terms[0]+'/19'+terms[-1]
                else:
                    x = '01/'+terms[0]+'/'+terms[-1] 
            elif len(terms[-1])==2:
                x = terms[0].zfill(2)+'/'+terms[1].zfill(2)+'/19'+terms[-1]
    return x

df2['text'] = df2.text.str.replace(r'(((?:\d+[/-])?\d+[/-]\d+)|\d4)', lambda x: myfunc(x.groups('Date')[0]))

我只为数字日期格式做了它。但我有点困惑如何使用字母数字日期。

我知道这是一个粗略的代码,但这正是我得到的。

【问题讨论】:

【参考方案1】:

我认为这是 coursera 文本挖掘作业之一。那么你可以使用正则表达式和提取来获得解决方案。 dates.txt 即

doc = []
with open('dates.txt') as file:
    for line in file:
        doc.append(line)

df = pd.Series(doc)

def date_sorter():
    # Get the dates in the form of words
    one = df.str.extract(r'((?:\d,2\s)?(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*(?:-|\.|\s|,)\s?\d,2[a-z]*(?:-|,|\s)?\s?\d2,4)')
    # Get the dates in the form of numbers
    two = df.str.extract(r'((?:\d1,2)(?:(?:\/|-)\d1,2)(?:(?:\/|-)\d2,4))')
    # Get the dates where there is no days i.e only month and year  
    three = df.str.extract(r'((?:\d1,2(?:-|\/))?\d4)')
    #Convert the dates to datatime and by filling the nans in two and three. Replace month name because of spelling mistake in the text file.
    dates = pd.to_datetime(one.fillna(two).fillna(three).replace('Decemeber','December',regex=True).replace('Janaury','January',regex=True))
return pd.Series(dates.sort_values())

date_sorter()

输出:

9 1971-04-10 84 1971-05-18 2 1971-07-08 53 1971-07-11 28 1971-09-12 474 1972-01-01 153 1972-01-13 13 1972-01-26 129 1972-05-06 98 1972-05-13 111 1972-06-10 225 1972-06-15 31 1972-07-20 171 1972-10-04 191 1972-11-30 486 1973-01-01 335 1973-02-01 415 1973-02-01 36 1973-02-14 405 1973-03-01 323 1973-03-01 422 1973-04-01 375 1973-06-01 380 1973-07-01 345 1973-10-01 57 1973-12-01 481 1974-01-01 436 1974-02-01 104 1974-02-24 299 1974-03-01

如果你只想返回索引,那么return pd.Series(dates.sort_values().index)

解析第一个正则表达式

#?:非捕获组 ((?:\d,2\s)? # 两位数组。`?` 指前面的标记或组。这里的数字是 2 或 1,空格出现一次或更少。 (?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[az]* # 组中以任何字母 `[]` 结尾的单词出现任意次数 ( `*`)。 (?:-|\.|\s|,) # 模式匹配 -,.,space \s? #(`?` 这里它只暗示空格,即前面的标记) \d,2[a-z]* # 小于或等于两位数,末尾有任意数量的字母 (`*`)。 (例如:可能是 1 日、13 日、22 日、1 月、12 月等)。 (?:-|,|\s)?# 字符-/,/空格可能出现一次,也可能不会出现,因为末尾有`?` \s? # 空格可能出现也可能根本不出现(最大值为1)(`?`这里只指空格) \d2,4) # 匹配 2 或 4 的数字

希望对您有所帮助。

【讨论】:

@bharath shetty 我有一个关于 ? 的问题。影响了多少先前的元素。例如最后一个“?”在下面的代码中 (?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[az]*(?:-|\.|\s|,)\s ?仅指 [a-z]*(?:-|\.|\s|,)\s? 我无法正确理解这个问题。你的意思是在(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*(?:‌​-|\.|\s|,)\s? 中结束? 是指哪个组???

以上是关于使用正则表达式提取不同格式的日期并对其进行排序 - 熊猫的主要内容,如果未能解决你的问题,请参考以下文章

带有文本的 Jquery 表排序器日期提取

正则表达式在javascript中重新排序部分日期

正则表达式-提取年份

正则表达式:如何提取不完整的日期并进行转换

从两种不同的 url 格式中提取数字的单个正则表达式?

Google表格正则提取第n个日期字符串