【问题标题】:Split string using regular expressions and store it into data frame使用正则表达式拆分字符串并将其存储到数据框中
【发布时间】:2014-11-20 22:20:12
【问题描述】:

我有一个这样的字符串:

Received @ 10/10/2014 02:29:55 a.m.  Changed status: 'processing' @ 10/10/2014 02:40:20 a.m.  Changed status: 'processed' @ 10/10/2014 02:40:24 a.m.

我需要使用某些规则来“解析”这个字符串:

  • 第一个块是Received 日期和时间
  • 第一个块之后的每个块都以 Changed status: 开头并以日期和时间结束

    可以有任意数量的 Changed status: 块(至少 1 个)并且状态可能会有所不同

我需要做的是:

  1. 拆分字符串并将每个块放入一个数组中。

    示例:

    [Received @ 10/10/2014 02:29:55 a.m.], [Changed status: 'processing' @ 10/10/2014 02:40:20 a.m.], [Changed status: 'processed' @ 10/10/2014 02:40:24 a.m.]

  2. 每个块拆分后,我需要将每个条目拆分为三个字段

对于上面的例子,我需要的是这样的:

Received       | NULL       | 10/10/2014 02:29:55 am
Changed status | processing | 10/10/2014 02:40:20 am
Changed status | processed  | 10/10/2014 02:40:20 am

我认为第二步很容易(每个块都可以使用@: 作为分隔符进行拆分),但第一步让我不得不扯掉头发。有没有办法用正则表达式做这种事情?

我尝试了一些方法(例如Received|Changed.*[ap].m.),但它不起作用(正则表达式的求值总是返回完整的字符串)。

我想在 R 中这样做:

  1. 将完整的数据表(字段较多,上面的文字是最后一个)读入数据框
  2. “解析”此字符串并将其存储到第二个数据帧中

R 内置了对正则表达式的支持,所以这是我在接近解决方案时的第一个想法。

任何帮助将不胜感激。老实说,我在这里迷路了(但我会继续尝试......如果我找到让我更接近解决方案的步骤,我会编辑我的帖子)

【问题讨论】:

  • 你打算用什么语言评估这个?
  • @DaaaahWhoosh 我计划在 R 中执行此操作(已经在帖子中...和标签中说过)。但我可以使用任何其他支持 RegEx 的语言(例如awk)。我想直接在 R 中执行此操作,因为如果我使用其他实用程序执行此操作,无论如何我都必须将结果导入 R
  • 接收和更改的状态选项卡是否分隔?其他所有内容都用单个空格分隔?
  • @rawr 不幸的是,所有内容仅由空格分隔:(

标签: regex r string


【解决方案1】:

您可以将其放入函数中。在您发布的字符串中,重要信息似乎用两个空格分隔,这很好。基本上我所做的就是尝试让所有相关的行平均分成合适的长度。

x <- "Received @ 10/10/2014 02:29:55 a.m.  Changed status: 'processing' @ 10/10/2014 02:40:20 a.m.  Changed status: 'processed' @ 10/10/2014 02:40:24 a.m."

s <- strsplit(gsub("['.]", "", x), "  ")[[1]]
s[g] <- sub("(\\D) ", "\\1:  ", s[g <- grep("Received", s)])
do.call(rbind, strsplit(s, " @ |: "))
#      [,1]             [,2]         [,3]                      
# [1,] "Received"       ""           "10/10/2014 02:29:55 am"
# [2,] "Changed status" "processing" "10/10/2014 02:40:20 am"
# [3,] "Changed status" "processed"  "10/10/2014 02:40:24 am"

我没有"NULL",因为我猜你的意思是你想要一个空字符。 NULL 无论如何都不会出现在数据框中。

【讨论】:

  • 这让我更接近解决方案:)
  • 诀窍是在拆分之前摆脱所有不重要的东西
【解决方案2】:

这是基于strapplyc 的简短解决方案。 strapplyc 将正则表达式匹配到输入字符串 s 将匹配项提取到正则表达式的括号部分,(?:...) 除外,它是非捕获的。

pat 中有 3 对括号。第一个匹配 Recieved 或 Changed 状态。然后我们可选地匹配一个冒号、空格、单引号、零个或多个非单引号字符和另一个引号。两个引号之间的部分是第二个捕获的字符串。然后我们匹配空格、@、空格和日期/时间字符串。捕获日期/时间字符串。

最后使用matrix将其重塑为3列:

library(gsubfn)

pat <- "(Received|Changed status)(?:: '([^']*)')? @ (../../.... ..:..:.. ....)"
matrix(strapplyc(s, pat, simplify = TRUE), nc = 3, byrow = TRUE)

给予:

     [,1]             [,2]         [,3]                      
[1,] "Received"       ""           "10/10/2014 02:29:55 a.m."
[2,] "Changed status" "processing" "10/10/2014 02:40:20 a.m."
[3,] "Changed status" "processed"  "10/10/2014 02:40:24 a.m."

更新:简化。还将输出修改为有问题。

【讨论】:

    【解决方案3】:
    tmp <- "Received @ 10/10/2014 02:29:55 a.m.  Changed status: 'processing' @ 10/10/2014 02:40:20 a.m.  Changed status: 'processed' @ 10/10/2014 02:40:24 a.m."
    
    
    tmp1 <- strsplit(gsub('Received', 'Received:', tmp), '\\s{2}', perl = TRUE)
    
    do.call(rbind, strsplit(tmp1[[1]], '@ |: '))
    
    #                 [,1]             [,2]            [,3]                      
    # [1,] "Received"       ""              "10/10/2014 02:29:55 a.m."
    # [2,] "Changed status" "'processing' " "10/10/2014 02:40:20 a.m."
    # [3,] "Changed status" "'processed' "  "10/10/2014 02:40:24 a.m."
    

    【讨论】:

      【解决方案4】:

      我假设您已将数据保存在 data.frame 中,并且您希望在数据框中的许多行上执行此操作。我将那个 data.frame 称为“数据”,这就是我要做的,尽管也许其他人可以让它更优雅:

       Split <- str_split(Data$String, "@") # Make a list with your string split by "@"
      
       Data$Received <- NA
       Data$Processing <- NA
       Data$Processed <- NA
      
       for (i in 1:nrow(Data)){
             Data$Received[i] <- str_sub(Split[[i]][2], 2, 24) # Extract the date received, etc.
             Data$Processing[i] <- str_sub(Split[[i]][3], 2, 24)
             Data$Processed[i] <- str_sub(Split[[i]][4], 2, 24)
       }
      
       Data$Received <- mdy_hms(Data$Received) # Use lubridate to convert it to POSIX format
       Data$Processing <- mdy_hms(Data$Processing)
       Data$Processed <- mdy_hms(Data$Processed)
      

      这为您提供了三列您想要的日期和时间。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-02-23
        相关资源
        最近更新 更多