[英]regexp R - extract string between commas
由于我的csv文件已损坏,因此我使用以下命令将其读入R:
dataDT <- data.table::fread(".../test.csv", sep = NULL)
它为数据集提供了类似的内容:
dataDT <- data.table("ColA,ColB,ColC,ColD" = c("1,10,some text... , some text,,20190801",
"2,22,some text... , some text,,20190801",
"3,30,some text... , some text,,20170601"))
dataDT
> dataDT
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
现在,我想要将每行中的字符串分成4个新列 :
targetDT <- data.table(ColA = c(1,2,3),
ColB = c(10,22,30),
ColC = c("some text... , some text,", "some text... , some text,", "some text... , some text,"),
ColD = c("20190801","20190801",'20170601'))
targetDT
> targetDT
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
逻辑将是:
如何实现以上逻辑?
编辑_1:
敏感数据,抱歉,我无法提供确切数据。 看起来像:
ID,Code1,Project_Name,Report_Date
1: 123123,1, A & B,20100101
2: 1413,2, C, D and E,20120101
3: 53163,333, F, G,20140303
4: 23453,44,This is a name,20160801
5: 12645,555,5th test, to continue,20190501
因此,第一个逗号之前的所有内容绝对是数字,第一和第二个逗号之间的所有内容也都是数字。 上一个逗号之后的所有内容绝对是类似日期的8位数字。 中间部分可以包含多个逗号,但不能包含引号(我想这是fread将逗号视为定界符的原因)。
这是一个regex
模式,通过该模式,您可以替换与前导2和终极数字值相邻的逗号字符,并将它们彼此分隔,并用空格将周围的文本分隔开。 这可能是更安全的使用非空格字符进行分离,因为我的下一步将是阅读泰晤士报“行”与一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的解决方案
library(data.table)
library(stringr)
library(dplyr)
dataDT <- data.table(data = c("1,10,some text... , some text,,20190801",
"2,22,some text... , some text,,20190801",
"3,30,some text... , some text,,20170601"))
dataDT <- dataDT %>%
mutate(
ColA = str_extract(data, "^[^,]*(?=,)"),
ColB = str_extract(data, "(?<=,)[^,]*(?=,)"),
ColD = str_extract(data, "(?<=,)[^,]*$"),
ColC = str_sub(data, nchar(ColA)+nchar(ColB)+3, nchar(data)-nchar(ColD)-1)
) %>%
select(ColA, ColB, ColC, ColD)
dataDT
#> 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
由reprex软件包 (v0.3.0)创建于2019-06-27
到目前为止发布的答案建议使用正则表达式的解决方案。
或者,可以考虑列的位置 。 正如OP所指出的
- ColA在第一个逗号前有字符串;
- ColB具有介于第一和第二逗号之间的所有内容;
- ColD在最后一个逗号后有字符串;
- ColC在中间部分有字符串(它可能包含其他逗号)。
这样做的想法是照常使用sep = ","
fread()
读取文件sep = ","
这会导致数据集未对齐。 重新整形为长格式后,可以按行标识第一,第二和最后一列以及中间列。 这些条目可以指定各自的列名称。 在最终ColC
为宽格式期间,中间列折叠为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)
请注意,示例数据集已通过插入其他逗号进行了修改,以具有更实际的测试用例。
读取操作的结果是未对齐且参差不齐的数据集:
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
如果我们看一下中间结果,可以更好地解释该方法。
在melt()
, long
是
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
由此,创建查找表lut
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
在更新加入之后,在重新调整为宽格式之前, long
样子
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
现在,数据项已与它们各自的列名对齐。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.