Решение XSLT 2.0:
<xsl:template match="tag2">
<tag2>
<xsl:value-of select="distinct-values(tokenize(., '
'))"/>
</tag2>
</xsl:template>
Тот же подход, что и у @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
ewlines вnull
cat file | tr "\n" "\000" |
затем с помощьюsed
g
локально повторно вставьте \n
ewlines везде, где у вас есть шаблонnull[
sed "s/\x0\[/\n/g" |
окончательно привести в порядок отдельные строки, потеряв ведущую [
в строке1
sed "1 s/\[//;
замена первого ]
на \t
ab
s/\]/\t/1;
замена второго :
на \t
ab
s/:/\t/2;
и, наконец, замените все оставшиеся null
на
, чтобы избежать объединения слов вместе, где они были первоначально разделены линией \n
ewline
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
Вы можете разделить каждое сообщение на три части (дата, человек, сообщение ), а затем использовать массивы 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]
, если они не находятся в начале новой строки. Я не знаком с miller , но, вероятно, вы можете сделать что-то похожее на ваше расширяемое желаемое решение, изменив последнюю команду awk.
Вероятно, это не самый эффективный способ, но он работает.