2010-02-11 53 views
43

我有一个包含一个文本串的对象的矢量:斩波字符串转换成固定的宽度字符要素

x <- "xxyyxyxy" 

和欲把它转换成一个向量与含有两个字母的每个元素:

[1] "xx" "yy" "xy" "xy" 

它似乎像strsplit()应该是我的票,但由于我没有正则表达式foo,我无法弄清楚如何使这个函数按照我想要的方式截断字符串。我应该怎么做?

+0

所以要串在基于已知计数的时间间隔分割,strsplit()适用于固定的字符串或章EXPS,但听起来像你想它由长度做了什么? – Dan 2010-02-11 19:26:24

+0

完全正确。我想根据长度来做。 strsplit想匹配正则表达式的分隔符,我没有分隔符。 – 2010-02-11 19:28:59

+1

两年后,在stackoverflow.com上有更快的答案。 [http://stackoverflow.com/a/11619681/168976](http://stackoverflow.com/a/11619681/168976)。 – wind 2013-11-27 08:15:22

回答

52

使用子是最佳方法:

substring(x, seq(1,nchar(x),2), seq(2,nchar(x),2)) 

但这里有plyr一个解决方案:

library("plyr") 
laply(seq(1,nchar(x),2), function(i) substr(x, i, i+1)) 
+6

只是增加一般性,如果我们需要每个'n'字符而不是每2个字符,它会是:substring(x,seq(1,nchar(x),n),seq(n,nchar(x), n))' – MichaelChirico 2015-06-17 22:01:53

6

总劈,JD,但它得到它做

x <- "xxyyxyxy" 
c<-strsplit(x,"")[[1]] 
sapply(seq(2,nchar(x),by=2),function(y) paste(c[y-1],c[y],sep="")) 
[1] "xx" "yy" "xy" "xy" 
+0

这正是我编码的黑客。当然,我会做一个循环,而不是sapply;) – 2010-02-11 19:33:16

6

这里有一种方法,但不使用使用regexen:

a <- "xxyyxyxy" 
n <- 2 
sapply(seq(1,nchar(a),by=n), function(x) substr(a, x, x+n-1)) 
10

strsplit将是有问题的,看这样的正则表达式

strsplit(z, '[[:alnum:]]{2}') 

它会分裂在正确的点,但没有剩下。

你可以使用子&朋友

z <- 'xxyyxyxy' 
idx <- 1:nchar(z) 
odds <- idx[(idx %% 2) == 1] 
evens <- idx[(idx %% 2) == 0] 
substring(z, odds, evens) 
+0

这是一个很好的做法。我想我让自己在思想上迷上了srtsplit(),因为strsplit(x,“”)与我想要的有多接近。 – 2010-02-11 19:46:33

+0

如果你必须在3个字符后切断字符串,子字符串如何工作?看起来只能用于2个字符的印章。 – MySchizoBuddy 2015-07-27 17:23:56

19

如何

strsplit(gsub("([[:alnum:]]{2})", "\\1 ", x), " ")[[1]] 

基本上,添加一个分隔符(这里““)和然后使用strsplit

18

这里是分割字符串变换成字符的快速的解决方案,然后将粘贴甚至元素和奇数元素在一起。

x <- "xxyyxyxy" 
sst <- strsplit(x, "")[[1]] 
paste0(sst[c(TRUE, FALSE)], sst[c(FALSE, TRUE)]) 

基准设定:

library(microbenchmark) 

GSee <- function(x) { 
    sst <- strsplit(x, "")[[1]] 
    paste0(sst[c(TRUE, FALSE)], sst[c(FALSE, TRUE)]) 
} 

Shane1 <- function(x) { 
    substring(x, seq(1,nchar(x),2), seq(2,nchar(x),2)) 
} 

library("plyr") 
Shane2 <- function(x) { 
    laply(seq(1,nchar(x),2), function(i) substr(x, i, i+1)) 
} 

seth <- function(x) { 
    strsplit(gsub("([[:alnum:]]{2})", "\\1 ", x), " ")[[1]] 
} 

geoffjentry <- function(x) { 
    idx <- 1:nchar(x) 
    odds <- idx[(idx %% 2) == 1] 
    evens <- idx[(idx %% 2) == 0] 
    substring(x, odds, evens) 
} 

drewconway <- function(x) { 
    c<-strsplit(x,"")[[1]] 
    sapply(seq(2,nchar(x),by=2),function(y) paste(c[y-1],c[y],sep="")) 
} 

KenWilliams <- function(x) { 
    n <- 2 
    sapply(seq(1,nchar(x),by=n), function(xx) substr(x, xx, xx+n-1)) 
} 

RichardScriven <- function(x) { 
    regmatches(x, gregexpr("(.{2})", x))[[1]] 
} 

基准1:

x <- "xxyyxyxy" 

microbenchmark(
    GSee(x), 
    Shane1(x), 
    Shane2(x), 
    seth(x), 
    geoffjentry(x), 
    drewconway(x), 
    KenWilliams(x), 
    RichardScriven(x) 
) 

# Unit: microseconds 
#    expr  min  lq median  uq  max neval 
#   GSee(x) 8.032 12.7460 13.4800 14.1430 17.600 100 
#   Shane1(x) 74.520 80.0025 84.8210 88.1385 102.246 100 
#   Shane2(x) 1271.156 1288.7185 1316.6205 1358.5220 3839.300 100 
#   seth(x) 36.318 43.3710 45.3270 47.5960 67.536 100 
#  geoffjentry(x) 9.150 13.5500 15.3655 16.3080 41.066 100 
#  drewconway(x) 92.329 98.1255 102.2115 105.6335 115.027 100 
#  KenWilliams(x) 77.802 83.0395 87.4400 92.1540 163.705 100 
# RichardScriven(x) 55.034 63.1360 65.7545 68.4785 108.043 100 

基准2:

现在,无线更大的数据。

x <- paste(sample(c("xx", "yy", "xy"), 1e5, replace=TRUE), collapse="") 

microbenchmark(
    GSee(x), 
    Shane1(x), 
    Shane2(x), 
    seth(x), 
    geoffjentry(x), 
    drewconway(x), 
    KenWilliams(x), 
    RichardScriven(x), 
    times=3 
) 

# Unit: milliseconds 
#    expr   min   lq  median   uq   max neval 
#   GSee(x) 29.029226 31.3162690 33.603312 35.7046155 37.805919  3 
#   Shane1(x) 11754.522290 11866.0042600 11977.486230 12065.3277955 12153.169361  3 
#   Shane2(x) 13246.723591 13279.2927180 13311.861845 13371.2202695 13430.578694  3 
#   seth(x) 86.668439 89.6322615 92.596084 92.8162885 93.036493  3 
#  geoffjentry(x) 11670.845728 11681.3830375 11691.920347 11965.3890110 12238.857675  3 
#  drewconway(x) 384.863713 438.7293075 492.594902 515.5538020 538.512702  3 
#  KenWilliams(x) 12213.514508 12277.5285215 12341.542535 12403.2315015 12464.920468  3 
# RichardScriven(x) 11549.934241 11730.5723030 11911.210365 11989.4930080 12067.775651  3 
2

注意力子,如果字符串长度是不是你要求的长度的倍数,那么你就需要一个+(N-1)第二序列

substring(x,seq(1,nchar(x),n),seq(n,nchar(x)+n-1,n)) 
+0

你是男人,是天才!我用'x < - paste0(x,strrep(“”,n - (nchar(x)%% n)))',但这样更方便! – 2017-10-08 19:02:42

2

辅助函数:

fixed_split <- function(text, n) { 
    strsplit(text, paste0("(?<=.{",n,"})"), perl=TRUE) 
} 

fixed_split(x, 2) 
[[1]] 
[1] "xx" "yy" "xy" "xy" 
1

那么,我用下面的伪代码来完成这个任务:

  1. 在每个长度为n的块上插入一个特殊序列。
  2. 按照所述序列拆分字符串。

在代码中,我做了

chopS <- function(text, chunk_len = 2, seqn) 
{ 
    # Specify select and replace patterns 
    insert <- paste("(.{",chunk_len,"})", sep = "") 
    replace <- paste("\\1", seqn, sep = "") 

    # Insert sequence with replaced pattern, then split by the sequence 
    interp_text <- gsub(pattern, replace, text) 
    strsplit(interp_text, seqn) 
} 

这里面返回与分裂向量的列表,虽然不是矢量。

0

以下是一个使用stringi::stri_sub()的选项。尝试:

x <- "xxyyxyxy" 
stringi::stri_sub(x, seq(1, stringi::stri_length(x), by = 2), length = 2) 
# [1] "xx" "yy" "xy" "xy"