在前两个冒号处分割字符串

5
我想要将一个字符串列按照前两个冒号分割,但不按照任何后续的冒号分割:
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)

我已经进行了广泛的搜索,以下问题是最接近我当前困境的:

如何在字符串中按第一个逗号分割

感谢任何建议。我更喜欢使用基础 R。

编辑:

冒号前的字符数不总是两个,第一个和第二个冒号之间的字符数也不总是两个。因此,我编辑了示例以反映这一点。

5个回答

4
使用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"

更新: 使用最新的示例(如上所示)和 Hadley 的注释解决方案:

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"

还有str_split_fixed函数。 - hadley

4

在基础 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可以作为字符串向量进行处理。


这是一个很好的答案,但我想知道m中的数字代表什么意思? - Mark Miller
1
regexec() 返回一个匹配对象,其中每个匹配的第一个元素是每个组的起始匹配位置的向量(首先包括整个匹配,因此第一个显式组为 #2,第二个为 #3,等等),第二个元素是匹配长度的向量。regmatches() 然后使用该匹配数据从字符串向量中提取匹配的文本。 - Simon

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 

这很简洁,但需要使用在字符串中可能永远不会出现的字符来代替逗号。 - topchef
@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所指出的那样,数据中必须确保不存在逗号(或其他字符)。

另外,每个字符串中至少必须存在两个冒号,否则模式无法匹配任何内容,因此不会进行拆分。


0
你能不能在第一个冒号上使用strsplit(sub(":\s*", XX, x), XX)(就像你链接到的其他问题的示例一样),取第二部分并再次在第一个冒号上拆分?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接