59

I have a list of birthdays that look something like this:

dob <- c("9/9/43 12:00 AM/PM", "9/17/88 12:00 AM/PM", "11/21/48 12:00 AM/PM")

I want to just grab the calendar date from this variable (ie drop everything after the first occurrence of white-space).

Here's what I have tried so far:

dob.abridged <- substring(dob,1,8)
dob
[1] "9/9/43 1" "9/17/88 " "11/21/48"
dob.abridged <- gsub(" $","", dob.abridged, perl=T)
> dob.abridged
[1] "9/9/43 1" "9/17/88"  "11/21/48"

So my code works for calendar dates of length 6 or 7, but not length 8. Any pointers on a more effective regex to use with gsub that can handle calendar dates of length 6, 7 or 8?

Thank you.

4

5 回答 5

127

不需要substring,只需使用gsub

gsub( " .*$", "", dob )
# [1] "9/9/43"   "9/17/88"  "11/21/48"

一个空格 ( ),然后是任意字符 ( .) 任意次数 ( *),直到字符串结尾 ( $)。请参阅?regex来学习正则表达式。

于 2013-04-09T06:51:52.757 回答
17

我经常使用strsplit这些类型的问题,但喜欢 Romain 的答案是多么简单。我认为将 Romain 的解决方案与strsplit答案进行比较会很有趣:

这是一个strsplit解决方案:

sapply(strsplit(dob, "\\s+"), "[", 1)

使用 microbenchmark 包和dob <- rep(dob, 1000)原始数据:

Unit: milliseconds
                                    expr       min        lq    median
                   gsub(" .*$", "", dob)  4.228843  4.247969  4.258232
 sapply(strsplit(dob, "\\\\s+"), "[", 1) 14.438241 14.558832 14.634638
        uq       max neval
  4.268029  5.081608  1000
 14.756628 53.344984  1000

Win 7 机器上的明显赢家是gsub来自 Romain 的正则表达式。感谢罗曼的回答和解释。

于 2013-04-09T12:10:13.173 回答
15

该库stringr包含针对此问题量身定制的功能。

library(stringr)
word(dob,1)
# [1] "9/9/43"   "9/17/88"  "11/21/48"
于 2018-02-26T00:41:02.960 回答
0

在空格之前从字母中提取字符的另一种方法是:

您必须安装软件包:“stringr”

stringr::str_extract(c("juan carlos", "miguel angel"), stringr::regex(pattern = "[a-z]+(?=\\s)", ignore_case = F))

[a-z]: 匹配 a 和 z 之间的每个字符(按 Unicode 代码点顺序)。

+: 1 个或更多。

(?=\\s): Lookahead,后跟 \s(即空格)(不匹配 \s)。

更多信息:https ://stringr.tidyverse.org/articles/regular-expressions.html

于 2021-02-03T16:13:54.073 回答
-1

另一种仅提取日期的正则表达式模式

library(stringr)
str_extract(dob, regex("\\d{1,}\\/\\d{1,}\\/\\d{1,}"))
#[1] "9/9/43"   "9/17/88"  "11/21/48"
  • \\d{1,}: 匹配数字至少 1 次
  • \\/: 转义正斜杠
于 2020-08-11T02:44:41.467 回答