【问题标题】:Splitting a string without delimiters in R在R中拆分没有分隔符的字符串
【发布时间】:2014-01-08 14:08:58
【问题描述】:

我在R 中有一个字符向量,每个元素都包含一个字符串 - 让我们使用这个示例:

my.files <- c("AWCallibration#NoneBino-3", "AWExperiment1#NoneBino-1", "AWExperiment2#NonemonL-2"
)

我想从这些字符串中提取某些信息 -

  1. 首先,两个大写字母字符(在这种情况下,总是"AW"
  2. 试验是用于校准 ("Callibration") 还是数据收集 - 如果是后者,则使用哪种条件("Experiment1""Experiment2"
  3. 在此特定试验中使用了哪个子条件("Bino""monL"
  4. 子条件的重复("1""2"

我第一次尝试使用strsplit,但这似乎只适用于带有常规分隔符的情况,例如"_"substring 似乎更适合我的需求,但实际上并没有起作用,因为在常规位置不会发生拆分("Experiment1" 是十一个元素长,"Callibration" 是十二个元素)。

我怀疑使用正则表达式可能是这里的答案,但我不知道如何解释拆分之间的不同长度。

【问题讨论】:

  • 使用substring,它是矢量化的,可以同时作用于所有元素。是的,您将需要多个条件和多个子字符串调用
  • substr 仍然存在与substring 相同的问题 - 如何解决每次未在同一元素上发生的拆分?
  • 您不必在一个条件和一行中做出所有决定,对吗? (提示:如果您想将条件折叠成一行,请在 else 条件中使用嵌套的 ifelse :)
  • 你是对的!我只是有一个错误,就是试图让一切尽可能紧凑(通常对我不利)。

标签: regex string r split


【解决方案1】:

可以一一提取信息:

first <- substr(my.files, 1, 2)
# [1] "AW" "AW" "AW"

second <- sub("^..(.*)#.*", "\\1", my.files)
# [1] "Callibration" "Experiment1"  "Experiment2" 

third <- sub("^.*#None(.*)-\\d+$", "\\1", my.files)
# [1] "Bino" "Bino" "monL"

fourth <- sub(".*-(\\d+)$", "\\1", my.files)
# [1] "3" "1" "2"

多合一命令:

strsplit(my.files, "(?<=^..)(?=[A-Z])|#None|-", perl = TRUE)
# [[1]]
# [1] "AW"           "Callibration" "Bino"         "3"           
# 
# [[2]]
# [1] "AW"          "Experiment1" "Bino"        "1"          
# 
# [[3]]
# [1] "AW"          "Experiment2" "monL"        "2"          

【讨论】:

  • 这是一个完美的分步指南,非常感谢。现在让我低下头并通过正则表达式 - 这是一个很好的学习练习。
  • @luser 正则表达式是一个非常强大的工具。学习是值得的。
  • 我很密集 - sub("^..(.*)#.*", "\\1", my.files) 如何产生“Callibration”等?据我所知,正则表达式指定的模式基本上是整个字符串 - 两个字符,加上任意数量的字符,直到散列,然后是任意数量的字符,直到字符串的结尾。 sub 然后似乎将字符串替换为另一个 - “\\1”。我读错了“子”参数的第二部分吗?
  • @luser 你是对的。 "\\1" 表示将整个字符串替换为第一个括号 "()" 内的字符串部分。在这种情况下,它是第二个字符之后直到(但不包括)"#" 符号的所有内容。
  • @luser 看看这个问题\1的含义:stackoverflow.com/questions/15825872/…顺便说一句:我添加了一个额外的解决方案。
【解决方案2】:

这里有几个不同的解决方案:

gsubfn::strapplyc试试这个:

library(gsubfn)
pat <- "(..)(.*)#None(.*)-(.*)"
strapplyc(my.files, pat, simplify = rbind)

给出:

     [,1] [,2]           [,3]   [,4]
[1,] "AW" "Callibration" "Bino" "3" 
[2,] "AW" "Experiment1"  "Bino" "1" 
[3,] "AW" "Experiment2"  "monL" "2" 

注意gsubfn package的开发版本中有一个read.pattern命令可以像这样使用上面的patread.pattern(text = my.files, pattern = pat, as.is = TRUE)

sub/strsplit 这是另一种解决方案。它在第二个字符后插入一个减号,然后用减号或#None 分割每个条带:

my.files2 <- sub("(..)", "\\1-", my.files)
do.call(rbind, strsplit(my.files2, "-|#None"))

给出:

     [,1] [,2]           [,3]   [,4]
[1,] "AW" "Callibration" "Bino" "3" 
[2,] "AW" "Experiment1"  "Bino" "1" 
[3,] "AW" "Experiment2"  "monL" "2"

gsub/read.table 这里我们使用gsub 在前两个字符后插入一个减号,并将#None 替换为减号。然后我们使用read.table 和一个负号sep 来读取它:

withMinus <- gsub("^(..)|#None", "\\1-", my.files)
read.table(text = withMinus, sep = "-", as.is = TRUE)

  V1           V2   V3 V4
1 AW Callibration Bino  3
2 AW  Experiment1 Bino  1
3 AW  Experiment2 monL  2

修订:

  • 更正和第二种解决方案。
  • 第三种解决方案。

【讨论】:

  • 这是一个非常好的替代解决方案集合,也满足了我莫名其妙的需要,尽可能少行完成所有事情。
猜你喜欢
  • 2012-11-07
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 2021-05-30
  • 2019-11-15
  • 1970-01-01
  • 2022-11-03
  • 2023-03-14
相关资源
最近更新 更多