【问题标题】:Extract text from first, second and third brackets in R从R中的第一个,第二个和第三个括号中提取文本
【发布时间】:2015-10-07 15:18:31
【问题描述】:

我在 R 中有以下数据框:

text <- c("[AAA]xxxx", "[AAA] yyyrrr", "[AAA][bbb] bla", "[AAA][bbb] cccvvv", 
      "[AAA][bbb] bla", "[AAA][bbb][CcC] bla", "[AAA][bbb][CcC] xbbpr") 
value <- rnorm(7)
df <- data.frame(text, value)

我想在我的数据框中为第一个、第二个和第三个括号对中包含的文本分别创建三个新变量。

所需的输出如下所示:

                  text       value Bracket1 Bracket2 Bracket3
1             [AAA]xxxx -0.01819034      AAA       NA       NA
2          [AAA] yyyrrr -0.24808460      AAA       NA       NA
3        [AAA][bbb] bla -0.36293689      AAA      bbb       NA
4     [AAA][bbb] cccvvv  1.27757055      AAA      bbb       NA
5        [AAA][bbb] bla -0.46889715      AAA      bbb       NA
6   [AAA][bbb][CcC] bla  0.07105410      AAA      bbb      CcC
7 [AAA][bbb][CcC] xbbpr -0.26603845      AAA      bbb      CcC

我无法从第一个括号中提取文本,更不用说第二个或第三个了。

例如,我尝试过:

    df$Bracket1 <- gsub('.*\\[(.*)\\].*', '\\1', text)

    df$Bracket1 <- sub('.*\\[(.*)\\].*', '\\1', text)

但这些都产生了:

                   text       value    Bracket1
1             [AAA]xxxx -0.01819034         AAA
2          [AAA] yyyrrr -0.24808460         AAA
3        [AAA][bbb] bla -0.36293689         bbb
4     [AAA][bbb] cccvvv  1.27757055         bbb
5        [AAA][bbb] bla -0.46889715         bbb
6   [AAA][bbb][CcC] bla  0.07105410         CcC
7 [AAA][bbb][CcC] xbbpr -0.26603845         CcC

我是 regex 的新手,对 R 比较陌生,提前感谢您的任何建议。

【问题讨论】:

  • 太棒了!非常感谢你的帮助。我还不知道它是什么意思,所以现在我将深入研究你的语法并将它们拼凑在一起。你会提交作为答案让我接受吗?

标签: r regex text extract


【解决方案1】:

这是一种使用gregexprregmatches 的方法:

mtchs <- regmatches(df$text, gregexpr("\\[\\w+\\]", df$text))

然后只需将输出重新组织为所需的结构:

library(plyr) # for rbind.fill
df[,3:5] <- do.call(rbind.fill,
            lapply(mtchs, function(xx) {x <- data.frame(matrix(xx, nrow=1))
                                        names(x) <- paste0("Bracket", 1:length(xx))
                                        x}))
# or using dplyr's bind_row:
library(dplyr)
df[,3:5] <- bind_rows(lapply(mtchs, function(xx) {x <- data.frame(matrix(xx, nrow=1))
                    names(x) <- paste0("Bracket", 1:length(xx))
                    x}))
# or using data.table's rbindlist:
library(data.table)
df[,3:5] <-  rbindlist(lapply(mtchs, function(xx) {x <- data.frame(matrix(xx, nrow=1))
                    names(x) <- paste0("Bracket", 1:length(xx))
                    x}), fill=TRUE)

如果需要,您可以更改 regmatches 中的正则表达式以去掉括号:

mtchs <- regmatches(df$text, gregexpr("(?<=\\[)\\w+(?=\\])", df$text, perl=TRUE))

【讨论】:

  • 这太好了,而且你给我展示了一些新功能,谢谢你的帮助!
  • @czimm 另外,看看 Arun 的回答,比我的更优雅!
【解决方案2】:

这是一个基于 gsub 的解决方案:如果我们有匹配项,则保留第 1 组文本,如果找不到带括号的匹配项,则匹配整个字符串并替换为空组 1。

df$Bracket1 <- gsub('(?:.*?\\[([^][]*)\\].*|.*)', '\\1', text, perl=T)
df$Bracket2 <- gsub('(?:.*?\\[[^][]*\\].*?\\[([^][]*)\\].*|.*)', '\\1', text, perl=T)
df$Bracket3 <- gsub('(?:.*?\\[[^][]*\\].*?\\[[^][]*\\].*?\\[([^][]*)\\].*|.*)', '\\1', text, perl=T)

IDEONE demo

【讨论】:

    【解决方案3】:

    使用来自data.table 包的transpose()

    require(data.table) # v1.9.6+
    dt = data.table(text, value) # text is character
    vals = regmatches(dt$text, gregexpr("(?<=\\[)[[:alpha:]]+(?=])", dt$text, perl=TRUE))
    
    dt[, paste0("Bracket", 1:3) := transpose(vals)]
    #                     text      value Bracket1 Bracket2 Bracket3
    # 1:             [AAA]xxxx -0.9285790      AAA       NA       NA
    # 2:          [AAA] yyyrrr  0.7928830      AAA       NA       NA
    # 3:        [AAA][bbb] bla  0.1177066      AAA      bbb       NA
    # 4:     [AAA][bbb] cccvvv  1.1818542      AAA      bbb       NA
    # 5:        [AAA][bbb] bla -0.4476371      AAA      bbb       NA
    # 6:   [AAA][bbb][CcC] bla  2.2992593      AAA      bbb      CcC
    # 7: [AAA][bbb][CcC] xbbpr  2.1161453      AAA      bob      CcC
    

    【讨论】:

    • 很好,谢谢 Arun,transpose() 对我来说也是一个新的。
    猜你喜欢
    • 2018-03-17
    • 2022-08-05
    • 1970-01-01
    • 2013-04-15
    • 1970-01-01
    • 2017-03-11
    • 2013-05-24
    • 1970-01-01
    • 2014-11-18
    相关资源
    最近更新 更多