间距矢量按规则模式

时间:2018-05-01 06:28:38

标签: r regex vector pattern-matching

我有一个载体

vec <- c("ab", "#4", "gw", "#29", "mp", "jq", "#35", "ez")

通常遵循两个不同字符串序列之间交替的模式(第一个序列全部按字母顺序排列,第二个序列是数字,符号为#)。

但是,有些情况下不会显示#字词:所以在上面mpjq之间,然后再在ez之后。我想定义一个填补空白的功能&#34;使用字符串#,以便输出:

 [1] "ab" "#4" "gw" "#29" "mp" "#" "jq" "#35" "ez" "#"
然后我将转换为数据框

   V1  V2
1  ab  #4
2  gw  #29
3  mp  #
4  jq  #35
5  ez  #

到目前为止,我的尝试相当笨重,并且依赖于遍历向量并填补空白。我有兴趣看到更优雅的解决方案。

我的解决方案

greplSpace <- function(pattern, replacement, x){

  j <- 1

  while( j < length(x) ){
    if(grepl(pattern, x[j+1]) ){
      j <- j+2 
    } else {
      x <- c( x[1:j], replacement, x[(j+1):length(x)] )
      j <- j+2
    }
  }

  if( ! grepl(pattern, tail(x,1) ) ){ x <- c(x, replacement) }

  return(x)
}

library(magrittr)

vec <- c("ab", "#4", "gw", "#29", "mp", "jq", "#35", "ez")

vec %>% greplSpace("#", "#", . ) %>% 
        matrix(ncol = 2, byrow = TRUE) %>%
        as.data.frame

4 个答案:

答案 0 :(得分:5)

S2开始,我们可以使用中的某些功能直接创建您的预期数据框。

vec

答案 1 :(得分:1)

您可以使用Base R:

首先将向量折叠为字符串,同时在需要时替换#。 然后只需使用read.csv

阅读
vec1=gsub("([a-z]),\\s*([a-z])|$","\\1,#,\\2",toString(vec))
read.csv(text=gsub("(#.*?),","\\1\n",vec1),h=F)
  V1  V2
1 ab  #4
2 gw #29
3 mp   #
4 jq #35
5 ez   #

说明:

  • 首先按toString
  • 将矢量折叠为字符串
  • 然后,如果,[a-z],\s*[a-z]或结尾即|$两侧都有字母,则会插入#
  • 然后在数字或#之后创建换行符,并将数据作为表格读入

你也可以这样做:

a=read.csv(h=F,text=toString(sub("([a-z]+)","\n\\1",vec)),na=c(" ",""))[1:2]
a
  V1   V2
1 ab   #4
2 gw  #29
3 mp <NA>
4 jq  #35
5 ez <NA>

 data.frame(replace(as.matrix(a),is.na(a),"#"))
  V1   V2
1 ab   #4
2 gw  #29
3 mp    #
4 jq  #35
5 ez    #

答案 2 :(得分:1)

以下是base R选项split。通过检查每个字符串中的“#”来创建逻辑索引,通过此分组变量将累积和和split原始向量转换为list('lst')。对于那些没有两个(最大长度)元素的list元素,最后通过NA赋值length<-。然后,rbind,将list个元素分成两列matrix。如果需要,请将这些NA转换为#

lst <-  split(vec, cumsum(!grepl("#", vec)))
out <- do.call(rbind, lapply(lst, `length<-`, max(lengths(lst))))
out[,2][is.na(out[,2])] <- "#" #not recommended though 
out
#  [,1] [,2] 
#1 "ab" "#4" 
#2 "gw" "#29"
#3 "mp" "#"  
#4 "jq" "#35"
#5 "ez" "#"  

如果我们需要as.data.frame输出

,请用data.frame换行

答案 3 :(得分:1)

另一种base可能性:

do.call(rbind, tapply(vec, cumsum(!grepl("^#", vec)), FUN = function(x){
  if(length(x) == 1) c(x, "#") else x}))

#   [,1] [,2] 
# 1 "ab" "#4" 
# 2 "gw" "#29"
# 3 "mp" "#"  
# 4 "jq" "#35"
# 5 "ez" "#"

说明:

  1. 检查vec中的元素是否以#开头,并取消它:!grepl("^#", vec);创建一个逻辑向量。

  2. 通过将cumsum应用于逻辑向量来创建分组变量(注意:1&amp; 2类似于@akrun)。

  3. 使用tapply将函数应用于由分组变量定义的vec的每个子集。检查if length1#。如果是这样,请使用尾随elseif(length(x) == 1) c(x, "#") else x填充,只返回子集:do.call(rbind,

  4. 将结果列表按行绑定在一起:# create a row index ri <- cumsum(!grepl("^#", vec)) # create a column index ci <- ave(ri, ri, FUN = seq_along) # create an empty matrix of desired dimensions m <- matrix(nrow = max(ri), ncol = 2) # assign 'vec' to matrix at relevant indices m[cbind(ri, ci)] <- vec # replace NA with '#' m[is.na(m)] <- "#"

  5. 另一个:

    data.table

    使用library(data.table) d <- data.table(vec) d[ , g := cumsum(!grepl("^#", vec))] dcast(d, g ~ rowid(g), value.var = "vec", fill = "#") # g 1 2 # 1: 1 ab #4 # 2: 2 gw #29 # 3: 3 mp # # 4: 4 jq #35 # 5: 5 ez # 。如上所述创建分组变量,并从长到宽重塑。

    <input type="button" value="startCut" onclick="moveMap()">