2015-06-23 5 views
10

Ich habe eine Spalte data.frame wo einige Leerzeichen sollten Trennzeichen einige nur ein Leerzeichen sein.Ersetzen Sie bestimmte Leerzeichen zu Tabs - Trennzeichen

#input data 
dat <- data.frame(x=c("A 2 2 textA1 textA2 Z1", 
         "B 4 1 textX1 textX2 textX3 Z2", 
         "C 3 5 textA1 Z3")) 
#        x 
# 1  A 2 2 textA1 textA2 Z1 
# 2 B 4 1 textX1 textX2 textX3 Z2 
# 3    C 3 5 textA1 Z3 

Du möchtest bis 5 Spalte data.frame konvertieren:

#expected output 
output <- read.table(text=" 
A 2 2 textA1 textA2 Z1 
B 4 1 textX1 textX2 textX3 Z2 
C 3 5 textA1 Z3",sep="\t") 
# V1 V2 V3     V4 V5 
# 1 A 2 2  textA1 textA2 Z1 
# 2 B 4 1 textX1 textX2 textX3 Z2 
# 3 C 3 5    textA1 Z3 

Im Wesentlichen 1. ändern müssen, 2., 3., und das letzte Feld auf eine Registerkarte (oder einem anderen Trennzeichen, wenn er es macht einfacher zu codieren).

mit regex Spielen gibt nicht etwas Nützliches noch ...

Hinweis 1: In realen Daten I 1. ersetzen müssen, 2., 3., ..., 19. und die letzten Räume Registerkarten.
Hinweis2: Es gibt kein Muster in V4, Text kann alles sein.
Hinweis3: Letzte Spalte ist ein Wort mit variabler Länge.

+2

Versuch 'v1 <- gsub ("^ ([^] +) \\ s + ([^] +) \\ s + ([^] +) \\ s +",' \\ 1 , \\ 2, \\ 3, ', dat $ x); read.table (text = sub (' + (? = [^] + $) ',', ', V1, perl = WAHR), sep = ",") ' – akrun

+0

Dank @akrun, bitte fügen Sie Ihre Kommentar als Antwort. – zx8754

+0

@akrun siehe Hinweis, deine Lösung würde immer noch funktionieren, muss nur auf '\\ 1, \\ 2, ... \\\ 19 'erweitert werden ...' – zx8754

Antwort

8

Versuchen

v1 <- gsub("^([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+", '\\1,\\2,\\3,', dat$x) 
read.table(text=sub(' +(?=[^ ]+$)', ',', v1, perl=TRUE), sep=",") 
# V1 V2 V3     V4 V5 
#1 A 2 2  textA1 textA2 Z1 
#2 B 4 1 textX1 textX2 textX3 Z2 
#3 C 3 5    textA1 Z3 

Oder eine Option, inspiriert von @ Tensibai der Post

n <- 3 
fpat <- function(n){ 
    paste0('^((?:\\w+){', n,'})([\\w ]+)\\s+(\\w+)$') 
} 

read.table(text=gsub(fpat(n), "\\1'\\2' \\3", dat$x, perl=TRUE)) 
# V1 V2 V3     V4 V5 
#1 A 2 2  textA1 textA2 Z1 
#2 B 4 1 textX1 textX2 textX3 Z2 
#3 C 3 5    textA1 Z3 

Weitere Säulen,

n <- 19 
v1 <- "A 24 34343 212 zea4 2323 12343 111 dsds 134d 153xd 153xe 153de 153dd dd dees eese tees3 zee2 2353 23335 23353 ddfe 3133" 

read.table(text=gsub(fpat(n), "\\1'\\2' \\3", v1, perl=TRUE), sep='') 
# V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13 V14 V15 
#1 A 24 34343 212 zea4 2323 12343 111 dsds 134d 153xd 153xe 153de 153dd dd 
# V16 V17 V18 V19     V20 V21 
#1 dees eese tees3 zee2 2353 23335 23353 ddfe 3133 
+1

Sorry, ich kann die Bearbeitung nicht zweimal upvoten ist brilliant (ich hatte nicht die Idee, das Muster innerhalb einer Funktion zu machen, und der Gsub-Aufruf, um die zitierte Interpretation von read.table zu nutzen ist großartig) Ich muss noch lernen – Tensibai

+1

@Tensibai Die Bearbeitung war nur möglich, weil von deinem schlauen Code. Ich habe eine Weile nachgedacht, aber ich habe es nicht richtig verstanden. Danke für die Unterstützung. – akrun

3

kann hier eine verdrehte Art und Weise sein, dass zu gehen funktioniert unabhängig die Anzahl der "Wörter", die Sie haben (und das funktioniert mit Ihren Daten); es auf der Anzahl der ALPHANUM Zeichen in Ihren „Worten“ im Vergleich zu der Anzahl der ALPHANUM Zeichen in den anderen Feldern basiert:

res <- gsub("\\w{3,}\\K\\t(?=\\w{3,})", " ", gsub(" ", "\t", dat$x), perl=T) 
res 
# [1] "A\t2\t2\ttextA1 textA2\tZ1"  "B\t4\t1\ttextX1 textX2 textX3\tZ2" "C\t3\t5\ttextA1\tZ3" 

read.table(text=res, sep="\t") 
# V1 V2 V3     V4 V5 
#1 A 2 2  textA1 textA2 Z1 
#2 B 4 1 textX1 textX2 textX3 Z2 
#3 C 3 5    textA1 Z3 

EDIT: Eine ganz andere Art und Weise zu gehen, nur auf der Anzahl der Basis Räume k Sie vor dem letzten ersetzen müssen:

k <- 3 # in your example 
res <- sapply(as.character(dat$x), 
       function(x, k){ 
       pos_sp <- gregexpr(" ", x)[[1]] 
       x <- strsplit(x, "")[[1]] 
       if (length(pos_sp) > k+1) pos_sp <- pos_sp[c(1:k, length(pos_sp))] 
       x[pos_sp] <- "\t" 
       x <- paste(x, collapse="") 
       }, k=k) 

read.table(text=res, sep="\t") 
# V1 V2 V3     V4 V5 
# 1 A 2 2  textA1 textA2 Z1 
# 2 B 4 1 textX1 textX2 textX3 Z2 
# 3 C 3 5    textA1 Z3 
6

mit einer variablen Anzahl von Spalten:

library(stringr) 
cols <- 3 
m <- str_match(dat$x, paste0("((?:\\w+){" , cols , "})([\\w ]+) (\\w+)")) 
t <- paste0(gsub(" ", "\t", m[,2]), m[,3], "\t", m[,4]) 

> read.table(text=t,sep="\t") 
    V1 V2 V3     V4 V5 
1 A 2 2  textA1 textA2 Z1 
2 B 4 1 textX1 textX2 textX3 Z2 
3 C 3 5    textA1 Z3 

Ändern Sie die Anzahl der Spalten, um zu sagen, wie viele Sie möchten. Für den regulären Ausdruck:

  • ((?:\\w+){3}) Die 3 Wiederholungen {3} der nicht einfangende Gruppe (?:\w+) der w+ durch einen Raum
  • ([\\w ]+) (\w+) capture [\w ]+ Der freie Text aus alphanumerischen Zeichen oder Leerzeichen gefolgt mindestens ein alphanumerisches Zeichen matche Erfassen von einem Leerzeichen und der Capture das letzte Wort mit \w+

Sobald das erledigt, fügen Sie die 3 Teile zurück von str_match kümmert sich um den Austausch der Räume in der ersten Gruppe m[,2] durch Tabs.

m[,1] ist das ganze Spiel, so dass es hier nicht verwendet wird.


Alte Antwort:

Eine grundlegende ein Matching basiert auf einer festgelegten Anzahl von Feldern:

> read.table(text=gsub("(\\w+) (\\w+) (\\w+) ([\\w ]+) (\\w+)$","\\1\t\\2\t\\3\t\\4\t\\5",dat$x,perl=TRUE),sep="\t") 
    V1 V2 V3     V4 V5 
1 A 2 2  textA1 textA2 Z1 
2 B 4 1 textX1 textX2 textX3 Z2 
3 C 3 5    textA1 Z3 

so viele hinzufügen (\ w +) Sie vor wünschen, und erhöhen die Anzahl der \ 1 (Rückbezüge)