![]()  | 
	
 
  | 
		
			
  | 	
	
	
		
		|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны | 
![]()  | 
	
	
| 
		 | 
	Опции темы | Поиск в этой теме | Опции просмотра | 
| 
		 
			 
			#1  
			
			
			
			
		 
		
		
	 | 
|||
		
		
  | 
|||
| 
	
	
		
			
			 "Построение частотного словаря и проверка закона Ципфа" 
		
	
		
		
		
		
		
	
		
		
	
	
	Нужно написать программу, которая обрабатывает текстовые файлы, пополняя базу данных встречающихся слов, сохраняя частоту встречаемости слов. По накопленному словарю построить гистограмму встречаемости слов разной длины и проверить закон Ципфа. (желательно для хранения словаря использовать суффиксное дерево). Люди знающие, подскажите с чего начать хотя бы  | 
| 
		 
			 
			#2  
			
			
			
			
		 
		
		
	 | 
|||
		
		
  | 
|||
| 
	
	
		
			
			 Закон Ципфа говорит о том, что если проанализировать достаточно большой текст, то слово, которое чаще всего в нем встречается, будет встречаться примерно в два раза чаще, чем второе по частоте, в три раза - чем третье и т.д. Что в данном контексте означает слово "примерно" для абстрактной задачи сказать сложно, но, видимо, как-то можно определить допустимую погрешность, исходя, например, из общего объема текста. Или еще как-то. 
		
	
		
		
		
		
		
	
		
		
	
	
	Суффиксные деревья применяются для решения задачи поиска самой длинной повторяющейся подстроки в заданном тексте. Прочитать про них можно здесь: http://algolist.manual.ru/ Вот тут http://www.delphisources.ru/forum/showthread.php?t=2944 лежит программа, которая ищет в произвольном текстовом файле слова, встречающиеся в каждом предложении. Это не то, что вам нужно, но может быть полезным. А может и не быть ![]() Вам нужно слова выбирать с учетом словоформ, как я понял?  | 
| 
		 
			 
			#3  
			
			
			
			
		 
		
		
	 | 
|||
		
		
  | 
|||
| 
	
	
		
			
			 Ну да, союзы, предлоги - всё это. Пасиб, почитаем 
		
	
		
		
		
		
		
	
		
		
	
	
	 | 
| 
		 
			 
			#4  
			
			
			
			
		 
		
		
	 | 
|||
		
		
  | 
|||
| 
	
	
		
			
			 Спрашивая про словоформы, я имел в виду вот что: слова, допустим, "программист" и "программисты" нужно считать как одно слово или как разные? Потому, что если как разные, то здесь вообще не видно проблемы, разве что продумать грамотную организацию словаря для быстрого поиска. Если же это считается как одно слово, но в разных формах, то тогда уже хитрее алгоритм получается. 
		
	
		
		
		
		
		
	
		
		
	
	
	 | 
| 
		 
			 
			#5  
			
			
			
			
		 
		
		
	 | 
|||
		
		
  | 
|||
| 
	
	
		
			
			 Нет, всё-таки нужны слова. "программист" и "программисты" нужно считать как РАЗНЫЕ слова. Еще есть вопрос - подразумевает ли данная программы использование базы данных на Delphi (в условии есть фраза "пополняя базу данных встречающихся слов")? 
		
	
		
		
		
		
		
	
		
		
	
	
	 | 
| 
		 
			 
			#6  
			
			
			
			
		 
		
		
	 | 
|||
		
		
  | 
|||
| 
	
	
		
			
			 Проблема в том, как хранить этот частотный словарь?  
		
	
		
		
		
		
		
	
		
		
	
	
	Есть мнение по реализации программы: "Заводишь большой массив структуры{слово,частота}. Открываешь файл. Считываешь слово. Автоматом заносишь его в массив. Частоту увеличиваешь на 1. Считываешь следущее слово. Пробегаешь по массиву от начального элемента до текущего. Смотришь, было ли оно там. Если было, частоту слова увеличиваешь на 1. Если нет помещаешь в массив новое слово. И так, пока не конец файла." А где этот массив записей хранить тогда, в типизированном файле?  | 
| 
		 
			 
			#7  
			
			
			
			
		 
		
		
	 | 
|||
		
		
  | 
|||
| 
	
	
		
			
			 Попробуй написать класс... 
		
	
		
		
		
		
		
	
		
		
	
	
	А данные храни в xml и парси в класс... Может так будет лучше..  | 
| 
		 
			 
			#8  
			
			
			
			
		 
		
		
	 | 
|||
		
		
  | 
|||
| 
	
	
		
			
			 Для меня это звучит жестоко )) 
		
	
		
		
		
		
		
	
		
		
	
	
	 | 
| 
		 
			 
			#9  
			
			
			
			
		 
		
		
	 | 
|||
		
		
  | 
|||
| 
	
	
		
			
			 Да не так уж это и страшно...  
		
	
		
		
		
		
		
	
		
		
	
	
	Тогда создай таблицу.. в БД.. А то типизированные долго обрабатывать будешь... если слов много..  | 
| 
		 
			 
			#10  
			
			
			
			
		 
		
		
	 | 
|||
		
		
  | 
|||
| 
	
	
		
			
			 Код: 
	  public
    { Public declarations }
  end;
 
type
  PRec = ^TRec;
  TRec = record
    str: string;
    col: LongWord;
  end;
 
type
   zap = record
       slovo : string;
       chast : Longword;
   end;
 
var
  Form1: TForm1;
  mas_slov: array of zap;
  O: string;
 
implementation
 
{$R *.dfm}
 
function TrimEx( s: string ): string;
begin
   Result := s;
   Result := StringReplace( Result, ',', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, '.', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, '!', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, '?', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, '-', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, ';', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, ':', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, '=', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, '*', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, '(', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, ')', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, '/', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, '_', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, '"', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, '+', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, '\', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, '<', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, '>', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, '[', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, ']', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, '{', '', [rfReplaceAll, rfIgnoreCase] );
   Result := StringReplace( Result, '}', '', [rfReplaceAll, rfIgnoreCase] );
   // Убираем лишние символы..
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  StringCount: Word;
  sl: TStringList;
  l: TList;
  i, j: integer;
  s, tmp: string;
  r: PRec;
  f: boolean;
begin
   StringCount := 0;
   sl := TStringList.Create;
 
   // выделяем слова
   for i := 0 to Memo1.Lines.Count-1 do
   begin
      s := Memo1.Lines[i];
      while Length( s ) > 0 do
      begin
         if Pos( ' ', s ) > 0 then
         begin
            tmp := Copy( s, 1, Pos( ' ', s )-1 );
            Delete( s, 1, Pos( ' ', s ) );
            tmp := TrimEx( tmp );
         end
         else
         begin
            tmp := s;
            s := '';
            tmp := TrimEx( tmp );
         end;
         if Trim( tmp ) <> '' then
            sl.Add( tmp );
      end;
   end;
 
   StringCount := sl.Count;
 
   // Производим расчёт
   l := TList.Create;
   for i := 0 to sl.Count-1 do
   begin
      if l.Count = 0 then
      begin
         New( r );
         r^.str := sl[i];
         r^.col := 1;
         l.Add( r );
      end
      else
      begin
         f := false;
         for j := 0 to l.Count-1 do
         begin
            r := l[j];
            if r^.str = sl[i] then
            begin
               r^.col := r^.col + 1;
               l[j] := r;
               f := true;
               Break;
            end;
         end;
         if not f then
         begin
            New( r );
            r^.str := sl[i];
            r^.col := 1;
            l.Add( r );
         end;
      end;
   end;
 
   // Выводим результат
   for i := 0 to l.Count-1 do
   begin
      r := l[i];
 
      Memo2.Lines.Add( r^.str + ' - ' + IntToStr( r^.col ) + ' (' + Format( '%.2f%%', [r^.col/StringCount*100] ) + ')' );
//**********************************      
      mas_slov[i].slovo := r^.str;
      mas_slov[i].chast := r^.col;
//**********************************
   end;
 
   l.Free;
   sl.Free;
end;
 
procedure TForm1.Button2Click(Sender: TObject);
begin
 with OpenDialog1 do
  begin
   if not Execute then Exit;
   Memo1.Lines.LoadFromFile(FileName);
  end;
end;
 
procedure TForm1.Button3Click(Sender: TObject);
 Var FST : TFileStream;
begin
  FST := TFileStream.Create('slov.txt',fmCreate);
  Memo2.Lines.SaveToStream(FST);
  FST.Free;
end;
 
end.Не могу загнать данные (слово, частота) в массив записей mas_slov. Главное в Memo выводит r^.str и r^.col, а в массив нет!  | 
| 
		 
			 
			#11  
			
			
			
			
		 
		
		
	 | 
|||
		
		
  | 
|||
| 
	
	
		
			
			 Код: 
	program WordFreq;
{$APPTYPE CONSOLE}
uses
  SysUtils,
  Classes;
var
  Dictionary: TStringList;
const
  WordDelimiters = ' !?.,;`-+*=/\<>()[]~{}'#39;
function  DictionarySortFunc(List: TStringList; Index1, Index2: Integer): Integer;
begin
  if      Integer(List.Objects[Index1]) > Integer(List.Objects[Index2]) then Result := 1
  else if Integer(List.Objects[Index1]) < Integer(List.Objects[Index2]) then Result := -1
  else
    Result := 0;
end;
procedure AddToDictionary(SWord: String);
var
  i: Integer;
begin
  SWord := AnsiLowerCase(SWord);
  if Dictionary.Find(SWord, i)
    then Dictionary.Objects[i] := Pointer(Integer(Dictionary.Objects[i]) + 1)
    else Dictionary.AddObject(SWord, Pointer(1));
end;
procedure ProcessString(S: String);
var
  SWord: String;
  i    : Integer;
begin
  if (S <> '') and (Pos(S[Length(S)], WordDelimiters) = 0) then
    S := S + WordDelimiters[1];
  i     := 1;
  SWord := '';
  while (i <= Length(S)) do
    if Pos(S[i], WordDelimiters) = 0 then begin
      SWord := SWord + S[i];
      Inc(i);
    end else begin
      if SWord <> '' then
        AddToDictionary(SWord);
      SWord := '';
      while Pos(S[i], WordDelimiters) <> 0 do
        Inc(i);
    end;
end;
var
  F : Text;
  S : String;
  i : Integer;
begin
  try
    if   (ParamCount < 1)
      or (Pos('?', ParamStr(1)) = 1)
      or (not FileExists(ParamStr(1))) then begin
      Writeln('Use: ' + ExtractFileName(ParamStr(0)) + ' <filename>');
      Exit;
    end;
    Dictionary := TStringList.Create;
    Dictionary.Sorted := True;
    AssignFile(F, ParamStr(1));
    Reset(F);
    while not Eof(F) do begin
      Readln(F, S);
      ProcessString(Trim(S));
    end;
    CloseFile(F);
    Dictionary.Sorted := False;
    Dictionary.CustomSort(DictionarySortFunc);
    Assign(F, ChangeFileExt(ParamStr(1), '.result'));
    Rewrite(F);
    for i := 0 to Dictionary.Count - 1 do
      Writeln(F, Integer(Dictionary.Objects[i]), ' - ', Dictionary[i]);
    CloseFile(F);
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end. | 
| 
		 
			 
			#12  
			
			
			
			
		 
		
		
	 | 
|||
		
		
  | 
|||
| 
	
	
		
			
			 Спасибо, Rosenkrantz. 
		
	
		
		
		
		
		
	
		
		
	
	
	НО частотный словарь хотелось бы хранить и наращивать, вкидывая на обработку новые тексты. Ладно, это мои проблемы. Больше нет времени, ничего координально править не буду. Еще раз спасибо. P.S. завтра пойду на защиту с комиссией, лишь бы не запарили не по делу  | 
| 
		 
			 
			#13  
			
			
			
			
		 
		
		
	 | 
|||
		
		
  | 
|||
| 
	
	
		
			
			 Всё норм - сдал. Всем спасибо, тема закрыта. 
		
	
		
		
		
		
		
	
		
		
	
	
	 |