我有许多大的、以空格分隔的 WhatsApp 聊天记录,我需要将时间戳从 12 小时时间格式转换为 24 小时时间格式。
这些文件95%的内容保持相同的行格式如下:
MM/DD/YY,|HH:MM|XM|-|participant:|chatText
但是,这些聊天记录中有一些实例没有保持如上所示的标准行格式。
这是日志示例:
5/30/22, 9:50 AM - person2: Good morning
5/30/22, 11:35 AM - person1: Hi, how are you?
5/30/22, 11:47 AM - person2: I am well
Transfer number: 3778324
Completed:
5/30/22, 12:55 PM - person1: https://mylink.com
5/30/22, 12:59 PM - person2: <Media omitted>
5/30/22, 9:46 PM - person1: thanks
以下是要求:
这是更改后的示例:
5/30/22, 09:50 - person2: Good morning
5/30/22, 11:35 - person1: Hi, how are you?
5/30/22, 11:47 - person2: I am well
Transfer number: 3778324
Completed:
5/30/22, 12:55 - person1: https://mylink.com
5/30/22, 12:59 - person2: <Media omitted>
5/30/22, 21:46 - person1: thanks
这是我到目前为止能想到的,但我不知道如何超越 HH 位置,我也不知道如何避免对非标准格式的行进行更改:
echo "5/30/22, 9:46 PM - person1: thanks"\ |awk -F' ' 'BEGIN{OFS=" "}{("date --date=\""$2 $3"\" +%H:$M") |getline $2;print }'
任何帮助将不胜感激!
使用任何 POSIX awk:
$ cat tst.awk
$1 ~ "^([0-9]{1,2}/){2}[0-9]{2},$" {
split($2,t,":")
if ( ($3 == "PM") && (t[1] < 12) ) {
t[1] += 12
}
time = sprintf(" %02d:%02d ", t[1], t[2])
sub(/ [0-9]{1,2}:[0-9]{2} [AP]M /,time)
}
{ print }
$ awk -f tst.awk file
5/30/22, 09:50 - person2: Good morning
5/30/22, 11:35 - person1: Hi, how are you?
5/30/22, 11:47 - person2: I am well
Transfer number: 3778324
Completed:
5/30/22, 12:55 - person1: https://mylink.com
5/30/22, 12:59 - person2: <Media omitted>
5/30/22, 21:46 - person1: thanks
上面使用
sub()
来更改 $0
而不是直接更改 $2
和 $3
这样它就不会更改以时间戳开头的行上的任何空白(制表符和/或空白链将是如果直接更改$2
或$3
,则转换为单个空格),例如用上面的脚本改变$0
:
$ cat file1
5/30/22, 9:50 AM - person2: Good morning
$ awk -f tst.awk file1
5/30/22, 09:50 - person2: Good morning
vs如果直接改变
$2
(注意Good
和morning
之间空白的变化):
$ cat tst.awk
$1 ~ "^([0-9]{1,2}/){2}[0-9]{2},$" {
split($2,t,":")
if ( ($3 == "PM") && (t[1] < 12) ) {
t[1] += 12
}
$2 = sprintf("%02d:%02d", t[1], t[2])
sub(/ [AP]M /," ")
}
{ print }
$ awk -f tst.awk file1
5/30/22, 09:50 - person2: Good morning
只是为了好玩,因为你标记了
sed
,这里有一个 GNU sed
和 date
的解决方案。但是不要在大文件上使用它,它会比其他出色的 awk
解决方案慢得多:对于修改它的每一行,它都会使用 shell 执行一个 date
命令。
$ sed -E 'h;s!^(\S+),(\s+\S+\s+[AP]M\>).*!date -d "\1" +"%D, %R"!e;T;G;s!\n(\s*\S+){3}!!' file.log
05/30/22, 09:50 - person2: Good morning
05/30/22, 11:35 - person1: Hi, how are you?
05/30/22, 11:47 - person2: I am well
Transfer number: 3778324
Completed:
05/30/22, 12:55 - person1: https://mylink.com
05/30/22, 12:59 - person2: <Media omitted>
05/30/22, 21:46 - person1: thanks
替换命令的
e
标志用shell执行模式空间的内容,用输出替换模式空间。所以我们首先复制保留空间中的输入行(h
),我们用date, hour [AP]M <something>
替换date -d "date hour [AP]M" +"%D, %R"
并执行感谢e
标志。如果没有替换(非标准格式的行),我们将开始一个新的循环。否则我们将一个换行符和保留空间附加到模式空间 (G
),然后我们删除旧的 date hour [AP]M
,只留下原始行的尾部。
我会利用 GNU
AWK
按照以下方式完成这项任务,让 file.txt
内容成为
5/30/22, 9:50 AM - person2: Good morning
5/30/22, 11:35 AM - person1: Hi, how are you?
5/30/22, 11:47 AM - person2: I am well
Transfer number: 3778324
Completed:
5/30/22, 12:55 PM - person1: https://mylink.com
5/30/22, 12:59 PM - person2: <Media omitted>
5/30/22, 9:46 PM - person1: thanks
然后
awk '$3~/^[AP]M$/{split($2,arr,":");if($3=="PM"&&arr[1]<12){arr[1]+=12};$2=sprintf("%02d:%02d",arr[1],arr[2])}{print}' file.txt
给出输出
5/30/22, 09:50 AM - person2: Good morning
5/30/22, 11:35 AM - person1: Hi, how are you?
5/30/22, 11:47 AM - person2: I am well
Transfer number: 3778324
Completed:
5/30/22, 12:55 PM - person1: https://mylink.com
5/30/22, 12:59 PM - person2: <Media omitted>
5/30/22, 21:46 PM - person1: thanks
说明:对于第 3 个字段是 AM 或 PM 的行,如果第 3 个字段是
:
并且数组的第一个元素(即小时)是小于 12 将其增加 12,将第二个字段设置为arr
,其中 HH 是小时,用零填充到宽度为 2,MM 是分钟,用零填充到宽度为 2。与是否进行此类更改无关PM
线。如果您想了解有关 HH:MM
或 print
的更多信息,请阅读 String 函数(GNU Awk 用户指南)。请注意,我没有设置
split
或 sprintf
,因为默认值适用于呈现的任务。(在 GNU Awk 5.1.0 中测试)