regexp R-提取逗号之间的字符串

regexp R-提取逗号之间的字符串,r,regex,data.table,gsub,R,Regex,Data.table,Gsub,由于我的csv文件已损坏,我正在使用以下命令将其读入R: dataDT <- data.table::fread(".../test.csv", sep = NULL) 所以,第一个逗号之前的所有内容都是数字,第一个和第二个逗号之间的所有内容都是数字。最后一个逗号之后的所有内容都绝对是一个类似于8位数字的日期。中间部分可以包含多个逗号,但不包含引号(我想这就是fread将逗号视为分隔符的原因).这里有一个regex模式,允许您替换与前导两个和终端数值相邻的逗号字符,并用空格将它们彼此和周

由于我的csv文件已损坏,我正在使用以下命令将其读入R:

dataDT <- data.table::fread(".../test.csv", sep = NULL)

所以,第一个逗号之前的所有内容都是数字,第一个和第二个逗号之间的所有内容都是数字。最后一个逗号之后的所有内容都绝对是一个类似于8位数字的日期。中间部分可以包含多个逗号,但不包含引号(我想这就是fread将逗号视为分隔符的原因).

这里有一个
regex
模式,允许您替换与前导两个和终端数值相邻的逗号字符,并用空格将它们彼此和周围的文本分隔开。使用非空格字符分隔可能更安全,因为我的下一步是使用
read.*
函数之一或
fread
再次读取这些“行”。也许用“|”作为分隔符

sub("(\\d+)[,](\\d+)[,](.+)[,](\\d+)$", 
    "\\1 \\2 '\\3' \\4", 
    dataDT$"ColA,ColB,ColC,ColD" )

[1] "1 10 'some text... , some text,' 20190801" "2 22 'some text... , some text,' 20190801"
[3] "3 30 'some text... , some text,' 20170601"
模式中的括号用于创建“捕获类”,在每种情况下,我都使用“\d+”模式“捕获”了任意数量的数字或十进制分隔符。我还在替换模式中用单引号将文本(用“+”)括起来,这样第三列中的“内部空间”就不会被理解为分隔符。
“\\1”
“\\2”
等是对每个捕获类中捕获的字符的引用,按其在模式中的出现顺序排列。请参见
?regex
。但是,如果使用不同的分隔符,则不需要单引号

下面是一个使用“|”作为
sep
的测试

fread(text =sub("(\\d+)[,](\\d+)[,](.+)[,](\\d+)", "\\1|\\2|'\\3'|\\4", dataDT$"ColA,ColB,ColC,ColD" ) ,sep="|")
   V1 V2                          V3       V4
1:  1 10 'some text... , some text,' 20190801
2:  2 22 'some text... , some text,' 20190801
3:  3 30 'some text... , some text,' 20170601

注意:如果您的数值带有逗号或前导或尾随货币,则需要更改示例,因为使用了
“\\d”
捕获字符的数字组将不再成功。

这里有一个
regex
模式,允许您替换与前导两个和终端数值相邻的逗号字符,并用空格将它们彼此和周围的文本分隔开。使用非空格字符分隔可能更安全,因为我的下一步是使用
read.*
函数之一或
fread
再次读取这些“行”。也许用“|”作为分隔符

sub("(\\d+)[,](\\d+)[,](.+)[,](\\d+)$", 
    "\\1 \\2 '\\3' \\4", 
    dataDT$"ColA,ColB,ColC,ColD" )

[1] "1 10 'some text... , some text,' 20190801" "2 22 'some text... , some text,' 20190801"
[3] "3 30 'some text... , some text,' 20170601"
模式中的括号用于创建“捕获类”,在每种情况下,我都使用“\d+”模式“捕获”了任意数量的数字或十进制分隔符。我还在替换模式中用单引号将文本(用“+”)括起来,这样第三列中的“内部空间”就不会被理解为分隔符。
“\\1”
“\\2”
等是对每个捕获类中捕获的字符的引用,按其在模式中的出现顺序排列。请参见
?regex
。但是,如果使用不同的分隔符,则不需要单引号

下面是一个使用“|”作为
sep
的测试

fread(text =sub("(\\d+)[,](\\d+)[,](.+)[,](\\d+)", "\\1|\\2|'\\3'|\\4", dataDT$"ColA,ColB,ColC,ColD" ) ,sep="|")
   V1 V2                          V3       V4
1:  1 10 'some text... , some text,' 20190801
2:  2 22 'some text... , some text,' 20190801
3:  3 30 'some text... , some text,' 20170601

注意:如果数值带有逗号或前导或尾随货币,则需要更改示例,因为使用
“\\d”
捕获数字字符组将不再成功。

使用stringr的解决方案

库(data.table)
图书馆(stringr)
图书馆(dplyr)
dataDT%
选择(可乐、可乐、可乐、冷)
数据传输
#>感冒
#>1 10一些文本,一些文本,20190801
#>2 22一些文本,一些文本,20190801
#>3 30一些文字,一些文本,20170601

于2019-06-27由(v0.3.0)

使用stringr的解决方案创建

库(data.table)
图书馆(stringr)
图书馆(dplyr)
dataDT%
选择(可乐、可乐、可乐、冷)
数据传输
#>感冒
#>1 10一些文本,一些文本,20190801
#>2 22一些文本,一些文本,20190801
#>3 30一些文字,一些文本,20170601

由(v0.3.0)创建于2019-06-27。目前发布的答案建议使用正则表达式解决方案

或者,可以考虑立柱的位置。正如OP所指出的那样

  • ColA在第一个逗号前有字符串
  • ColB拥有第一个和第二个逗号之间的所有内容
  • ColD在最后一个逗号后有字符串
  • COLC在中间部分有字符串(它可能包含附加逗号)。
想法是像往常一样使用
fread()
sep=“,”
读取文件,这会导致数据集不对齐。在重新调整为长格式后,可以识别每行的第一列、第二列和最后一列以及中间列。可以为这些条目指定相应的列名。在最终重塑为宽格式的过程中,中间列折叠为
ColC

library(data.table)
# read file
DT <- fread("
1,10,some text...  some text,,20190801
2,22,some text... , some text,,20190801
3,30,some text... ,, some text,,20170601"
            , sep = ","
            , fill = TRUE
            , header = FALSE
            , strip.white = FALSE)
如果我们看中间结果,可以更好地解释这种方法

melt()
之后,
long

由此创建查找表
lut

更新后,在重新整形为宽格式之前加入


现在,数据项已与其各自的列名对齐。

到目前为止发布的答案建议使用正则表达式解决方案

或者,可以考虑立柱的位置。正如OP所指出的那样

  • ColA在第一个逗号前有字符串
  • ColB拥有第一个和第二个逗号之间的所有内容
  • ColD在最后一个逗号后有字符串
  • COLC在中间部分有字符串(它可能包含附加逗号)。
想法是像往常一样使用
fread()
sep=“,”
读取文件,这会导致数据集不对齐。在重新调整为长格式后,可以识别每行的第一列、第二列和最后一列以及中间列。可以为这些条目指定相应的列名。在t
library(data.table)
# read file
DT <- fread("
1,10,some text...  some text,,20190801
2,22,some text... , some text,,20190801
3,30,some text... ,, some text,,20170601"
            , sep = ","
            , fill = TRUE
            , header = FALSE
            , strip.white = FALSE)
DT
   V1 V2                      V3         V4         V5       V6       V7
1:  1 10 some text...  some text              20190801       NA       NA
2:  2 22           some text...   some text            20190801       NA
3:  3 30           some text...              some text       NA 20170601
cols <- c("ColA", "ColB", "ColC", "ColD")
# reshape from wide to long format
long <- melt(DT[, rn := .I], "rn", na.rm = TRUE)
# create lookup table to rename column names  
lut <- long[, .(variable, col = rep(cols, c(1L, 1L, .N - 3, 1L))), by = rn]
# rename columns by an update join
long[lut,  on = .(rn, variable), variable := col][]
# reshape and collapse 
dcast(long, rn ~ variable, paste, collapse = ",")
   ColA ColB                      ColC     ColD
1:    1   10  some text...  some text, 20190801
2:    2   22 some text... , some text, 20190801
3:    3   30 some text... ,, some text 20170601
    rn variable                   value
 1:  1       V1                       1
 2:  2       V1                       2
 3:  3       V1                       3
 4:  1       V2                      10
 5:  2       V2                      22
 6:  3       V2                      30
 7:  1       V3 some text...  some text
 8:  2       V3           some text... 
 9:  3       V3           some text... 
10:  1       V4                        
11:  2       V4               some text
12:  3       V4                        
13:  1       V5                20190801
14:  2       V5                        
15:  3       V5               some text
16:  2       V6                20190801
17:  3       V7                20170601
    rn variable  col
 1:  1       V1 ColA
 2:  1       V2 ColB
 3:  1       V3 ColC
 4:  1       V4 ColC
 5:  1       V5 ColD
 6:  2       V1 ColA
 7:  2       V2 ColB
 8:  2       V3 ColC
 9:  2       V4 ColC
10:  2       V5 ColC
11:  2       V6 ColD
12:  3       V1 ColA
13:  3       V2 ColB
14:  3       V3 ColC
15:  3       V4 ColC
16:  3       V5 ColC
17:  3       V7 ColD
    rn variable                   value
 1:  1     ColA                       1
 2:  2     ColA                       2
 3:  3     ColA                       3
 4:  1     ColB                      10
 5:  2     ColB                      22
 6:  3     ColB                      30
 7:  1     ColC some text...  some text
 8:  2     ColC           some text... 
 9:  3     ColC           some text... 
10:  1     ColC                        
11:  2     ColC               some text
12:  3     ColC                        
13:  1     ColD                20190801
14:  2     ColC                        
15:  3     ColC               some text
16:  2     ColD                20190801
17:  3     ColD                20170601