Как я могу подсчитывать уникальные термины в текстовом файле без учета регистра?

Это может быть любой язык высокого уровня, который может быть доступен в типичной Unix-подобной системе (Python, Perl, awk, стандартные утилиты unix {sort, uniq} и т. д.). Надеюсь, это достаточно быстро, чтобы сообщить общее количество уникальных терминов для текстового файла размером 2 МБ.

Мне это нужно только для быстрой проверки работоспособности, поэтому его не нужно хорошо проектировать.

Помните, без учета регистра.

Большое спасибо, ребята.

Примечание: если вы используете Python, не используйте код только для версии 3. Система, на которой я его запускаю, имеет только 2.4.4.


person Alex Budovski    schedule 27.05.2009    source источник
comment
Иногда я удивляюсь, как люди боятся производительности Python. Однажды я написал скрипт, который брал 4 ГБ изображений dicom, превращал их в PNG, превращал эти PNG в scipy-массивы, анализировал файлы сегментации, которые также были преобразованы в scipy-массивы, и сохранял этот материал на диск, в результате чего получалась гора целых чисел размером 32 ГБ. . Сделали менее чем за 10 минут.   -  person bayer    schedule 27.05.2009
comment
В чем именно заключается ваш вопрос? Вы пытались решить проблему самостоятельно? Если да, то с какими проблемами вы столкнулись? Если нет, то почему?   -  person innaM    schedule 27.05.2009
comment
Когда мне приходится решать эту задачу, считать легко. Все проблемы возникают при токенизации. На что похож ввод?   -  person brian d foy    schedule 27.05.2009


Ответы (8)


В Python 2.4 (возможно, он работает и в более ранних системах):

#! /usr/bin/python2.4
import sys
h = set()
for line in sys.stdin.xreadlines():
  for term in line.split():
    h.add(term)
print len(h)

В Перле:

$ perl -ne 'for (split(" ", $_)) { $H{$_} = 1 } END { print scalar(keys%H), "\n" }' <file.txt
person pts    schedule 27.05.2009
comment
Для нечувствительности к регистру - вам нужен h.add(term.lower()) - person viksit; 27.05.2009
comment
Но разве это без учета регистра? Если я добавлю строку print h в конце для примера файла, я получу: 4 set(['bar', 'Foo', 'Bar', 'foo']). Foo и foo должны быть одинаковыми. - person Alex Budovski; 27.05.2009
comment
Ах, я слишком медлителен, ребята, позвольте мне проверить ваши комментарии. - person Alex Budovski; 27.05.2009
comment
Круто, я даже не знал о наборе - person Kinlan; 27.05.2009
comment
Если вам нравятся однострочники, то следующее эквивалентно: - person Ants Aasma; 27.05.2009
comment
Perl-версия также нуждается в $H{lc($_)} для нечувствительности к регистру. - person mikegrb; 27.05.2009

В Перле:

my %words; 
while (<>) { 
    map { $words{lc $_} = 1 } split /\s/); 
} 
print scalar keys %words, "\n";
person Christoffer    schedule 27.05.2009

Использование команд bash/UNIX:

sed -e 's/[[:space:]]\+/\n/g' $FILE | sort -fu | wc -l
person Eduard - Gabriel Munteanu    schedule 27.05.2009

Используя только стандартные утилиты Unix:

< somefile tr 'A-Z[:blank:][:punct:]' 'a-z\n' | sort | uniq -c

Если вы работаете в системе без Gnu tr, вам нужно будет заменить "[:blank:][:punct:]" списком всех пробелов и знаков препинания, которые вы хотели бы рассматривать как разделители слов, а не как часть слова, например , "\t.,;".

Если вы хотите, чтобы выходные данные были отсортированы в порядке убывания частоты, вы можете добавить «| sort -r -n» в конец.

Обратите внимание, что это также приведет к нерелевантному количеству токенов пробела; если вас это беспокоит, после tr вы можете использовать sed для фильтрации пустых строк.

person cjs    schedule 27.05.2009

Вот однострочный Perl:

perl -lne '$h{lc $_}++ for split /[\s.,]+/; END{print scalar keys %h}' file.txt

Или перечислить количество для каждого элемента:

perl -lne '$h{lc $_}++ for split /[\s.,]+/; END{printf "%-12s %d\n", $_, $h{$_} for sort keys %h}' file.txt

Это делает попытку обработать пунктуацию так, чтобы "foo." считается с «foo», а «don't» рассматривается как одно слово, но вы можете настроить регулярное выражение в соответствии со своими потребностями.

person jmcnamara    schedule 27.05.2009

Просто (52 штриха):

perl -nE'@w{map lc,split/\W+/}=();END{say 0+keys%w}'

Для более старых версий perl (55 штрихов):

perl -lne'@w{map lc,split/\W+/}=();END{print 0+keys%w}'
person Hynek -Pichi- Vychodil    schedule 27.05.2009

Более короткая версия на Python:

print len(set(w.lower() for w in open('filename.dat').read().split()))

Считывает весь файл в память, разбивает его на слова, используя пробелы, преобразует каждое слово в нижний регистр, создает (уникальный) набор из слов нижнего регистра, считает их и печатает вывод.

Также возможно использование одного вкладыша:

python -c "print len(set(w.lower() for w in open('filename.dat').read().split()))"
person elifiner    schedule 30.05.2009

Вот awk oneliner.

$ gawk -v RS='[[:space:]]' 'NF&&!a[toupper($0)]++{i++}END{print i}' somefile
  • «NF» означает «если есть персонаж».
  • '!a[topuuer[$0]++]' означает "показывать только уникальные слова".
person Hirofumi Saito    schedule 27.05.2009