如何从(相对)非结构化文本中提取日期[R]

时间:2015-03-03 23:25:09

标签: r string date grep

我很难从字符串中提取日期。该字符串可以看作多种方式之一,但总是包含某种形式:

<full month name> <numeric date>, <year>

如:

DECEMBER 4, 2011

然而,字符串开头的文本范围很广,采用了所有这些形式:

THE PUBLIC SCHEDULE FOR MAYOR RAHM EMANUEL JUNE 9, 2011
THE PUBLIC SCHEDULE FOR MAYOR RAHM EMANUEL FOR OCTOBER 29 & OCTOBER 30, 2011
The Public Schedule for Mayor Rahm Emanuel December 17, 2011 through January 2, 2012
The Public Schedule for Mayor Rahm Emanuel December 8th and 9th, 2012
The Public Schedule for Mayor Rahm Emanuel – March 13, 2013

这些变化真的让我失望。通常情况下,我只是删除字符串的前X个字符,并使用余数作为我的日期,但由于格式不断变化,这是不可能的。我一直试图改变这种情况,但我最终创造了同样多的问题。

似乎grep()可能是这里使用的函数,但我真的不明白如何创建一个捕获这些日期的模式,或者如何使用它的输出。

感谢您的帮助!

1 个答案:

答案 0 :(得分:5)

这或多或少只是一种启发式方法。如果您删除了截至当月的所有内容,我们将获得更易于管理的内容。我们假设您的示例行位于变量b中:

months.regex <- paste(month.name, collapse='|')
d <- gsub(paste0(".*(", months.regex, ")"), "\\1", 
          b[grep(months.regex, b, TRUE)], TRUE)

这只选择一个月的行,并删除一个月内的所有内容:

> d
[1] "JUNE 9, 2011"               "OCTOBER 30, 2011"          
[3] "January 2, 2012"            "December 8th and 9th, 2012"
[5] "March 13, 2013"            

月份和年份相当容易提取:

month <- match(tolower(gsub("\\s.*", "", d)), tolower(month.name))
day <- gsub("\\S+\\s+(.*),.*", "\\1", d)
year <- as.integer(gsub(".*,\\s*(\\d{4})", "\\1", d))

真正的问题是自由形式的日子和多个日期。没有完美的方法 - 如果行中超过一个月,上面将总是选择最后一个日期。要减少多天,您可以使用类似

的内容
day <- as.integer(gsub("\\D.*", "", day))

如果有多个,则会选择第一天。完整的结果是:

> paste(month.name[month], day, year)
[1] "June 9 2011"     "October 30 2011" "January 2 2012"  "December 8 2012"
[5] "March 13 2013"