Eine Zeichenfolge in einen Vektor mit Zeichenelementen fester Breite zerschneiden

Ich habe ein Objekt mit einer Textzeichenfolge:

x <- "xxyyxyxy" 

und ich möchte das in einen Vektor aufteilen, wobei jedes Element zwei Buchstaben enthält:

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

Es scheint, als ob der strsplit mein Ticket sein sollte, aber da ich keinen regulären Ausdruck foo habe, kann ich nicht herausfinden, wie man diese function in Stücke strsplit , wie ich es will. Wie soll ich das machen?

    Die Verwendung von substring ist der beste Ansatz:

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

    Aber hier ist eine Lösung mit plyr:

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

    Hier ist eine schnelle Lösung, die die Zeichenfolge in Zeichen aufteilt und dann die geraden Elemente und die ungeraden Elemente zusammenfügt.

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

    Benchmark-Setup:

     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]] } 

    Benchmark 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 

    Benchmark 2:

    Jetzt mit größeren Daten.

     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 

    Wie wäre es mit

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

    Im Grunde fügen Sie ein Trennzeichen (hier “”) hinzu und verwenden Sie dann strsplit

    strsplit wird problematisch sein, schau dir eine regexp so an

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

    Es wird an den richtigen Stellen gespalten, aber nichts ist übrig.

    Sie könnten Teilzeichenfolge und Freunde verwenden

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

    Hier ist ein Weg, aber nicht mit Regexen:

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

    Total hack, JD, aber es macht es fertig

     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" 

    Eine Hilfsfunktion:

     fixed_split < - function(text, n) { strsplit(text, paste0("(?<=.{",n,"})"), perl=TRUE) } fixed_split(x, 2) [[1]] [1] "xx" "yy" "xy" "xy" 

    ACHTUNG mit Teilstring, wenn die Stringlänge kein Vielfaches der von Ihnen gewünschten Länge ist, dann benötigen Sie ein + (n-1) in der zweiten Sequenz:

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

    Nun, ich habe den folgenden Pseudocode verwendet, um diese Aufgabe zu erfüllen:

    1. Fügen Sie für jeden Block der Länge n eine spezielle Sequenz ein.
    2. Teilen Sie die Zeichenfolge durch die Sequenz.

    Im Code habe ich es getan

     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) } 

    Dies gibt eine Liste mit dem aufgeteilten Vektor zurück, jedoch keinen Vektor.

    Mit C ++ kann man sogar noch schneller sein. Vergleiche mit GSee’s Version :

     GSee < - function(x) { sst <- strsplit(x, "")[[1]] paste0(sst[c(TRUE, FALSE)], sst[c(FALSE, TRUE)]) } rstub <- Rcpp::cppFunction( code = ' CharacterVector strsplit2(const std::string& hex) { unsigned int length = hex.length()/2; CharacterVector res(length); for (unsigned int i = 0; i < length; ++i) { res(i) = hex.substr(2*i, 2); } return res; }') x <- "xxyyxyxy" all.equal(GSee(x), rstub(x)) #> [1] TRUE microbenchmark::microbenchmark(GSee(x), rstub(x)) #> Unit: microseconds #> expr min lq mean median uq max neval #> GSee(x) 4.272 4.4575 41.74284 4.5855 4.7105 3702.289 100 #> rstub(x) 1.710 1.8990 139.40519 2.0665 2.1250 13722.075 100 set.seed(42) x < - paste(sample(c("xx", "yy", "xy"), 1e5, replace = TRUE), collapse = "") all.equal(GSee(x), rstub(x)) #> [1] TRUE microbenchmark::microbenchmark(GSee(x), rstub(x)) #> Unit: milliseconds #> expr min lq mean median uq max neval #> GSee(x) 17.931801 18.431504 19.282877 18.738836 19.47943 27.191390 100 #> rstub(x) 3.197587 3.261109 3.404973 3.341099 3.45852 4.872195 100 

    Hier ist eine Option mit stringi::stri_sub() . Versuchen:

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