Вывести из файла все русские слова по алфавиту, начинающихся с гласной - C (СИ)
Формулировка задачи:
Здраствуйте.
Дано текстовый файл.за один просмотр файла вывести его содержание в следующем порядке:
сначала все русские слова по алфавиту, начинающихся с гласной, и количество их вхождений в файл, а затем аналогичные данные о словах, начинающихся с гласной.
Решение задачи: «Вывести из файла все русские слова по алфавиту, начинающихся с гласной»
textual
Листинг программы
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node_t
{
char* pstr; // Указатель на слово
size_t length; // Длина слова
size_t count; // Количество слов
struct node_t* next; // Следующий узел
} TNode;
//-----------------------------------------------------------------------------
// Функция меняет верхний регистр русских букв на ничжний
char ToLower(char c)
{
if (('А' <= c) && (c <= 'П'))
{
c += 32;
}
else if (('Р' <= c) && (c <= 'Я'))
{
c += 80;
}
else if ('Ё' == c)
{
c = 'ё';
}
return c;
}
//-----------------------------------------------------------------------------
// Функция определяет является ли символ буквой русского алфавита
int IsAlpha(char c)
{
return ((('А' <= c) && (c <= 'п') )||
(('р' <= c) && (c <= 'ё')));
}
//-----------------------------------------------------------------------------
// Функция сравнивает 2 строки заданной длины.
// Ориентирована на русский алфавит. Сравнение регистронезависимое.
int StrNCmp(const char* a, size_t lenA, const char* b, size_t lenB)
{
// Берём минимальную из длин
size_t len = (lenA < lenB) ? lenA : lenB;
int result = 0;
int i;
// Выполняем пока не достигнем минимальной длины
// или пока не найдём различия
for (i = 0; (i < len) && (result == 0); ++i)
{
result = ToLower(a[i]) - ToLower(b[i]);
}
// Если различий небыло, тогда пытаеся наёти
// различия в длине
if (result == 0)
{
result = lenA - lenB;
}
return result;
}
//-----------------------------------------------------------------------------
// Находит в заданной строке слово на русском языке.
// В begin передаётся указатель на начало слова, а end - конец
int GetWord(char* text, char** begin, char** end)
{
// Перебирваем символы в строке пока не встретим
// русскую букву (ну или пока текст не закончится)
for (; *text && !IsAlpha(*text); ++text) { ; }
*begin = text;
// Перебирваем символы в строке пока встречаются
// русские буквы
for (; *text && IsAlpha(*text); ++text) { ; }
*end = text;
// Возвращаем длину найденного слова
return *end - *begin;
}
//-----------------------------------------------------------------------------
// Функция добавляет в список новое слово не нарушая порядок сортировки списка.
// Если такое слово уже встречается, то значение count узла просто инкрементируется.
TNode* PushWithSortAndCount(TNode** list, char* pstr, size_t length)
{
// Временно создаём самый верхний узел.
// Создаётся для упрощения дальнейшего алгоритма
TNode* head = (TNode*) malloc(sizeof(TNode));
TNode* cur = head;
TNode* node;
int cmp = 1;
head->next = *list;
// Ищем мето, куда можно пристроить новое слово.
// Если cmp будет равно 0, то это означает, что такое
// слово уже есть
for (; cur->next &&
((cmp = StrNCmp(cur->next->pstr, cur->next->length, pstr, length)) < 0)
; cur = cur->next) { ; }
// Если слово не повторяется, то создаём и вставляем новый узел
if (cmp)
{
node = (TNode*) malloc(sizeof(TNode));
node->pstr = pstr;
node->length = length;
node->count = 1;
node->next = cur->next;
cur->next = node;
// В случае если слово попало на вершину списка
if (cur == head)
{
*list = node;
}
}
// Слово уже есть
else
{
cur->next->count++;
}
free(head);
return *list;
}
//-----------------------------------------------------------------------------
// Очищаем всеь список
void Clear(TNode** list)
{
TNode* node;
// Перебираем все эелементы и удаляем каждый узел
while (*list)
{
node = *list;
*list = node->next;
free(node);
}
}
//-----------------------------------------------------------------------------
// Печать списка
void Print(const TNode* list, FILE* stream)
{
for (; list; list = list->next)
{
fprintf(stream, "\t%4d : %.*s\n", list->count, list->length, list->pstr);
}
}
//-----------------------------------------------------------------------------
// Вормируем из текста 2 списка. В одном храняться информация о словах
// начинающихся на гласные буквы, в другом - на согласные. Оба списка не
// дублируют слова из text, а хранять лишь указатели.
void GetLists(char* text, TNode** a, TNode** b)
{
const char CChars[] = "аеёиоуыэюя";
char* begin;
char* end;
while (GetWord(text, &begin, &end) > 0)
{
if (strchr(CChars, ToLower(*begin)))
{
PushWithSortAndCount(a, begin, end - begin);
}
else
{
PushWithSortAndCount(b, begin, end - begin);
}
text = end;
}
}
//-----------------------------------------------------------------------------
// Загружаем содержимое файла в память
char* GetTextFromFile(const char* fname)
{
FILE* f = fopen(fname, "rb");
if (f == NULL)
{
perror(fname);
system("pause");
exit (EXIT_FAILURE);
}
// Определяем размер файла
fseek(f, 0, SEEK_END);
size_t size = ftell(f);
fseek(f, 0, SEEK_SET);
char* text = (char*) malloc(size + 1);
text[size] = '\0';
// Загружаем
fread(text, size, 1, f);
fclose(f);
return text;
}
//-----------------------------------------------------------------------------
int main(int argc, char* argv[])
{
if (argc != 2)
{
fprintf(stdout, "Использование: program <ТЕКСТОВЫЙ ФАЙЛ>\n"
"Примечание: текстовый фал должен быть в кодировке CP866\n");
system("pause");
return EXIT_FAILURE;
}
char* text = GetTextFromFile(argv[1]);
TNode* a = NULL;
TNode* b = NULL;
GetLists(text, &a, &b);
fprintf(stdout, "Сам текст\n"
"-----------------------\n"
"%s\n\n", text);
fprintf(stdout, "Начинающиеся на гласные\n"
"-----------------------\n");
Print(a, stdout);
fprintf(stdout, "Начинающиеся на согласные\n"
"-----------------------\n");
Print(b, stdout);
Clear(&a);
Clear(&b);
free(text);
system("pause");
return EXIT_SUCCESS;
}