Regex 转换';1-1-1至1-10-1';到'的十个值;1-1-1'';1-2-1'';1-10-1';

Regex 转换';1-1-1至1-10-1';到'的十个值;1-1-1'';1-2-1'';1-10-1';,regex,r,Regex,R,我有一个如下所示的数据帧: ID 1-1-1, 1-2-1 2-1-1 3-1-1 through 3-5-1 我希望将数据帧转换为 ID 1-1-1 1-2-1 2-1-1 3-1-1 3-2-1 3-3-1 3-4-1 3-5-1 对于第一个数据帧中的第一行,我认为melt可以完成这项工作。但对于第三行,我认为应该以某种方式将“through”替换为中间的id。我尝试了一些正则表达式,但没有找到一个好方法 以下问题: 如果有另一列,我想匹配它们呢 NewColumn

我有一个如下所示的数据帧:

ID     
1-1-1, 1-2-1
2-1-1
3-1-1 through 3-5-1
我希望将数据帧转换为

ID    
1-1-1
1-2-1
2-1-1
3-1-1
3-2-1
3-3-1
3-4-1
3-5-1
对于第一个数据帧中的第一行,我认为melt可以完成这项工作。但对于第三行,我认为应该以某种方式将“through”替换为中间的id。我尝试了一些正则表达式,但没有找到一个好方法

以下问题:

如果有另一列,我想匹配它们呢

NewColumn  ID
A          1-1-1, 1-2-1
B          2-1-1
C          3-1-1 through 3-5-1


ID中的第一个digid对于多个新列项目可能是相同的。

我们可以使用
cSplit
splitstackshape
数据来实现这一点。在我们将
通过
替换为
使用
sub
后,表
将接近

使用regex
sub
,我们匹配是否有零个或多个空格(
\\s*
),后跟
,后跟零个或多个空格(
\\s*
),并将其替换为
作为“ID”列

df1$ID <- sub('\\s*through\\s*', ', ', df1$ID)

为了便于理解,可以将代码分成块。我们根据“,”进行拆分,以创建“长”格式

 cLong <- cSplit(df1, 'ID', ', ', 'long')
现在,我们使用
data.table
方法,因为
cSplit
的输出已经是“data.table”

 DT1 <- cLong1[, list(ID_2=if(.N>1) 
                            ID_2[1]:ID_2[2] 
                            else ID_2),
                                 by = .(ID_1, ID_3)]
更新 对于后续问题,我们只需要在
cSplit
步骤中进行更改。我们可以添加'NewColumn'作为分组变量

df1$ID <- sub('\\s*through\\s*', ', ', df1$ID)

cSplit(cSplit(df1, 'ID', ', ', 'long'), 'ID', '-',
    type.convert=TRUE)[,  list(ID_2=if(.N>1) ID_2[1]:ID_2[2] else ID_2),
    by = .(NewColumn, ID_1, ID_3)
    ][,list(ID=paste(ID_1, ID_2, ID_3, sep="-")) ,.(NewColumn)]
#   NewColumn    ID
#1:         A 1-1-1
#2:         A 1-2-1
#3:         B 2-1-1
#4:         C 3-1-1
#5:         C 3-2-1
#6:         C 3-3-1
#7:         C 3-4-1
#8:         C 3-5-1
df1$ID 1)ID_2[1]:ID_2[2]else ID_2),
by=(NewColumn,ID_1,ID_3)
][,list(ID=paste(ID_1,ID_2,ID_3,sep=“-”),(NewColumn)]
#新列ID
#1:A 1-1-1
#2:A 1-2-1
#3:B2-1-1
#4:c3-1-1
#5:c3-2-1
#6:c3-3-1
#7:c3-4-1
#8:c3-5-1
数据
df1感谢您的支持!那很快,很漂亮。我如何将“3-1-1到3-5-1”中的“通过”分到中间的ID?首先我认为这是一个重复。但是,后来我意识到你的问题很好。@akrun这不是另一个
cSplit
dupe吗?不,我早些时候关闭了它,但似乎更有效。hi akrun,谢谢你的快速回复!将每个ID拆分为ID2和ID3是一种很好的方法,这在R脚本编写和实际ID命名方面都很有意义。但是,当我尝试您的单行代码时,as.data.table.matrix(X[[X]])中会出现一个错误as
error:4个参数传递给.Internal(nchar),这需要3个
@Hanfu您可以尝试逐步代码以了解错误发生的位置吗。我使用的是data.table的开发版本,即v1.9.5我使用data.table 1.9.4。我正在使用的
splitstackshape_1.4.2
数据在
R>cLong1@Hanfu失败。表1.9.5
。您是否使用相同的示例来获得此错误?我确实使用了我在问题中所述的确切示例。我使用splitstackshape_1.4.2和数据。表_1.9.4。使用数据时,错误依然存在。表1.9.5
 cLong1 <- cSplit(cLong, 'ID', '-', type.convert=TRUE)
 DT1 <- cLong1[, list(ID_2=if(.N>1) 
                            ID_2[1]:ID_2[2] 
                            else ID_2),
                                 by = .(ID_1, ID_3)]
 ID <- do.call(paste, c(DT1[,c(1,3,2), with=FALSE], sep='-'))
 data.frame(ID)
df1$ID <- sub('\\s*through\\s*', ', ', df1$ID)

cSplit(cSplit(df1, 'ID', ', ', 'long'), 'ID', '-',
    type.convert=TRUE)[,  list(ID_2=if(.N>1) ID_2[1]:ID_2[2] else ID_2),
    by = .(NewColumn, ID_1, ID_3)
    ][,list(ID=paste(ID_1, ID_2, ID_3, sep="-")) ,.(NewColumn)]
#   NewColumn    ID
#1:         A 1-1-1
#2:         A 1-2-1
#3:         B 2-1-1
#4:         C 3-1-1
#5:         C 3-2-1
#6:         C 3-3-1
#7:         C 3-4-1
#8:         C 3-5-1
df1 <- structure(list(ID = c("1-1-1, 1-2-1", "2-1-1",
"3-1-1 through 3-5-1")), .Names = "ID", class = "data.frame",
 row.names = c(NA, -3L))
#newdata
df1 <- structure(list(NewColumn = c("A", "B", "C"),
ID = c("1-1-1, 1-2-1", 
"2-1-1", "3-1-1 through 3-5-1")), .Names = c("NewColumn", "ID"
), class = "data.frame", row.names = c(NA, -3L))