Войти в систему

Home
    - Создать дневник
    - Написать в дневник
       - Подробный режим

LJ.Rossia.org
    - Новости сайта
    - Общие настройки
    - Sitemap
    - Оплата
    - ljr-fif

Редактировать...
    - Настройки
    - Список друзей
    - Дневник
    - Картинки
    - Пароль
    - Вид дневника

Сообщества

Настроить S2

Помощь
    - Забыли пароль?
    - FAQ
    - Тех. поддержка



Пишет deadbeef ([info]deadbeef)
@ 2004-11-21 07:10:00


Previous Entry  Add to memories!  Tell a Friend!  Next Entry
Вот, сотворил. Может полезно будет.
Сотворил простейшую и кратчайшую программку, которая может помочь людям русским, в одном мутном деле.
Иногда, возникает подозрение, что под разными именами в инете пишет один и тот же человек. Это подозрение бывает достаточно сложно проверить, однако и на такую хитрую задницу с лабиринтом, найдётся русский лом.


Нижеприведённая программка делает очень простую вещь - считает, сколько в тексте есть разных буквосочетаний. Из соображений скорости и простоты она учитывает только 512 наиболее распространённых в русском языке буквосочетаний. На выходе получаем простой список из 512 относительных величин в экспоненциальном формате - количество буквосочетаний одного типа отнесённое к общему количеству буквосочетаний. Теперь остаётся только загнать этот список в какую-нибудь программку для построения графиков, чтобы она нарисовала нам спектр текста (я пользую gnuplot).
А главное, и самое интересное, что этот самый спектр текста будет почти одинаков для разных текстов одного автора и будет отличаться для текстов разных авторов. Нарисовав в одном графике спектры для двух текстов, мы без особого труда можем определить, принадлежат ли тексты разным людям, или они были написаны одним человеком (ну или нелюдем). Тексты, правда, должны быть достаточно длинными, чтобы дать спектр действительно характерный для изучаемого автора - книга, например, или собранные в один файл сотни комментариев.

Вот, например, участок спектра с 100-го по 200-е буквосочетания для двух разных кусков Лукьяненки:
Image

А вот, тот же участок для Лукьяненки и Неведимова (Лукьяненка - красный):
Image

Посмотрев на картинки, разобраться, что на первой картинке - автор один, а на второй - авторы разные, не так уж и сложно.


#include <locale.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <getopt.h>

#define SLOG_COUNT  (512)

char *slog[SLOG_COUNT] = {
"ст","то","ен","но","ни","ов","на","ра","ос","пр","ро","ко","ан","ли","по","во",
"ес","ре","не","от","ол","од","ор","ть","ва","го","ер","ит","ет","ти","об","ел",
"он","та","ри","ль","ны","те","ал","ат","де","ка","ом","ис","тв","ве","ин","ие",
"ло","ми","со","ав","ог","ме","ем","ия","им","ле","ас","из","ив","ла","ак","че",
"мо","да","ии","ед","за","тр","ой","ск","ар","нн","до","ки","ам","оп","ил","ик",
"ви","бо","ма","тс","ьн","ся","ев","аз","оз","ек","ир","же","ои","бы","си","ег",
"ич","ци","вс","еп","ап","зн","ди","ад","ид","ип","сл","вы","вн","ру","ля","ые",
"ей","ое","ок","се","их","оч","вл","ож","ят","хо","эт","пе","тн","ых","ры","уд",
"чт","ио","ще","ку","аб","дн","сп","ьс","ео","ая","чи","ий","му","св","ги","ду",
"ае","йс","це","нт","ча","ше","оо","лю","сс","ют","вр","яв","жн","уп","ез","ус",
"зв","ым","ыл","мы","кр","ян","ну","ее","па","иа","еб","ую","аи","нс","са","ьк",
"га","иг","ыв","еи","еч","кт","жи","аж","ты","ый","уч","ут","ту","иб","яс","мн",
"ач","су","чн","яп","ыс","зм","бе","дл","зо","ац","сь","пи","мп","лу","дс","ах",
"ын","бр","ям","ня","ур","щи","гр","яз","ун","бщ","жд","еж","аю","ши","уж","ыт",
"нк","нь","бу","зд","тк","вп","ьв","яи","гл","йн","сн","вт","би","мс","ды","ук",
"ып","др","ул","зи","рн","вк","кл","ао","хр","ех","кс","юд","ию","аг","тп","уг",
"пл","ву","ьп","ув","бл","см","йв","йп","яо","ьт","як","мв","ьш","ьи","хи","ёт",
"иц","фи","ря","яд","ср","ум","ба","йи","рс","вв","вя","рт","хс","рм","яе","оц",
"жа","ью","оя","йт","иу","гд","ке","нц","ыи","нд","ош","йк","ущ","дв","ау","мм",
"оу","ющ","ша","рп","хп","ьм","лл","эк","зы","бс","иж","рк","уб","мк","вм","тд",
"кн","хв","ык","еа","ьо","рв","ай","уе","еш","ьз","ох","зк","кв","вд","ён","хн",
"яр","аш","ыо","фо","йм","сч","еу","лн","зу","ец","ащ","пу","ца","рг","ьд","оэ",
"зр","йо","тт","мч","йд","ял","лж","иф","ьг","ыр","кп","ыд","гу","чё","йр","иэ",
"вг","мя","юб","хк","яч","ьб","тя","ыш","чк","зе","уи","кц","ыч","ыб","ещ","лы",
"яб","оф","мб","ях","сё","юс","бн","тм","ём","вз","сы","ха","пы","уа","лс","шл",
"рь","сх","рж","рд","нг","хт","рх","сд","ух","мд","ьч","яю","ье","уш","уз","ща",
"ге","еф","аэ","фр","бъ","дя","тч","тб","мт","км","уо","мл","ьр","йб","вш","юп",
"фе","йч","тл","яу","нв","мр","юв","еэ","дё","яц","ыз","сш","дп","аа","ья","зя",
"юч","иш","дь","ху","яэ","бм","гн","кд","шн","вб","хд","йз","ящ","ъе","фа","хл",
"ёр","её","хм","дк","аф","ою","лк","лг","цы","юи","йг","вэ","бх","хг","ьл","ощ",
"зл","яг","йц","щё","оа","тз","ея","юз","аё","бя","ыу","кк","вц","нп","юо","лё",
"чу","нф","чш","йш","ьу","йэ","йа","юр","юн","юк","мг","юц","шк","пн","ыг","мз",
};

int spectrum[SLOG_COUNT];

void usage(char *name)
{
	printf("Usage: %s [--verbose] [--help] [file]\n", name);
}
   
int main(int argc, char *argv[]) {
 char                   c1 = 0, c2 = 0, buf[256], *src, *prog;
 int                    ret, i, verbose = 0, count = 0;
 FILE			*fd;
 static struct option   long_options[] =
 {
   {"verbose", no_argument,       0, 'v'},
   {"help",    no_argument,       0, 'h'},
   {0, 0, 0, 0}
 };

	setlocale(LC_ALL, "" );

	prog = strrchr(argv[0],'/');
	if(!prog) prog = argv[0];
	else      prog++;

	while ((ret = getopt_long (argc, argv, "vh", long_options, NULL)) != -1)
	{
		switch(ret)
		{
			case 'v': verbose = 1; break;
			case 'h': usage(prog); break;
			default: usage(prog); return 1;
		}
	}

	if(verbose) printf("Cleaning spectrum...\n");

	for(i = 0; i < SLOG_COUNT; i++) spectrum[i] = 0;

	if(argc > optind)
	{
		if(verbose) printf("Reading file %s\n",argv[optind]);
		fd = fopen(argv[optind],"r");
	}
	else
	{
		if(verbose) printf("Reading stdin\n");
		fd = stdin;
	}

	while(fgets(buf,sizeof(buf),fd))
	{
		src = buf;
		while(*src)
		{
			c2 = tolower(*src);
			if(c1 && isalpha(c2))
			{
				for(i = 0; i < SLOG_COUNT; i++)
				{
					if(slog[i][0] == c1 && slog[i][1] == c2)
					{
	        				spectrum[i]++;
	        				count++;
						break;
					}
				}
			}
			c1 = c2;
			src++;
		}
	}

	if(count > 0) 
	{
		for(i = 0; i < SLOG_COUNT; i++)
		{
			printf("%e # %s\n", (double)spectrum[i] / (double)count, slog[i]);
		}
	}

	if(fd != stdin) fclose(fd);

	return 0;
}


Вот собственно и всё.

Программка читает либо стандартный ввод, либо файл, если он указан в качестве аргумента. Выдаёт результат на терминал, ну или куда там перенаправишь - в файл, например. А можно сразу скормить рисовалке графиков.

Клоны могут отдыхать.
Лицензия - GNU, автор - я.



(Читать комментарии) - (Добавить комментарий)


[info]vchk@lj
2004-11-22 19:43 (ссылка)
UTF-8, конечно, повеселее будет. Но запретить и не пущать - пока ещё не время. Всё идёт своим чередом, потихоньку всё адаптируется к UTF-8. KOI8-R останется разве что для каких-нибудь однокристалок и встроенных контроллеров, где объём важен. Была ж KOI7 - ну и кто теперь про неё вспоминает?

(Ответить) (Уровень выше) (Ветвь дискуссии)

Re: Reply to your comment...
[info]mivlad@lj
2004-11-22 22:53 (ссылка)
Если уж важен объём, то лучше использовать windows-1251. С точки зрения объёма самого текста разницы никакой, а сортировка делается без дополнительных таблиц.

Кстати, я не могу вспомнить ничего такого однокристального с настолько ограниченным объёмом, что бы общалось с пользователем на русском языке. На пейджерах вроде бы латиница была? Что там остаётся… Станки какие-нибудь?

(Ответить) (Уровень выше) (Ветвь дискуссии)

Re: Reply to your comment...
[info]vchk@lj
2004-11-23 08:42 (ссылка)
Сортировать-то обычно не требуется. Обычно требуется выводить сообщения на русском. А в этом случае лучше, если кодировка совпадает с кодировкой той системы, где софт делается. Ну чтобы с перекодировкой не геморроиться.

А однокристальное с русским - ну да, станки, например. Или какие-нибудь системы управления чем-нибудь.

(Ответить) (Уровень выше)


[info]krace@lj
2005-01-10 14:57 (ссылка)
пейджеры были, кстати, руссифицированные. лет 10 назад, помню, мы с ними весело кувыркались. у некоторых была поддержка кириллицы в прошивке, а некоторым и ПЗУшку менять приходилось. Кодировочные таблицы там были — мама не горюй: на собаку-водолаза и на всех овчарок сразу.  ;)

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]vchk@lj
2005-01-10 17:40 (ссылка)
Это не только с пейджерами. В мобильниках тоже были забавные кодировки. Да и сейчас, текстовые LCD-экранчики индустриального стандарта (на HD44780 и т.п.) тоже с кодировкой занятной.
Вот DataVision, например -
0xA0 - "Б"
0xA1 - "Г"
0xA2 - "Ё"
0xA3 - "Ж"
0xA4 - "З"
и т.д. Т.е. в верхней части таблицы символов только те русские буквы, аналогов которых в латиннице нет.
Суть такая, что предлагается использовать латинские буквы вместо таких же по написанию русских.
Что весьма "радует" когда приходится писать софт для устройства с таким LCD. Пришлось тупенький перекодировщик написать и прогонять исходник сначала через него, а потом уже компилятору скармливать. Благо в унихообразных системах проблем с построением таких цепочек из разных приблуд нет.

(Ответить) (Уровень выше) (Ветвь дискуссии)

эх, молодость-молодость...
[info]krace@lj
2005-01-10 17:46 (ссылка)
да-да-да, именно так всё и было.

(Ответить) (Уровень выше)

Re: Reply to your comment...
[info]tarkhil@lj
2005-05-05 15:27 (ссылка)
Сортировка давным-давно загнана в разделяемые библиотеки и подгружаемые локали. А основная проблема UTF - то, что она еще не устаканилась. Я вот с трепетом думаю о том, как будем переносить на более новый Perl некую софтину, которая специально патчена для корректной обработки UTF Perl'ом 5.6.1...

(Ответить) (Уровень выше)


(Читать комментарии) -