2013-11-03 166 views
4

我想前兩個冒號分割字符串的列,但不能對任何後續冒號:分割字符串

my.data <- read.table(text=' 

my.string some.data 
123:34:56:78 -100 
87:65:43:21 -200 
a4:b6:c8888 -300 
11:bbbb:ccccc -400 
uu:vv:ww:xx -500', header = TRUE) 

desired.result <- read.table(text=' 

my.string1 my.string2 my.string3 some.data 
123   34   56:78   -100 
87   65   43:21   -200 
a4   b6   c8888   -300 
11   bbbb  ccccc   -400 
uu   vv   ww:xx   -500', header = TRUE) 

我已經廣泛搜查,以下問題是最接近我目前的窘境:

Split on first comma in string

謝謝你的任何建議。我更喜歡使用基R.

編輯:

字符數之前第一結腸並不總是2和第一兩個冒號之間的字符數並不總是2。所以,我編輯了這個例子來反映這一點。

回答

3

在基礎R:

> my.data <- read.table(text=' 
+ 
+ my.string some.data 
+ 123:34:56:78 -100 
+ 87:65:43:21 -200 
+ a4:b6:c8888 -300 
+ 11:bbbb:ccccc -400 
+ uu:vv:ww:xx -500', header = TRUE,stringsAsFactors=FALSE) 
> m <- regexec ("^([^:]+):([^:]+):(.*)$",my.data$my.string) 
> my.data$my.string1 <- unlist(lapply(regmatches(my.data$my.string,m),'[',c(2))) 
> my.data$my.string2 <- unlist(lapply(regmatches(my.data$my.string,m),'[',c(3))) 
> my.data$my.string3 <- unlist(lapply(regmatches(my.data$my.string,m),'[',c(4))) 
> my.data 
     my.string some.data my.string1 my.string2 my.string3 
1 123:34:56:78  -100  123   34  56:78 
2 87:65:43:21  -200   87   65  43:21 
3 a4:b6:c8888  -300   a4   b6  c8888 
4 11:bbbb:ccccc  -400   11  bbbb  ccccc 
5 uu:vv:ww:xx  -500   uu   vv  ww:xx 

你會請參閱我已使用stringsAsFactors=FALSE確保my.string可以作爲字符串的向量處理。

+0

這是一個很好的答案,但我想知道'm'中的數字是什麼意思? –

+1

'regexec()'返回一個匹配對象,其中每個匹配的第一個元素是每個組開始匹配位置的向量(首先整個匹配,所以第一個顯式組是#2,第二個是#3,等等),第二個是矢量匹配長度。 'regmatches()'然後使用該匹配數據從字符串向量中提取匹配的文本。 – Simon

0

難道你不能只在第一個冒號的strsplit(sub(「:\ s *」,XX,x),XX)(如你在其他問題的鏈接中列出的例子)再次分裂第一個冒號?

+0

我不這麼認爲。當你嘗試它時它有效嗎? –

3

使用包stringr

str_match(my.data$my.string, "(.+?):(.+?):(.*)") 

    [,1]   [,2] [,3] [,4] 
[1,] "123:34:56:78" "123" "34" "56:78" 
[2,] "87:65:43:21" "87" "65" "43:21" 
[3,] "a4:b6:c8888" "a4" "b6" "c8888" 
[4,] "11:bbbb:ccccc" "11" "bbbb" "ccccc" 
[5,] "uu:vv:ww:xx" "uu" "vv" "ww:xx" 

UPDATE: 與最新的例子(上圖)和哈德利的評論解決方案:

str_split_fixed(my.data$my.string, ":", 3) 
    [,1] [,2] [,3] 
[1,] "123" "34" "56:78" 
[2,] "87" "65" "43:21" 
[3,] "a4" "b6" "c8888" 
[4,] "11" "bbbb" "ccccc" 
[5,] "uu" "vv" "ww:xx" 
+0

還有'str_split_fixed' – hadley

1

用「,」替換前兩個「:」,然後拆分「,」。

x <- gsub("([[:alnum:]]*):([[:alnum:]]*):(.)","\\1,\\2,\\3","12:34:56:78") 

strsplit(X 「」)

應用到數據幀

a.list <- sapply(my.data$my.string, function(x) strsplit(gsub("([[:alnum:]]*):([[:alnum:]]*):(.)","\\1,\\2,\\3",x),",")) 
a.vect <- unlist(a.list) 
a.df <- as.data.frame(matrix(a.vect,ncol=3,byrow=T), stringsAsFactors = F) 
names(a.df) <- c("my.string1", "my.string2", "my.string3") 
a.df$some.data <- my.data$some.data 
a.df 
+0

這很簡潔,但它需要使用字符來代替可能永遠不會出現在字符串其餘部分的逗號。 – topchef

+0

@topchef真的,像「ZZZZZZZZZZ8888888888」可能會這樣:) – ndr

1

我有點太遲了。我的解決方案與早期的答案有很大的重疊。然而,它可能是有用的人:

# Replace first two colons with commas. 
new.string = gsub(pattern="(^[^:]+):([^:]+):(.+$)", 
        replacement="\\1,\\2,\\3", 
        x=my.data$my.string) 

# Split on commas, producing a list. 
split.data = strsplit(new.string, ",") 

# Change list into matrix, then data.frame. 
new.data = data.frame(do.call(rbind, split.data)) 
names(new.data) = paste("my.string", seq(ncol(new.data)), sep="") 

my.data$my.string = NULL 
my.data = cbind(new.data, my.data) 
my.data 

# my.string1 my.string2 my.string3 some.data 
# 1  123   34  56:78  -100 
# 2   87   65  43:21  -200 
# 3   a4   b6  c8888  -300 
# 4   11  bbbb  ccccc  -400 
# 5   uu   vv  ww:xx  -500 

正如@topchef指出,逗號(或其它字符)必須保證是從數據中缺席。

另外,每個字符串中必須至少有兩個冒號,否則該模式不匹配任何內容,因此不會發生分裂。