将长字符串拆分成较小的字符串

6

我有一个数据框,其中包含像这样的数字列:

360010001001002
360010001001004
360010001001005
360010001001006

我想将它分成2位数、3位数、5位数、1位数和4位数的块:

36 001 00010 0 1002
36 001 00010 0 1004
36 001 00010 0 1005
36 001 00010 0 1006

这似乎应该很简单,但我正在阅读strsplit文档,我无法弄清楚如何按长度进行分割。


你的主要意图是a)将子字符串长度向量转换为索引对,还是b)高效地拆分为数据框列,并进行操作:将块作为新的单独数据框列拆分出来(-> ddply(transform,...)),或者只是在同一列上进行一些字符串操作(例如插入'-')?(-> ldply) - smci
我的问题早已解决,不过既然你问了...是的:我想要这些块作为单独的列。它们是一个ID号码。我得回去看一下确切的内容,但是这些块有意义:36代表州,001代表县,00010代表人口普查区块或其他什么东西。 - Amanda
没错,但我的问题是a):对你来说,是否指定一个任意向量widths = c(2,3,5,1,4)而不是普通的索引对(1,2)(3,5)(6,10)(11,11)(12,15)并不重要。几位回答者纠结于累积索引算术是否是你问题的关键部分。结果证明它并不是。你可以重新措辞以更清楚地表达。 - smci
5个回答

8
您可以使用substring函数(假设字符串/数字的长度是固定的):
xx <- c(360010001001002, 360010001001004, 360010001001005, 360010001001006)
out <- do.call(rbind, lapply(xx, function(x) as.numeric(substring(x, 
                     c(1,3,6,11,12), c(2,5,10,11,15)))))
out <- as.data.frame(out)

ddply(mutate...) 似乎比 do.call(rbind,...) 更优雅?请看下面的回答。 - smci
cumsum() 用于累加索引 - smci

4

一个功能版本:

split.fixed.len <- function(x, lengths) {
   cum.len <- c(0, cumsum(lengths))
   start   <- head(cum.len, -1) + 1
   stop    <- tail(cum.len, -1)
   mapply(substring, list(x), start, stop)
}    

a <- c(360010001001002,
       360010001001004,
       360010001001005,
       360010001001006)

split.fixed.len(a, c(2, 3, 5, 1, 4))
#      [,1] [,2]  [,3]    [,4] [,5]  
# [1,] "36" "001" "00010" "0"  "1002"
# [2,] "36" "001" "00010" "0"  "1004"
# [3,] "36" "001" "00010" "0"  "1005"
# [4,] "36" "001" "00010" "0"  "1006"

4
假设有以下数据:
x <- c("360010001001002", "360010001001004", "360010001001005", "360010001001006")

尝试以下方法:

read.fwf(textConnection(x), widths = c(2, 3, 5, 1, 4))

如果 x 是数字,则在此语句中将 x 替换为 as.character(x)

我最终做了这个:foo$county_id <- as.vector(gsub(foo$fullfipsid, pattern = "..(...).*", replace="\\1")) 对于每个块都有效。它起作用了。但我接受这个答案,因为它既优雅又有效。(我测试过了) - Amanda

0

哇,与Python相比,这项任务非常笨拙和痛苦。无论如何...

顺便说一下,我现在看到你的主要意图是将子字符串长度向量转换为索引对。 您可以使用cumsum(),然后将所有索引一起排序:

ll <- c(2,3,5,1,4)
sort( c(1, cumsum(ll), (cumsum(ll)+1)[1:(length(ll)-1)]) )
# now extract these as pairs.

但这很痛苦。flodel的答案更好。

至于将其拆分为d.f.列并高效地执行该任务:

stringr::str_sub()plyr::ddply() / ldply优雅地结合在一起。

require(plyr)
require(stringr)

df <- data.frame(value=c(360010001001002,360010001001004,360010001001005,360010001001006))
df$valc = as.character(df$value)

df <- ddply(df, .(value), mutate, chk1=str_sub(valc,1,2), chk3=str_sub(valc,3,5), chk6=str_sub(valc,6,10), chk11=str_sub(valc,11,11), chk14=str_sub(valc,12,15) )

#             value            valc chk1 chk3  chk6 chk11 chk14
# 1 360010001001002 360010001001002   36  001 00010     0  1002
# 2 360010001001004 360010001001004   36  001 00010     0  1004
# 3 360010001001005 360010001001005   36  001 00010     0  1005
# 4 360010001001006 360010001001006   36  001 00010     0  1006

0
您可以使用来自 stringi 包的此函数。
splitpoints <- cumsum(c(2, 3, 5, 1,4))
stri_sub("360010001001002",c(1,splitpoints[-length(splitpoints)]+1),splitpoints)

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