C++Builder
  Начало   Форум   Помощь Войти Регистрация  
Страниц: [1]   Вниз
  Печать  
Автор Тема: Подсчет частоты встречи слов от 1 до 10 букв  (Прочитано 8420 раз)
fuckbingo
Участник
**

Сказали спасибо: +0/-0
Offline Offline

Сообщений: 5


« : 06 июля 2012, 00:40:39 »

Подсчет частоты встречи слов от 1 до 10 букв(включительно) в текстовых файлах русского алфавита. Нужно подсчитать и сделать в stringird некую статистику: длина слова, количество встреченных слов в тексте, частоты появления (в % от общего количества слов в тексте)




 Непонимающий
Записан
S0mbre
Глобальный модератор
***

Сказали спасибо: +1113/-22
Offline Offline

Сообщений: 2137

S0mbre


WWW
« Ответ #1 : 09 июля 2012, 09:48:53 »

Был в настроении  Улыбка
Код
//---------------------------------------------------------------------------
// Unit1.h
//---------------------------------------------------------------------------
#include <Grids.hpp>
#include <vector.h>
//---------------------------------------------------------------------------
 
const int MINW = 1; // мин. длина слова
const int MAXW = 10; // макс. длина слова
 
struct CStats // структура для хранения статистики по данному слову
{
String word; // само слово
int length; // длина
long count; // количество совпадений в тексте
double percent; // процент (встречаемость в тексте)
 
__fastcall CStats(const String wd, int len=0, int cnt=0, double perc=0.0f) :
word(wd), count(cnt), length(len), percent(perc)
{ }
// оператор < для сортировки в контейнере
bool __fastcall operator<(CStats& obj)
{
return (word < obj.word);
}
bool __fastcall operator<(const CStats& obj) const
{
return (word < obj.word);
}
// оператор == для сравнения 2 структур между собой
bool __fastcall operator==(CStats& obj)
{
return (word == obj.word);
}
bool __fastcall operator==(const CStats& obj) const
{
return (word == obj.word);
}
};
 
// определени типа контейнера статистики по словам (std::vector)
typedef vector<CStats> StatVec;
typedef StatVec::iterator StatVec_I; // тип итератора
typedef StatVec::const_iterator StatVec_CI; // константный итератор
 
// объявление формы
class TForm1 : public TForm
{
__published:
void __fastcall Button2Click(TObject *Sender);
// ... (остальное)
private:
StatVec vData; // контейнер данных статистики
// функция для предв. форматирования текста
void __fastcall PreprocessText(String& Text /* исходный текст */);
// подсчет статистики слов в тексте
void __fastcall CountStats(String& Text /* исходный текст */,
long& TotalWords /* сюда запишется общее кол-во слов */);
// подсчет статистики слов в тексте (загрузка из файла)
void __fastcall CountStatsFromFile(const String TextFile /* путь текстового файла */,
long& TotalWords /* сюда запишется общее кол-во слов */);
// вывод статистики в грид
void __fastcall StatsToGrid(const StatVec& Data /* контейнер данных статистики */,
long TotalWords /* общее кол-во слов */, TStringGrid* Grid /* грид */);
// ... (остальное)
};
 
//---------------------------------------------------------------------------
// Unit1.cpp
//---------------------------------------------------------------------------
#include "Unit1.h"
#include <algorithm> // для sort, equal_range
#include <memory> // для auto_ptr
//---------------------------------------------------------------------------
 
void __fastcall TForm1::PreprocessText(String& Text)
{
// функция для предв. форматирования текста
 
Text = Text.LowerCase(); // переводим текст в нижний регистр
for(long i=1; i<=Text.Length(); i++) {
// если буква - не буква алфавита и не пробел, удалить ее
if(!isalpha(Text[i]) && !isspace(Text[i])) Text.Delete(i--, 1);
}
}
 
//---------------------------------------------------------------------------
void __fastcall TForm1::CountStats(String& Text, long& TotalWords)
{
// подсчет статистики слов в тексте
 
// 1. форматируем текст (удаляем знаки препинания и т.д.)
PreprocessText(Text);
// 2. список для хранения слов
std::auto_ptr<TStringList> slWords(new TStringList());
slWords->Delimiter = ' '; // разделитель слов - пробел (а также перенос строки)
slWords->DelimitedText = Text; // загружаем слова в список из текста
 
vData.clear(); // очищаем статистику
 
long total(0L); // счетчик слов, по которым ведется статистика
int len(0); // длина слова
 
for(long i=0L; i<slWords->Count; i++) { // цикл по словам в тексте
len = slWords->Strings[i].Trim().Length(); // получаем длину слова
if(len >= MINW && len <= MAXW) { // если длина в пределах [MINW, MAXW]...
// добавляем слово в контейнер (пока только само слово + длина)
vData.push_back(CStats(slWords->Strings[i].Trim().LowerCase(), len));
total++; // инкремент счетчика слов
}
}
TotalWords = total; // присваем TotalWords значение счетчика слов
if(vData.empty()) {
// если слов в контейнере нет, выход
ShowMessage("Файл не содержит слов!");
return;
}
 
std::sort(vData.begin(), vData.end()); // сортировка контейнера статистики (используется оператор <)
std::pair<StatVec_I, StatVec_I> bounds; // границы диапазона для equal_range
 
long count;
for(StatVec_CI cit=vData.begin(); cit!=vData.end(); ++cit) { // цикл по элементам контейнера статистики
// находим диапазон одинаковых слов, равных след. элементу
bounds = std::equal_range(vData.begin(), vData.end(), *cit);
// указатель на первый элемент в диапазоне
StatVec_I first_i = bounds.first;
// количество элементов в диапазоне (кол-во одинаковых слов, идущих подряд)
count = long(bounds.second - first_i);
if(count) { // если диапазон не пустой
if(count > 1L) vData.erase(first_i + 1, bounds.second); // удалить из контейнера остальные слова, кроме первого
first_i->count = count; // записываем кол-во совпадений (=размер диапазона)
first_i->percent = (double)count * 100.0f / (double)total;  // процент встречаемости
}
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::CountStatsFromFile(const String TextFile, long& TotalWords)
{
// подсчет статистики слов в тексте (загрузка из файла)
 
if(!FileExists(TextFile)) {
ShowMessage("Файл не существует!");
return;
}
std::auto_ptr<TStringList> slFile(new TStringList());
slFile->LoadFromFile(TextFile);
String Text = slFile->Text;
CountStats(Text, TotalWords);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::StatsToGrid(const StatVec& Data, long TotalWords, TStringGrid* Grid)
{
// вывод статистики в грид
 
Grid->RowCount = Data.size() + 2;
Grid->ColCount = 4;
Grid->Cells[0][0] = "Слово";
Grid->Cells[1][0] = "Длина";
Grid->Cells[2][0] = "Подсчет";
Grid->Cells[3][0] = "Встречаемость";
 
Grid->Cells[0][1] = "[ВСЕГО СЛОВ]:";
Grid->Cells[1][1] = "-";
Grid->Cells[2][1] = String(TotalWords); // общее кол-во слов
Grid->Cells[3][1] = "-";
 
long i = 2L;
for(StatVec_CI cit=vData.begin(); cit!=vData.end(); ++cit, i++) {
// цикл по элементам контейнера
Grid->Cells[0][i] = cit->word;
Grid->Cells[1][i] = String(cit->length);
Grid->Cells[2][i] = String(cit->count);
Grid->Cells[3][i] = FloatToStr(cit->percent);
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
// подсчет статистики текста в Memo1
// и вывод в StringGrid1
 
String Text = Memo1->Lines->Text;
long w(0L);
CountStats(Text, w);
   Memo1->Lines->Text = Text;
StatsToGrid(vData, w, StringGrid1);
}
 
Записан
fuckbingo
Участник
**

Сказали спасибо: +0/-0
Offline Offline

Сообщений: 5


« Ответ #2 : 09 июля 2012, 12:47:32 »

 Подмигивающий
Записан
fuckbingo
Участник
**

Сказали спасибо: +0/-0
Offline Offline

Сообщений: 5


« Ответ #3 : 09 июля 2012, 13:03:59 »

эм..........а возможно ли как то попроще)) а то Препод от меня ох....  сделать допустим как нибудь через условие по кодировке. (например если первая и последняя буквы входит в диапозон от а до я), то это слово и дальше считать длину слов и вывод в статистику? Непонимающий
Записан
fuckbingo
Участник
**

Сказали спасибо: +0/-0
Offline Offline

Сообщений: 5


« Ответ #4 : 09 июля 2012, 13:06:21 »

вот моя прога) http://zalil.ru/33555531
Записан
S0mbre
Глобальный модератор
***

Сказали спасибо: +1113/-22
Offline Offline

Сообщений: 2137

S0mbre


WWW
« Ответ #5 : 09 июля 2012, 16:03:45 »

Куда уж проще? Разбиение текста на слова происходит автоматически, буквально в 2 строчках
Код
slWords->Delimiter = ' ';
slWords->DelimitedText = Text;
 
Если для программы требуется Билдер, это самый очевидный подход. Что касается прочих "сложностей", без них программа будет работать некорректно. Например, функция PreprocessText нужна, чтобы удалить знаки препинания и перевести текст в нижний регистр (без этого "Пока" и "пока" будут разными словами, также как и "Эй!" и "Эй"). Функцию CountStats можно, конечно, разработать и без алгоритмов стандартной библиотеки, но займет гораздо больше места. Мне уже лень будет  Улыбка
Записан
fuckbingo
Участник
**

Сказали спасибо: +0/-0
Offline Offline

Сообщений: 5


« Ответ #6 : 09 июля 2012, 19:20:50 »

ты сделал подсчет одинаковых слов? или одинаковой длины? Улыбка нужно одинаковой длины)
допустим дан текст: слово язык рот губы нос глаза
должно получиться 2 слова по 3 буквы, 2 по 4 и 2 по 5
Записан
Leex
Участник
**

Сказали спасибо: +132/-1
Offline Offline

Сообщений: 577


« Ответ #7 : 09 июля 2012, 22:54:25 »

std::map для этой задачи идеален. Ключем делаешь длину слова а значение это частота встречания влов этой длинны.
алгоритм будет типа:
1)заводишь std::map<int,int> fmap;
2)берешь очередное слово, если слов больше нет, то на пункт 8
3)проверяешь его на корректность (на русские буквы)
4)если слово некорректно, то гуляешь на пункт 2
5)берешь длину слова сохраняешь где-нибудь, ну скажем в переменной length;
6)сохраняешь инфу в мапе. в нашем случае будет так: fmap[length]++;
7)идешь на шаг 2
Крутойв fmap вся статистика, выводишь/сохраняешь куда там тебе надо.
Записан
S0mbre
Глобальный модератор
***

Сказали спасибо: +1113/-22
Offline Offline

Сообщений: 2137

S0mbre


WWW
« Ответ #8 : 10 июля 2012, 14:14:09 »

ты сделал подсчет одинаковых слов? или одинаковой длины? Улыбка нужно одинаковой длины)
допустим дан текст: слово язык рот губы нос глаза
должно получиться 2 слова по 3 буквы, 2 по 4 и 2 по 5

Мил человек, а ты как спрашивал в топике?  В замешательстве

Подсчет частоты встречи слов от 1 до 10 букв(включительно) в текстовых файлах русского алфавита. Нужно подсчитать и сделать в stringird некую статистику: длина слова, количество встреченных слов в тексте, частоты появления (в % от общего количества слов в тексте)

GIGO, друг мой.
Записан
S0mbre
Глобальный модератор
***

Сказали спасибо: +1113/-22
Offline Offline

Сообщений: 2137

S0mbre


WWW
« Ответ #9 : 10 июля 2012, 14:24:45 »

1. Бери книгу Герберта Шилдта "C++. Методики программирования Шилдта".
2. Там есть раздел "Работа со строками", а в нем есть пример программы для разбивки текста на слова _без использования STL, динамических контейнеров и т.д._ - чисто C-строки, isalpha, ispunct, strtok и т.д.
3. Дальше - по наитию.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в: