2010-02-11 8 views
43

I ein Objekt, eine Textzeichenfolge enthalten:Chopping eine Zeichenkette in einen Vektor mit fester Breite Zeichenelemente

x <- "xxyyxyxy" 

und ich möchte, dass mit jedem Element in einen Vektor drehen zwei Buchstaben enthält:

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

es scheint wie die strsplit() sollte mein Ticket sein, aber da ich keinen regulären Ausdruck foo habe, kann ich nicht herausfinden, wie diese Funktion die Zeichenfolge hacken, wie ich es will. Wie soll ich das machen?

+0

so möchten Sie die Zeichenfolge in Intervallen basierend auf einer bekannten Anzahl, strsplit() arbeitet auf festen Strings oder reg exps, aber klingt wie Sie es durch Länge getan werden wollen? – Dan

+0

das ist genau richtig. Ich möchte es basierend auf der Länge machen. strsplit möchte einen Regex-Ausdruck für das Trennzeichen finden, und ich habe kein Trennzeichen. –

+1

Es gibt eine viel schnellere Antwort in stackoverflow.com zwei Jahre später. [http://stackoverflow.com/a/11619681/168976](http://stackoverflow.com/a/11619681/168976). – wind

Antwort

52

substring ist die bester 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)) 
+6

Nur hinzufügen für die Allgemeinheit, dass, wenn wir alle 'n' Zeichen statt jeder 2 wollten, wäre es: substring (x, seq (1, nchar (x), n), seq (n, nchar (x), n)) ' – MichaelChirico

6

Gesamt Hack, JD, aber es

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

Das ist genau der Hack den ich programmiert habe. natürlich würde ich eine Schleife statt Sapply machen;) –

6

hier gemacht wird ist eine Möglichkeit, aber nicht regexen mit:

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

strsplit wird als problematisch, schauen Sie sich ein regexp wie diese

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

es wird an den richtigen Punkten aufgeteilt, aber nichts ist übrig.

könnten Sie Teilzeichenfolge verwenden & Freunde

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

das ist eine süße Art, es auch zu tun. Ich denke, ich habe mich mental an srtsplit() hängen lassen, weil strsplit (x, "") genau das ist, was ich will. –

+0

Wie funktioniert der Teilstring, wenn Sie die Zeichenfolge nach 3 Zeichen zerschneiden müssen? sieht so aus, als würde es nur für 2-Character-Chops funktionieren. – MySchizoBuddy

19

Wie wäre es

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

Grundsätzlich fügen Sie ein Trennzeichen (hier "„) und dann Verwendung strsplit

18

Hier ist eine schnelle Lösung, die die Zeichenfolge in Zeichen zerlegt, dann die geraden Elemente Pasten zusammen und die ungeraden Elemente.

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, wi Die 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 
2

ATTENTION mit Teilzeichenfolge, wenn Stringlänge nicht ein Vielfaches von Ihrer gewünschte Länge ist, dann müssen Sie ein + (n-1) in der zweiten Folge:

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

Du Mann, bist ein Genie! Ich habe 'x <- paste0 (x, strrep (" ", n - (nchar (x) %% n)))' verwendet, aber das ist viel bequemer! –

2

Eine Hilfsfunktion:

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

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

Nun, habe ich den folgenden Pseudo-Code, 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

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 Teilvektor nach innen, aber nicht ein Vektor.

0

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

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