【问题标题】:Finding matches on a character in more than one position in R [duplicate]在R中多个位置的字符上查找匹配项[重复]
【发布时间】:2023-03-16 05:52:01
【问题描述】:

我有一个字符向量,我想在其中匹配第一个和最后一个部分,以便生成匹配字符列表。

这是一个示例字符:"20190625_165055_0f4e" 第一部分是日期。最后 4 个字符是唯一标识符。我需要列表中这两个部分重复的所有字符。

我可以使用一个简单的正则表达式来根据位置匹配字符,但有些中间字符比其他字符多,例如"20190813_170215_17_1057"

这是一个示例向量:

mylist<-c("20190712_164755_1034","20190712_164756_1034","20190712_164757_1034","20190719_164712_1001","20190719_164713_1001","20190722_153110_1054","20190813_170215_17_1057","20190813_170217_22_1057","20190828_170318_14_1065")

这是所需的输出:

c("20190712_164755_1034","20190712_164756_1034","20190712_164757_1034")
c("20190719_164712_1001","20190719_164713_1001")
c("20190722_153110_1054")
c("20190813_170215_17_1057","20190813_170217_22_1057")
c("20190828_170318_14_1065")

编辑:使我的字符向量更简单并添加了所需的输出

【问题讨论】:

  • 您好 APD,如果下面的答案不能解决您的问题,我同意 akrun 的观点,如果您提供一些预期的输出会更容易提供帮助。
  • 那是我原来的答案split(mylist, sub("^(\\d+)_.*_([^_]+)$", "\\1_\\2", mylist))
  • 以下 Ruby 代码可以做到,如果有人想将其翻译成 R:arr.group_by { |s| [s[0,8], s[-4,-2]] }.values

标签: r regex character matching


【解决方案1】:

我们可以删除带有subsplit 的中间子字符串,在此基础上将list 变成characterlist vectors

lst1 <- split(mylist, sub("^(\\d+)_.*_([^_]+)$", "\\1_\\2", mylist))
lst1
#$`20190712_1034`
#[1] "20190712_164755_1034" "20190712_164756_1034" "20190712_164757_1034"

#$`20190719_1001`
#[1] "20190719_164712_1001" "20190719_164713_1001"

#$`20190722_1054`
#[1] "20190722_153110_1054"

#$`20190813_1057`
#[1] "20190813_170215_17_1057" "20190813_170217_22_1057"

#$`20190828_1065`
#[1] "20190828_170318_14_1065"

sub 中,我们从字符串的开头 (^) 捕获 ((...)) 一个或多个数字 (\\d+),然后是 _,以及其他字符 (@987654333 @) 直到 _ 并捕获其余不是 _ ([^_]+) 的字符,直到字符串的结尾 ($)。在replacement 中,我们指定了捕获组的反向引用(\\1\\2)。本质上就是去掉中间的变化部分,并在开头和结尾保留固定的子字符串,然后用它来分割字符向量

【讨论】:

  • 这几乎行得通。当中间子串的长度不同时,它会以不同的方式对待它。在 mylist 上运行建议会导致正确的重复项,但带有额外两个字符的子字符串的字符除外,例如子字符串通常是 dddddd,但这些是 dddddd_dd
  • @APD 更新了帖子。希望能帮助到你。谢谢
【解决方案2】:

这是tidyr 中的extract 的替代方法。

library(tidyr)
result <- as.data.frame(mylist) %>%
  extract(1, into = c("date","var1","var2"),
          regex = "(^[0-9]{8}_[0-9]{6})_?(.*)?_([^_]+$)",
          remove = FALSE)
result
#                    mylist            date var1 var2
#1     20190625_165055_0f4e 20190625_165055      0f4e
#2     20190625_165056_0f4e 20190625_165056      0f4e
#3     20190625_165057_0f4e 20190625_165057      0f4e
#4     20190712_164755_1034 20190712_164755      1034
#...
#27 20190828_170318_14_1065 20190828_170318   14 1065
#28 20190828_170320_26_1065 20190828_170320   26 1065
#...

现在您可以根据这些变量轻松操作数据。

split(result,result$var2)
#$`0f22`
#                 mylist            date var1 var2
#29 20190917_165157_0f22 20190917_165157      0f22
#
#$`0f2a`
#                 mylist            date var1 var2
#18 20190813_152856_0f2a 20190813_152856      0f2a
#19 20190813_152857_0f2a 20190813_152857      0f2a
#...

【讨论】:

    【解决方案3】:

    我们可以使用extract 将日期部分和最后 4 个字符提取到单独的列中。然后我们使用group_split 根据这两列拆分数据。

    tibble::tibble(mylist) %>%
       tidyr::extract(mylist, c('col1', 'col2'), regex = '(.*?)_.*_(.*)', 
                      remove = FALSE) %>%
       dplyr::group_split(col1, col2, .keep = FALSE)
    
    
    #[[1]]
    # A tibble: 3 x 1
    #  mylist              
    #  <chr>               
    #1 20190712_164755_1034
    #2 20190712_164756_1034
    #3 20190712_164757_1034
    
    #[[2]]
    # A tibble: 2 x 1
    #  mylist              
    #  <chr>               
    #1 20190719_164712_1001
    #2 20190719_164713_1001
    
    #[[3]]
    # A tibble: 1 x 1
    #  mylist              
    #  <chr>               
    #1 20190722_153110_1054
    #...
    

    【讨论】:

      猜你喜欢
      • 2020-09-04
      • 2015-08-05
      • 2021-04-04
      • 2021-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多