【问题标题】:Replace element in vector based on first letter of character string根据字符串的第一个字母替换向量中的元素
【发布时间】:2016-09-22 11:32:49
【问题描述】:

考虑以下向量:

ID <- c("A1","B1","C1","A12","B2","C2","Av1")

names <- c("ALPHA","BRAVO","CHARLIE","AVOCADO")

我想根据向量names 的第一个字母将向量ID 中每个元素的第一个字符替换为向量names。我还想在0:9 之间的每个数字之前添加一个_0

请注意,Av1AVOCADO 元素会使事情有些偏离,尤其是在 Av1 中使用小写的 v

结果应该是这样的:

res <- c("ALPHA_01","BRAVO_01","CHARLIE_01","ALPHA_12","BRAVO_02","CHARLIE_02", "AVOCADO_01")

我知道应该使用 regex 完成,但我已经尝试了 2 天,但没有任何结果。

【问题讨论】:

  • 扔掉一点 - 实际上,这是非常重要的一点。 BINGO 有什么可以替代 Bi3?和BROTHERBro3?好吧,我的意思是不清楚你想如何定义模式。
  • @WiktorStribiżew 我不确定你的意思?我希望将A 替换为ALPHA,将Av 替换为AVOCADO,并插入_0
  • 好的,但是ALPHAA开头,A1Av1A开头,你怎么知道有AVOCADO在这之后处理需要 2 个前字符用于模式?
  • 我不知道,这就是为什么我要问比我更有知识的人。

标签: r regex replace


【解决方案1】:

我们可以使用gsubfn

library(gsubfn)
#remove the number part from 'ID' (using `sub`) and get the unique elements
nm1 <- unique(sub("\\d+", "", ID))
#using gsubfn, replace the non-numeric elements with the matching 
#key/value pair in the replacement
#finally format to add the "_" with sub
sub("(\\d+)$", "_0\\1", gsubfn("(\\D+)", as.list(setNames(names, nm1)), ID))
#[1] "ALPHA_01"   "BRAVO_01"   "CHARLIE_01" "ALPHA_02" 
#[5] "BRAVO_02"   "CHARLIE_02" "AVOCADO_01"

(\\d+) 表示一个或多个数字元素,(\\D+) 是一个或多个非数字元素。我们将它包装在括号内以作为一个组捕获并将其替换为反向引用(\\1 - 因为它是捕获组的第一个反向引用)。

更新

如果条件是仅将 0 附加到数字小于 10 的那些 'ID',那么我们可以使用第二个 gsubfnsprintf 来做到这一点

gsubfn("(\\d+)", ~sprintf("_%02d", as.numeric(x)), 
                      gsubfn("(\\D+)", as.list(setNames(names, nm1)), ID))
#[1] "ALPHA_01"   "BRAVO_01"   "CHARLIE_01" "ALPHA_12" 
#[5]  "BRAVO_02"   "CHARLIE_02" "AVOCADO_01"

【讨论】:

  • 谢谢 akrun - 你能解释一下subgsubfn 函数中每个符号的实际含义吗?我无法从帮助文件中得到正面或反面
  • @Bonono 我添加了一些解释。如果您遇到问题,请告诉我
  • 是的,这是有道理的——太好了!帮助文件看起来很复杂,很难清楚地理解。我怎么知道什么时候放+$
  • @Bonono 这些是元字符 + 表示一个或多个 * 为零或多个(当您不确定 100% 是否会出现一个数字 (\\d*) 时,$表示字符串的结尾,^ 是字符串的开头。
  • @Bonono 更新了帖子。
【解决方案2】:

通过基础 R 执行此操作,我们可以搜索第二个字符 V(如在 AVOCADO 中),如果为真则为 2 个字符,否则为 1 个字符。这将捕获 AVOCADO 和 ALPHA。然后,我们将这些子字符串与从 ID 中提取的字母进行匹配(也将 toupper 转换为使用 AV 捕获 Av)。最后粘贴_0以及每个ID中找到的数字

paste0(names[match(toupper(sub('\\d+', '', ID)), 
               ifelse(substr(names, 2, 2) == 'V', substr(names, 1, 2), 
                                substr(names, 1, 1)))],'_0', sub('\\D+', '', ID))
#[1] "ALPHA_01" "BRAVO_01" "CHARLIE_01" "ALPHA_02" "BRAVO_02" "CHARLIE_02" "AVOCADO_01"

【讨论】:

    猜你喜欢
    • 2015-05-06
    • 1970-01-01
    • 2018-12-12
    • 2022-12-11
    • 2019-10-04
    • 1970-01-01
    • 2014-05-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多