
おなじみgrep | uniq -c | sort -rn
ですが、この場合は少し複雑です。 Whatsapp Webチャットをコピーすると、次の結果が表示されます。
[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 Webチャットから数行をコピーしました。ファイルに簡単に貼り付けるには:xsel -b > filet_to_test.txt
。
利用できる仮定:
- メッセージには改行文字を含めることができます。
[6:45 pm, 25/09/2020]
2行目の上に文字列を含めることはできません。- 新しいメッセージ/記録は任意の形式で
[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
すべての\n
ewlineを次に翻訳するnull
cat file | tr "\n" "\000" |
次に、パターンがある場所にsed
g
全体的にewlineを再挿入します。\n
null[
sed "s/\x0\[/\n/g" |
[
最後に、行の先頭を失い、個々の行をクリーンアップします。1
sed "1 s/\[//;
最初のものをab]
に置き換えます。\t
s/\]/\t/1;
2番目のものをab:
に置き換えます。\t
s/:/\t/2;
最後に、元のewlineで区切られた単語を連結したくない場合は、残りを次のようnull
に置き換えます。\n
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
各メッセージを3つの部分(日付、人、メッセージ)に分割し、満たす条件にインデックス付きの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]
2番目のコマンド(sed 's/\(^\[.*\]\) \(.*\): \(.*\)/\1\t\2\t\3/g'
)は、各行を日付(パターンを含む[.*]
)、人(日付とコロンの間)、およびメッセージの3つの部分に分割します。次に、各部分をタブで区切って各行を出力します。
最後に、3番目のコマンド(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コマンドを変更して、拡張可能な目的のソリューションと同様の操作を実行できます。
おそらく最も効率的なアプローチではありませんが、うまくいきます。