sed在csv中的每一行的特定位置添加和删除和插入字符
sed adding and removing and inserting characters at specific positions to every row in csv
我在一个大约 100 万行的 csv 文件中有以下样本数据集。
20090531 235850000,605.530000,606.230000,0
20090531 235922000,605.500000,606.200000,0
20090531 235930000,605.530000,606.230000,0
20090531 235939000,605.550000,606.250000,0
20090531 235945000,605.500000,606.200000,0
20090531 235946000,605.530000,606.230000,0
我想要"clean"数据。因为我希望采用以下格式,其中 ^
是要插入的字符,.
是要删除的字符:
2009-05-31 23:59:46 ,605.530000,606.230000
^ ^ ^ ^ ... ..
我认为 sed
可能是最好的方法,但我不太熟悉 sed 和正则表达式,无法高效地完成,但到目前为止已经提出了以下建议。我已将每个正则表达式规则放在一个新行中以便于阅读。
sed '
s/.\{4\}/&-/;
s/.\{7\}/&-/;
s/.\{13\}/&:/;
s/.\{16\}/&:/' input.csv > output.csv
output.csv - 上面的命令输出:
2009-05-31 23:59:06000,605.530000,606.230000,0
2009-05-31 23:59:22000,605.500000,606.200000,0
2009-05-31 23:59:30000,605.530000,606.230000,0
2009-05-31 23:59:39000,605.550000,606.250000,0
所以剩下要做的就是删除秒后的 000
并删除最后的 ,0
问题一:有没有比我的方法更好的方法来做上面的操作?
问题2:如何去掉不需要的字符?
更新,我还删除了每行的最后 2 个字符。现在我只需要从时间中删除那 3 个零。
sed '
s/.\{4\}/&-/;
s/.\{7\}/&-/;
s/.\{13\}/&:/;
s/.\{16\}/&:/;
s/.\{2\}$//' input.csv > output.csv
解决方案:
sed -r '
s/^(.{4})(.{2})(.{2}) (.{2})(.{2})(.{2})000/-- ::/;
s/.\{2\}$//' input.csv > output.csv
我会一次性在前面进行替换,使用 backrefs,然后使用第二个命令删除末尾的 ,0
:
sed -r 's/^(.{4})(.{2})(.{2}) (.{2})(.{2})(.{2})000/-- ::/;s/,0$//' input.csv
-r
启用扩展的正则表达式语法,因此 ()
和 {}
不需要转义(这样可读性更高)。
()
中的组是捕获组;他们匹配的内容被捕获以备后用,作为第一组、第二组和后续组的 </code>、<code>
等。所以在替换中,</code> 指该行的前四个字符,<code>
指后面的两个字符,依此类推(这些称为 "back references")。
000
是模式的一部分但不是替换的一部分,因此它们被删除,第二个命令 s/,0$//
只是删除末尾的 ,0
这条线。
但是如果你想坚持你的方法:由于 000
总是出现在第一个逗号之前,你可以只添加
s/000,//
某处(或 s/...,//
,如果您愿意),如
sed '
s/.\{4\}/&-/;
s/.\{7\}/&-/;
s/.\{13\}/&:/;
s/.\{16\}/&:/;
s/.\{2\}$//;
s/000,//' input.csv > output.csv
您还可以结合使用 sed 和 awk 来完成此操作:
sed 's/.\{4\}/&-/;s/.\{7\}/&-/;s/.\{13\}/&:/;s/.\{16\}/&:/;s/,0$//' input.txt | awk '{print substr([=10=],1,18) substr([=10=],22)}' >output.txt
我修改了 sed 命令,也删除了末尾的“,0”(在 sed 中,行尾是“$”)。而且我添加了 awk 命令来打印出您不想要的违规“000”周围的两个串联子字符串(因此删除了“000”)。
另见相关问题:
I need to delete string from position X to position Y on each line in a text file
Awk 版本:
$ cat grav.awk
BEGIN { OFS=FS="" }
{
= "-"
= "-"
= ":"
= ":"
===""
$NF=$(NF-1)=""
}1
$ awk -f grav.awk grav.txt
2009-05-31 23:58:50,605.530000,606.230000
2009-05-31 23:59:22,605.500000,606.200000
2009-05-31 23:59:30,605.530000,606.230000
2009-05-31 23:59:39,605.550000,606.250000
2009-05-31 23:59:45,605.500000,606.200000
2009-05-31 23:59:46,605.530000,606.230000
可能不那么优雅,但是冗长而且不需要 awk 和 sed ;-)
仅当拆分索引固定时才有效。
while read str; do echo "${str:0:4}-${str:4:2}-${str:6:2} ${str:9:2}:${str:11:2}:${str:13:2},${str:19:21}"; done < input.csv > output.csv
${str:4:2}
表示:来自索引 4 的子字符串,长度为 2
使用固定宽度字段的 GNU awk:
$ awk -vFIELDWIDTHS="4 2 2 1 2 2 2 3 22 2" '{print "-""-"" "":"":" }' file
2009-05-31 23:58:50,605.530000,606.230000
2009-05-31 23:59:22,605.500000,606.200000
2009-05-31 23:59:30,605.530000,606.230000
2009-05-31 23:59:39,605.550000,606.250000
2009-05-31 23:59:45,605.500000,606.200000
2009-05-31 23:59:46,605.530000,606.230000
我在一个大约 100 万行的 csv 文件中有以下样本数据集。
20090531 235850000,605.530000,606.230000,0
20090531 235922000,605.500000,606.200000,0
20090531 235930000,605.530000,606.230000,0
20090531 235939000,605.550000,606.250000,0
20090531 235945000,605.500000,606.200000,0
20090531 235946000,605.530000,606.230000,0
我想要"clean"数据。因为我希望采用以下格式,其中 ^
是要插入的字符,.
是要删除的字符:
2009-05-31 23:59:46 ,605.530000,606.230000
^ ^ ^ ^ ... ..
我认为 sed
可能是最好的方法,但我不太熟悉 sed 和正则表达式,无法高效地完成,但到目前为止已经提出了以下建议。我已将每个正则表达式规则放在一个新行中以便于阅读。
sed '
s/.\{4\}/&-/;
s/.\{7\}/&-/;
s/.\{13\}/&:/;
s/.\{16\}/&:/' input.csv > output.csv
output.csv - 上面的命令输出:
2009-05-31 23:59:06000,605.530000,606.230000,0
2009-05-31 23:59:22000,605.500000,606.200000,0
2009-05-31 23:59:30000,605.530000,606.230000,0
2009-05-31 23:59:39000,605.550000,606.250000,0
所以剩下要做的就是删除秒后的 000
并删除最后的 ,0
问题一:有没有比我的方法更好的方法来做上面的操作? 问题2:如何去掉不需要的字符?
更新,我还删除了每行的最后 2 个字符。现在我只需要从时间中删除那 3 个零。
sed '
s/.\{4\}/&-/;
s/.\{7\}/&-/;
s/.\{13\}/&:/;
s/.\{16\}/&:/;
s/.\{2\}$//' input.csv > output.csv
解决方案:
sed -r '
s/^(.{4})(.{2})(.{2}) (.{2})(.{2})(.{2})000/-- ::/;
s/.\{2\}$//' input.csv > output.csv
我会一次性在前面进行替换,使用 backrefs,然后使用第二个命令删除末尾的 ,0
:
sed -r 's/^(.{4})(.{2})(.{2}) (.{2})(.{2})(.{2})000/-- ::/;s/,0$//' input.csv
-r
启用扩展的正则表达式语法,因此 ()
和 {}
不需要转义(这样可读性更高)。
()
中的组是捕获组;他们匹配的内容被捕获以备后用,作为第一组、第二组和后续组的 </code>、<code>
等。所以在替换中,</code> 指该行的前四个字符,<code>
指后面的两个字符,依此类推(这些称为 "back references")。
000
是模式的一部分但不是替换的一部分,因此它们被删除,第二个命令 s/,0$//
只是删除末尾的 ,0
这条线。
但是如果你想坚持你的方法:由于 000
总是出现在第一个逗号之前,你可以只添加
s/000,//
某处(或 s/...,//
,如果您愿意),如
sed '
s/.\{4\}/&-/;
s/.\{7\}/&-/;
s/.\{13\}/&:/;
s/.\{16\}/&:/;
s/.\{2\}$//;
s/000,//' input.csv > output.csv
您还可以结合使用 sed 和 awk 来完成此操作:
sed 's/.\{4\}/&-/;s/.\{7\}/&-/;s/.\{13\}/&:/;s/.\{16\}/&:/;s/,0$//' input.txt | awk '{print substr([=10=],1,18) substr([=10=],22)}' >output.txt
我修改了 sed 命令,也删除了末尾的“,0”(在 sed 中,行尾是“$”)。而且我添加了 awk 命令来打印出您不想要的违规“000”周围的两个串联子字符串(因此删除了“000”)。
另见相关问题: I need to delete string from position X to position Y on each line in a text file
Awk 版本:
$ cat grav.awk
BEGIN { OFS=FS="" }
{
= "-"
= "-"
= ":"
= ":"
===""
$NF=$(NF-1)=""
}1
$ awk -f grav.awk grav.txt
2009-05-31 23:58:50,605.530000,606.230000
2009-05-31 23:59:22,605.500000,606.200000
2009-05-31 23:59:30,605.530000,606.230000
2009-05-31 23:59:39,605.550000,606.250000
2009-05-31 23:59:45,605.500000,606.200000
2009-05-31 23:59:46,605.530000,606.230000
可能不那么优雅,但是冗长而且不需要 awk 和 sed ;-)
仅当拆分索引固定时才有效。
while read str; do echo "${str:0:4}-${str:4:2}-${str:6:2} ${str:9:2}:${str:11:2}:${str:13:2},${str:19:21}"; done < input.csv > output.csv
${str:4:2}
表示:来自索引 4 的子字符串,长度为 2
使用固定宽度字段的 GNU awk:
$ awk -vFIELDWIDTHS="4 2 2 1 2 2 2 3 22 2" '{print "-""-"" "":"":" }' file
2009-05-31 23:58:50,605.530000,606.230000
2009-05-31 23:59:22,605.500000,606.200000
2009-05-31 23:59:30,605.530000,606.230000
2009-05-31 23:59:39,605.550000,606.250000
2009-05-31 23:59:45,605.500000,606.200000
2009-05-31 23:59:46,605.530000,606.230000