WhatsApp 文字聊天基本分析:参与者的字符数

WhatsApp 文字聊天基本分析:参与者的字符数

我已经习惯了grep | uniq -c | sort -rn,但这个案子有点复杂。如果您复制 Whatsapp 网络聊天,您会得到类似的内容

[3:14 pm, 25/09/2020] James Smith: Hello!
[6:42 pm, 25/09/2020] John Doe: hi
[6:43 pm, 25/09/2020] James Smith: I was wondering..
if blah blah
and also blah
[6:45 pm, 25/09/2020] James Smith: blah blah blah blah...

我正在尝试获取有关对话中每个人的一些统计信息,从字符数 ( wc -c) 开始。

 74  James Smith
  2  John Doe

那怎么办呢?即,聊天中每个参与者的文本计数。在上面的示例中,Smith 贡献了 74 个字符,Doe 贡献了 2 个字符。

为了进行测试,我复制了 WhatsApp 网络聊天中符合假设的几行内容。要将它们轻松粘贴到文件中:xsel -b > filet_to_test.txt.

有效假设:

  • 消息可以有换行符。
  • 无法包含[6:45 pm, 25/09/2020]第二行以上的字符串。
  • 新消息/记录可能会以某种形式[6:45 pm, 25/09/2020]开始^\[\d{1,2}:\d{2}\s[ap]m,\s\d{2}/\d{2}/\d{4}\]\s
  • 时间戳之后的用户名不包含冒号。

更理想的解决方案是可扩展的(也许使用磨坊主),例如获取范围内或一周中每一天/小时的字符/字数。

答案1

与@dani-garcia 类似的方法。首先将您的文件文明化为tab单独的文件:

cat file | 
  tr "\n" "\000" | 
  sed "s/\x0\[/\n/g" | 
  sed "1 s/\[//; s/\]/\t/1; s/:/\t/2; s/\x0/ /g" |
  sed -E "s/(^[^,]+), ([0-9]{1,2}).([0-9]{2}).([0-9]{4})/\4-\3-\2 \1/" 

2020-09-25 3:14 pm      James Smith     Hello!
2020-09-25 6:42 pm      John Doe        hi
2020-09-25 6:43 pm      James Smith     I was wondering.. if blah blah and also blah
2020-09-25 6:45 pm      James Smith     blah blah blah blah...

通过tr将所有\newline 翻译为null

cat file | tr "\n" "\000" | 

然后在有模式的地方sed g全局重新插入ewlines\nnull[

sed "s/\x0\[/\n/g" | 

[最后通过丢失行首来整理各个行1

sed "1 s/\[//; 

将第一个替换]\tab

    s/\]/\t/1;

将第二个替换:\tab

    s/:/\t/2;

最后将剩余的替换null以避免将最初由\newline分隔的单词连接在一起

    s/\x0/ /g"

并整理你的日期,以便它们排序得很好

    sed -E "s/(^[^,]+), ([0-9]{1,2}).([0-9]{2}).([0-9]{4})/\4-\3-\2 \1/" 

现在您已将字段分开,您可以随意排序、分组、计数或进行任何操作。

| awk -F'\t' '{chats[$2]++; words[$2]+=split($3,tmp," "); chars[$2]+=length($3)}
   END{for (who in chats){
     S=(chats[who]==1)?"":"s";
     s=(words[who]==1)?"":"s";
     print who" sent "chats[who]" message"S" with "words[who]" word"s" and "chars[who]" characters"}}'

James Smith sent 3 messages with 14 words and 73 characters
John Doe sent 1 message with 1 word and 2 characters

答案2

您可以将每条消息分成三个部分(日期、人员、消息),然后使用按要满足的条件索引的 awk 数组,最后打印数组中的所有值,例如:

awk '{printf "%s%s", (NR>1&&/^\[.*\]/?"\n":""),$0}END{print " "}' test.txt | sed 's/\(^\[.*\]\) \(.*\): \(.*\)/\1\t\2\t\3/g' | awk 'BEGIN{FS="\t"} {arr[$2] =arr[$2]$3} END{for (i in arr) print length(arr[i]),i}'

test.txt你的输入文件。

解释:

如果该行不以 开头,第一个命令 ( awk '{printf "%s%s", (NR>1&&/^\[.*\]/?"\n":""),$0}END{print " "}' test.txt) 会删除换行符[blahblahblah],即它不是新消息,因此整个消息将在同一行中。

第二个命令 ( sed 's/\(^\[.*\]\) \(.*\): \(.*\)/\1\t\2\t\3/g') 将每一行分为三部分:日期(带有模式[.*])、人员(在日期和冒号之间)和消息。然后它输出每一行,每个部分用制表符分隔。

最后,第三个命令 ( awk 'BEGIN{FS="\t"} {arr[$2] =arr[$2]$3} END{for (i in arr) print length(arr[i]),i}') 使用按人员索引的 awk 数组,并输出每个人员的消息串联的长度。

假设

  • 日期由[和分隔,]并且中间不包含这些符号。
  • 人名不包含冒号
  • 消息可以包含字符串,就像[6:45 pm, 25/09/2020]它们不在新行的开头一样。

我不熟悉磨坊主,但您可能可以执行类似于可扩展所需解决方案的操作,更改最后一个 awk 命令。

也许这不是最有效的方法,但它确实有效。

相关内容