微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

正则表达式将时间方程转换为 R 日期时间 (POSIXct)

如何解决正则表达式将时间方程转换为 R 日期时间 (POSIXct)

我正在从另一个平台读取数据,其中使用下面列出的字符串组合来表示时间戳:

\* = current time 
t = current day (00:00)
mo = month 
d = days 
h = hours
m = minutes 

例如,*-3d 是当前时间减去 3 天,t-3h 是今天早上前三个小时(昨天午夜)。

我希望能够将这些方程提取到 R 中并获得相应的 POSIXct 值。我正在尝试在下面的函数中使用正则表达式,但丢失了每个字符串的数字乘数:

strTimeConverter <- function(z){
  ret <- stringi::stri_replace_all_regex(
    str = z,pattern = c('^\\*','^t','([[:digit:]]{1,})mo',})d',})h',})m'),replacement = c('Sys.time()','Sys.Date()','*lubridate::months(1)','*lubridate::days(1)','*lubridate::hours(1)','*lubridate::minutes(1)'),vectorize_all = F
  )
  return(ret)
  # return(eval(expr = parse(text = ret)))
}

> strTimeConverter('*-5mo+3d+4h+2m')
[1] "Sys.time()-*lubridate::months(1)+*lubridate::days(1)+*lubridate::hours(1)+*lubridate::minutes(1)"

> strTimeConverter('t-5mo+3d+4h+2m')
[1] "Sys.Date()-*lubridate::months(1)+*lubridate::days(1)+*lubridate::hours(1)+*lubridate::minutes(1)"

预期输出

# *-5mo+3d+4h+2m
"Sys.time()-5*lubridate::months(1)+3*lubridate::days(1)+4*lubridate::hours(1)+4*lubridate::minutes(1)"

# t-5mo+3d+4h+2m
"Sys.Date()-5*lubridate::months(1)+3*lubridate::days(1)+4*lubridate::hours(1)+4*lubridate::minutes(1)"

我认为将 [[:digit]]{1,} 括在括号 () 中会保留它们,但显然这是行不通的。我定义了这样的模式,否则代码会替换重复出现,例如* 被转换为 Sys.time(),但随后 m 中的 Sys.time() 被替换为 *lubridate::minutes(1)

我计划使用 eval(parse(text = ...)) 将(预期的)输出转换为 R 日期时间 - 目前已在函数中注释掉。

我愿意使用其他软件包或方法

更新

经过一番修改后,我发现以下版本有效 - 我正在按顺序替换字符串,以便不会再次替换新替换的字符:

strTimeConverter <- function(z){
  ret <- stringi::stri_replace_all_regex(
    str = z,pattern = c('y','d','h','mo','m','^\\*'),replacement = c('*years(1)','*days(1)','*hours(1)','*days(30)','*minutes(1)','Sys.time()'),vectorize_all = F
  )
  ret <- gsub(pattern = '\\*',replacement = '*lubridate::',x = ret)
  rdate <- (eval(expr = parse(text = ret)))
  attr(rdate,'tzone') <- 'UTC'
  return(rdate)
}
sample_string <- '*-5mo+3d+4h+2m'
strTimeConverter(sample_string)

这可行,但不是很优雅,并且可能会失败,因为我被迫合并其他表达式(例如 yd 表示一年中的某一天,例如 124)。

解决方法

您可以像这样在替换中使用反向引用:

library(stringr)
x <- c("*-5mo+3d+4h+2m","t-5mo+3d+4h+2m")
repl <- c('^\\*' = 'Sys.time()','^t' = 'Sys.Date()','(\\d+)mo' = '\\1*lubridate::months(1)','(\\d+)d' = '\\1*lubridate::days(1)','(\\d+)h' =  '\\1*lubridate::hours(1)','(\\d+)m' = '\\1*lubridate::minutes(1)')
stringr::str_replace_all(x,repl)
## => [1] "Sys.time()-5*lubridate::months(1)+3*lubridate::days(1)+4*lubridate::hours(1)+2*lubridate::minutes(1)"
##    [2] "Sys.Date()-5*lubridate::months(1)+3*lubridate::days(1)+4*lubridate::hours(1)+2*lubridate::minutes(1)"

参见R demo online

参见,例如,'(\\d+)mo' = '\\1*lubridate::months(1)'。在这里,(\d+)mo 匹配并捕获到 Group 1 一个或多个数字,而 mo 只是匹配。然后,当找到匹配项时,\1 中的 \1*lubridate::months(1) 将 Group 1 的内容插入到结果字符串中。

请注意,如果您用右侧的单词边界 (\b) 限制时间段匹配,可能会使替换更安全:

repl <- c('^\\*' = 'Sys.time()','(\\d+)mo\\b' = '\\1*lubridate::months(1)','(\\d+)d\\b' = '\\1*lubridate::days(1)','(\\d+)h\\b' =  '\\1*lubridate::hours(1)','(\\d+)m\\b' = '\\1*lubridate::minutes(1)')

如果时间跨度在没有任何非单词定界符的情况下相互粘合,它将不起作用,但是您的示例字符串中有 +,因此这里是安全的。

实际上,您也可以使用您使用的函数使其工作。只需确保反向引用具有 $n 语法:

x <- c("*-5mo+3d+4h+2m","t-5mo+3d+4h+2m")
pattern = c('^\\*','^t','(\\d+)mo','(\\d+)d','(\\d+)h','(\\d+)m')
replacement = c('Sys.time()','Sys.Date()','$1*lubridate::months(1)','$1*lubridate::days(1)','$1*lubridate::hours(1)','$1*lubridate::minutes(1)')
stringi::stri_replace_all_regex(x,pattern,replacement,vectorize_all=FALSE)

输出:

[1] "Sys.time()-5*lubridate::months(1)+3*lubridate::days(1)+4*lubridate::hours(1)+2*lubridate::minutes(1)"
[2] "Sys.Date()-5*lubridate::months(1)+3*lubridate::days(1)+4*lubridate::hours(1)+2*lubridate::minutes(1)"
,

另一种直接生成时间的选项如下:

strTimeConvert <- function(base=Sys.time(),delta="-5mo+3d+4h+2m"){
  mo <- gsub(".*([+-]\\d+)mo.*","\\1",x)
  ds <- gsub(".*([+-]\\d+)d.*",x)
  hs <- gsub(".*([+-]\\d+)h.*",x)
  ms <- gsub(".*([+-]\\d+)m.*",x)
  out <- base + months(as.numeric(mo)) + days(as.numeric(ds)) + 
          hours(as.numeric(hs)) + minutes(as.numeric(ms))
  out
}
strTimeConvert()
# [1] "2020-07-21 20:32:19 EDT"

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?