我有一个包含数百万条记录的csv文件,如下所示
1,,,,,,,,,,a,,,,,,,,,,,,,,,,4,,,,,,,,,,,,,,,456,,,,,,,,,,,,,,,,,,,,,3455,,,,,,,,,,
1,,,,,,,,,,b,,,,,,,,,,,,,,,,5,,,,,,,,,,,,,,,467,,,,,,,,,,,,,,,,,,,,,3445,,,,,,,,,,
2,,,,,,,,,,c,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,567,,,,,,,,,,,,,,,,,,,,,4656,,,,,,,,,,
我必须删除两个值之间的额外逗号,并且只保留一个。样本输入的输出应该类似于
1,a,4,456,3455
1,b,5,467,3445
2,c,6,567,4656
如何使用shell实现此功能,因为它也可以自动执行其他文件。 我需要将这些数据加载到数据库中。我们可以用R吗?
来做答案 0 :(得分:4)
编辑以解决修改过的问题。
R解决方案。
提供的原始解决方案只是处理文本。假设您的行在结构中,您可以使用:
处理多行# Create Data
Row1 = "1,,,,,,,a,,,,,,,,,,4,,,,,,,,,456,,,,,,,,,,,3455,,,,,,,"
Row2 = "2,,,,,,,b,,,,,,,,,,5,,,,,,,,,567,,,,,,,,,,,4566,,,,,,,"
Rows = c(Row1, Row2)
CleanedRows = gsub(",+", ",", Rows) # Compress multiple commas
CleanedRows = sub(",\\s*$", "", CleanedRows) # Remove final comma if any
[1] "1,a,4,456,3455" "2,b,5,567,4566"
但是如果你试图从csv中读取它并压缩行,
## Create sample data
Data =read.csv(text="1,,,,,,,a,,,,,,,,,,4,,,,,,,,,456,,,,,,,,,,,3455,,,,,,,
2,,,,,,,b,,,,,,,,,,5,,,,,,,,,567,,,,,,,,,,,4566,,,,,,,",
header=FALSE)
你的代码可能会说
Data = read.csv("YourFile.csv", header=FALSE)
Data = Data[which(!is.na(Data[1,]))]
Data
V1 V8 V18 V27 V38
1 1 a 4 456 3455
2 2 b 5 567 4566
注意:这假设非空白字段位于每行的相同位置。
答案 1 :(得分:4)
sed
方法:
sed -e "s/,\+/,/g" -e "s/,$//" input_file > output_file
将多个逗号转换为单个逗号,并删除最后一行逗号。
答案 2 :(得分:2)
使用tr -s
:
echo 'a,,,,,,,,b,,,,,,,,,,c' | tr -s ','
输出:
a,b,c
如果输入行有逗号逗号,tr -s ','
会将这些尾随逗号压缩成一个逗号,但要删除一个需要添加一些sed
代码:tr -s ',' | sed 's/,$//'
。
速度。测试一个10,000,000行测试文件,包含OP示例中的第一行,重复。
tr -s ','
(但留下尾随逗号)tr -s ',' | sed 's/,$//
sed -e "s/,\+/,/g" -e "s/,$//"
(Jean-François Fabre's answer。)答案 3 :(得分:0)
如果你的文件确实是一个CSV文件,它可能会以几种不同的方式引用逗号,这会使基于正则表达式的CSV解析不满意。
我通常使用并推荐csvkit
,它为shell提供了一套很好的CSV解析实用程序。 http://csvkit.readthedocs.io/en/latest/
使用这组命令在csvkit中回答了您的确切问题。首先,csvstat
显示文件的样子:
$ csvstat -H --max tmp.csv | grep -v None
1. column1: 2
11. column11: c
27. column27: 6
42. column42: 567
63. column63: 4656
然后,既然您知道所有数据都在这些列中,那么您可以运行:
$ csvcut -c 1,11,27,42,63 tmp.csv
1,a,4,456,3455
1,b,5,467,3445
2,c,6,567,4656
获得您想要的答案。
答案 4 :(得分:0)
我们可以使用R吗?
如果您的输入如图所示,即您希望跳过所有行中的相同列,则可以分析第一行,然后在read.table
中定义列类:
text <- "1,,,,,,,,,,a,,,,,,,,,,,,,,,,4,,,,,,,,,,,,,,,456,,,,,,,,,,,,,,,,,,,,,3455,,,,,,,,,,
1,,,,,,,,,,b,,,,,,,,,,,,,,,,5,,,,,,,,,,,,,,,467,,,,,,,,,,,,,,,,,,,,,3445,,,,,,,,,,
2,,,,,,,,,,c,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,567,,,,,,,,,,,,,,,,,,,,,4656,,,,,,,,,,"
tmp <- read.table(text = text, nrows = 1, sep = ",")
colClasses <- sapply(tmp, class)
colClasses[is.na(unlist(tmp))] <- "NULL"
这里我假设第一行没有实际的NA值。如果有,你需要稍微调整一下。
read.table(text = text, sep = ",", colClasses = colClasses)
# V1 V11 V27 V42 V63
#1 1 a 4 456 3455
#2 1 b 5 467 3445
#3 2 c 6 567 4656
显然,您指定的是file
而不是text
。
此解决方案对于小到中等大小的数据非常有效。对于大型数据,请将第二个read.table
替换为包含data {。}的fread
(但无论跳过列是否存在问题,这都适用)。