【问题标题】:Change Timestamp with 'Date Time' to 'Date'T'Time'将带有 'Date Time' 的时间戳更改为 'Date'T'Time'
【发布时间】:2021-03-10 11:47:23
【问题描述】:

我有一个这样的 csv:

ID;Query;Time;Value(optional);Url
12;"Query 1";2004-02-12 01:31:14;1;"Url 1"
12;"Query 1";2004-02-13 08:38:23;;"Url 2"
12;"Query 2";2004-02-13 08:38:31;;"Url 3"
12;"Query 3";2004-02-13 08:38:42;1;"Url 1"

但我想要的是一个 T 而不是时间列的空间;像这样:

ID;Query;Time;Value(optional);Url
12;"Query 1";2004-02-12T01:31:14;1;"Url 1"
12;"Query 1";2004-02-13T08:38:23;;"Url 2"
12;"Query 2";2004-02-13T08:38:31;;"Url 3"
12;"Query 3";2004-02-13T08:38:42;1;"Url 1"

如果您知道可以解决此问题的其他工具,那就太好了。您可以假设,年份是 2004 年固定的,但月份和日期不是固定的。 CSV 超过 2 GB,因此 Excel 之类的东西无法处理。

我尝试使用 SED,例如:

cat pleaseHelpMe.csv | sed 's/2004-..-.. /T/p'

但结果是它覆盖了模式,但我只想覆盖一个特定的字符。

结果:12;"Query 1";T01:31:14;1;"Url 1"

【问题讨论】:

  • 我已经恢复了 OP 的原始问题,OP 有他/她尝试的样本。后来 OP 不断添加提供的解决方案的结果,因此仅在此处删除了该部分。

标签: csv awk sed


【解决方案1】:

编辑:从 OP 更新示例内容表明需要更彻底的正则表达式:

由于这里的年份2004是固定的,所以可以这样使用:

sed -e 's/2004-\([0-9]*-[0-9]*\) /2004-\1T/'

和以前一样,但是现在捕获的组更大了。

再次

echo "12;"Query 1";2004-02-12 01:31:14;1;"Url 1""|sed -e 's/2004-\([0-9]*-[0-9]*\) /2004-\1T/'

12;Query 1;2004-02-12T01:31:14;1;Url 1

将 (digit)(space) 替换为 (digit)T,如下所示:

sed -e 's/\([0-9]\) /\1T/' 

因为每一行只有一个位置,空格后跟一个数字,这就足够了。

\([0-9]\) 捕获数字,使用\1 放回原位

用这个我得到

echo "12;"Query 1";2004-02-12 01:31:14;1;"Url 1""|sed -e 's/\([0-9]\) /\1T/'

12;Query 1;2004-02-12T01:31:14;1;Url 1

【讨论】:

  • 不幸的是,查询可能包含这样的东西,我忘了提这个,这是来自真实数据集的东西:142;"207 ad2d 530";2004-04-08 01:31:04;;"" -> 142;"207Tad2d 530";2004-04-08 01:31:04;;""
  • 我明白了。所以这被错误地替换了。不是什么大问题。我将进行编辑。
  • 谢谢,我想这就是我想要的;但如果任何查询包含“2004-03-17 是美好的一天”之类的内容,它们将被更改为:/;因此它可能不是我需要的
  • 是的,它们会改变。您必须准确描述您的文件以使用 sed。如果您的文件太复杂,您可以通过直观地选择相关文本来尝试在 vim 中使用类似 sed 的替换。他们不会变成:/,而是was -> Twas
  • 我添加了更多示例,查询可以是任何内容(如 google 查询)
【解决方案2】:

每当您发现自己在谈论“字段”(也称为“列”)时,您都应该使用 awk,而不是 sed 或 grep,因为 awk 旨在对字段进行操作:

$ awk 'BEGIN{FS=OFS=";"} {sub(/ /,"T",$3)}1' file
ID;Query;Time;Value(optional);Url
12;"Query 1";2004-02-12T01:31:14;1;"Url 1"
12;"Query 1";2004-02-13T08:38:23;;"Url 2"
12;"Query 2";2004-02-13T08:38:31;;"Url 3"
12;"Query 3";2004-02-13T08:38:42;1;"Url 1"
142;"207 ad2d 530";2006-04-08T01:31:04;;""

【讨论】:

  • 不幸的是,我没有任何使用 awk 的经验,你能解释一下为什么会这样吗?如果其中一个查询包含“\;”这会影响 awk
  • 我只是告诉 awk 使用 ; 作为字段分隔符,然后在第三个 ;-分隔字段上进行替换,就像您可以使用 s/old/new/ 一样sed 在特定字段上。并不是说它会影响 awk,而是它会破坏我用 awk 编写的脚本。这只是意味着在 awk 中编写一个不同的脚本来考虑这一点。同样,如果您的问题中的示例输入/输出不能真正代表您的真实数据,那么您必须将其修复为更现实,因为您在该示例中向我们展示了所有我们必须继续进行测试的内容想出一个解决方案。
  • 我添加了更多示例,查询可以是任何内容(如 google 查询)
  • 请停止在问题底部添加额外的行,只需更新问题顶部已经存在的示例输入/输出,以包括您添加的那些行和任何其他相关示例。让我们尽可能简单地为您提供帮助。 想想可能有什么问题 - 乍一看,我没有看到任何引用字段可以包含 "s 或换行符的示例,因此请考虑其中任何一个是否可能发生,并且,如果是这样,请包括它们以及您能想到的任何其他内容。
【解决方案3】:

您能否尝试在 GNU awk 中使用所示示例进行跟踪、编写和测试。

awk '
match($0,/[0-9]{4}-[0-9]{2}-[0-9]{2} ([0-9]{2}:){2}[0-9]{2}/){
  split(substr($0,RSTART,RLENGTH),arr," ")
  print substr($0,1,RSTART-1) arr[1]"T"arr[2] substr($0,RSTART+RLENGTH)
  next
}
1
' Input_file

说明:为上述添加详细说明。

awk '
##Starting awk program from here.
match($0,/[0-9]{4}-[0-9]{2}-[0-9]{2} ([0-9]{2}:){2}[0-9]{2}/){
##Using match function of awk to match yyyy-mm-dd hh:mm:ss regex here in current line.
  split(substr($0,RSTART,RLENGTH),arr," ")
##Splitting sub string of matched regex in match function into array named arr
  print substr($0,1,RSTART-1) arr[1]"T"arr[2] substr($0,RSTART+RLENGTH)
##Printing sub string from 1 to RSTART-1 arr 1st element T arr 2nd element sub string of rest line.
  next
##next will skip all further statements from here.
}
1
##1 will print current line. Basically that line which does not match regex.
' Input_file  ##Mentioning Input_file name here.

【讨论】:

  • 我用你的算法格式正确的输出更新问题
  • @Root_DE,对于您展示的示例,它对我来说效果很好。
  • 在 mose 案例中,它就像一个魅力,但如果查询包含正则表达式之类的东西,那么这些也会改变。有什么办法可以更新此 scipt 以不更改查询(或行的顺序)。例如。匹配第二个未转义引号后的第一个 yyyy-mm-dd hh:mm:ss 模式。
猜你喜欢
  • 1970-01-01
  • 2013-08-17
  • 2011-08-23
  • 1970-01-01
  • 2020-11-27
  • 2018-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多