在R中解析复杂的日期文本

时间:2019-06-28 09:01:11

标签: r parsing

我想从某些文本内容中提取所有日期。内容包括这样的日期文本:

21, 17, 16, 12, 10, 6, 5, 3 June 2019, 30 and 28, 27 May 2019

我希望将所有日期保留在这样的list()中:

c("2019-06-21", "2019-06-17", "2019-06-16", "2019-06-12", "2019-06-10", "2019-06-06", "2019-06-05", "2019-06-03", "2019-05-30", "2019-05-28", "2019-05-27")

有可能这样做吗?谢谢。

2 个答案:

答案 0 :(得分:1)

正如评论中指出的,简单的答案是将数据清除为R可以理解的格式。如果数据是从其他软件导入的,则通常(如果不是始终如此)从该软件而不是R会更容易。

也就是说,尽管对于这些任务必须手动完成,但始终可以翻译。下面是仅使用基本软件包在R中如何实现此目的的说明。

dates <- '21, 17, 16, 12, 10, 6, 5, 3 June 2019, 30 and 28, 27 May 2019'
#split on ', ' and ' and '
split_dates <- strsplit(dates, ", | and ", perl = TRUE)[[1]] 
#Find the dats which contain months and year
long_dates <- which(nchar(split_dates) > 2)
#Function to format dates
make_dates <- function(string){
    string <- unlist(strsplit(string, " "))
    nString <- length(string)
    year <- string[nString]
    month <- string[nString - 1]
    as.Date(paste0(year, month, string[seq(nString - 2)]), format = '%Y%B%d')
}
#Date vector for output
output_Dates <- integer(length(split_dates))
class(output_Dates) <- "Date"
j <- 0
for(i in long_dates){
    output_Dates[j:i] <- make_dates(split_dates[j:i])
    j <- i + 1
}
output_Dates

[1]"2019-06-21" "2019-06-17" "2019-06-16" "2019-06-12" "2019-06-10" "2019-06-06" "2019-06-05" "2019-06-03" "2019-05-30" "2019-05-28" "2019-05-27"

请注意,您期望的输出中似乎缺少2019-05-30是一致的。

答案 1 :(得分:0)

要补充@Oliver的答案,有一种解决方案使用stringrlubridate包并实现非常简单的正则表达式。

首先,找到月份年份块(例如"June 2019"):

mny_loc_list <- str_locate_all(date_string, 
    paste0("\\b(", paste(month.name, collapse = "|"), ")", "\\s*\\d{4}"))
print(mny_loc_list)
> > mny_loc_list
[[1]]
     start end
[1,]    29  38
[2,]    55  62
[3,]    72  81

请注意,内置month.name向量应与原始日期字符串中的月份名称相对应。可以通过适当设置区域设置或手动设置月份名称矢量来解决不一致问题。

然后,创建一个函数,将与每个月-年块相对应的日期转换为日历日期:

ExtractForMonth <- function(list_entry, string_entry) {

    # define the end of a previous month-year block
    if (string_entry %in% 1) {
        block_begin <- 1
    } else {
        # take the end of a previous entry if it is not the first block
        block_begin <- list_entry[(string_entry - 1), 2] + 1
    }

    n_day <- str_sub(date_string, block_begin, list_entry[string_entry, 1] - 1)
    month_year <- str_sub(date_string, 
        list_entry[string_entry, 1], list_entry[string_entry, 2])
    day_date <- str_extract_all(n_day, "\\b\\d+?\\b")
    date_final <- paste0(unlist(day_date), " ", month_year)
    return(lubridate::dmy(date_final))

}

最后,将此功能应用于每一对月-年块位置:

dates_list <- lapply(
    function(i) ExtractForMonth(list_entry = mny_loc_list[[1]],
        string_entry = i), 
    X = seq(to = nrow(mny_loc_list[[1]])))

print(dates_list)
[[1]]
[1] "2019-06-21" "2019-06-17" "2019-06-16" "2019-06-12" "2019-06-10"
[6] "2019-06-06" "2019-06-05" "2019-06-03"

[[2]]
[1] "2019-05-30" "2019-05-28" "2019-05-27"