如何在不编写正则表达式的情况下从字符串中解析日期?

Posted

技术标签:

【中文标题】如何在不编写正则表达式的情况下从字符串中解析日期?【英文标题】:How to parse dates from a string without writing a regular expression? 【发布时间】:2022-01-23 18:16:40 【问题描述】:

readr 包有一个名为 parse_number 的函数,它返回 string 中的数字:

readr::parse_number("Hello 2022!")

[1] 2022

是否有类似的方法可以从string 返回日期? readr 有一个名为 parse_date 的函数,但它做了一些不同的事情:

readr::parse_date("X2018-01-11_poland")

Warning: 1 parsing failure.
row col   expected             actual
  1  -- date like  X2018-01-11_poland

[1] NA

期望的输出:

# the raw string is "X2018-01-11_poland"
2018-01-11

附:我对使用正则表达式不感兴趣。

【问题讨论】:

只需指定format,根据strptime() 约定:readr::parse_date("X2018-01-11_poland", format = "X%Y-%m-%d_poland") 您对为此使用正则表达式的反感究竟是什么?精心设计的正则表达式可以对大多数正则表达式问题具有鲁棒性,并在性能和弹性方面提供相当不错的类日期提取结果。 【参考方案1】:

这是一个无正则表达式的想法,

parse_date(strsplit(x, '_', fixed = TRUE)[[1]][1], format = 'X%Y-%m-%d')
#[1] "2018-01-11"

不过,如果波兰部分也是固定的,你可以再做一次,

parse_date(x, format = 'X%Y-%m-%d_poland')
#[1] "2018-01-11"

【讨论】:

在添加 fixed=TRUE 之前,它并不是完全无正则表达式的,即使它是单字符正则表达式 :-) 哈哈哈,是的@r2evans。我们需要完全绕过正则表达式引擎;P parse_number() 本身也使用正则表达式,但您没有“看到”它。这个问题有点像“没有车我怎么能开车”。【参考方案2】:

使用基础 R 或 stringrlubridate 的可能替代方案

as.Date(substr("X2018-01-11_poland", 2, 11), format = "%Y-%m-%d")
#> [1] "2018-01-11"

library(stringr)
library(lubridate)

ymd(str_sub("X2018-01-11_poland", 2, 11))
#> [1] "2018-01-11"

由reprex package (v2.0.1) 于 2021 年 12 月 22 日创建

【讨论】:

【参考方案3】:

lubridate 包有parse_date_time2,易于使用。

library(lubridate)
dstring <- "X2018-01-11_poland"
date <- parse_date_time2(dstring, orders='Ymd')
date
#[1] "2018-01-11 UTC"

【讨论】:

【参考方案4】:

1) 这仅使用基本 R 并且不使用任何正则表达式。它假设 (1) 日期之前只有字母和空格,就像问题中的情况一样,但如有必要,可以通过在 let 中添加其他字符来轻松放宽;(2) 日期采用标准日期格式. chartr 将第一个参数中的第 i 个字符转换为第二个参数中的第 i 个字符,用空格替换每个字母。然后使用 as.Date。请注意, as.Date 会忽略末尾的垃圾,因此如果其他字符不在 lets 后面,则可以。

x <- "X2018-01-11_poland"

lets <- paste(letters, collapse = "")
as.Date(chartr(lets, strrep(" ", nchar(lets)), tolower(x)))
## [1] "2018-01-11"

2) 如果我们知道字符串总是以 X 开头并且 Date 紧随其后,那么我们可以在 as.Date 格式字符串中指定前缀。它也不使用任何正则表达式,只使用基本 R。

as.Date(x, "X%Y-%m-%d")
## [1] "2018-01-11"

3) 如果您愿意妥协并使用一个非常简单的正则表达式——这里 \D 匹配任何非数字并且反斜杠必须在引号内加倍。 gsub 删除任何此类字符。

as.Date(gsub("\\D", "", x), "%Y%m%d")
## [1] "2018-01-11"

【讨论】:

以上是关于如何在不编写正则表达式的情况下从字符串中解析日期?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用 CURDATE、MONTH、YEAR 等 DATE 函数的情况下从 RDBMS 获取当前月份记录

如何在不与 MainActivity 交互的情况下从通知中打开片段页面?

如何在不使用子进程的情况下从 python 自动化脚本中运行 python 'sdist' 命令?

如何编写一个正则表达式命令在 python 中将字符串转换为日期时间格式?

如何在不使用 regexp_like 的情况下从列中获取整数

如何在不提供 C# 管理员凭据的情况下从标准用户启动进程