Объясните принцип работы программы, которая удаляет слова из строки
Программа удаляет из строки все одинаковые слова и записывает количество повторов. Каким образом это происходит? Как реализован принцип работы функций?
#include <stdio.h>
#include <ctype.h>
// ищем самое первое слово в строке
int FindFirstWord(char* text, char** begin, char** end)
{
for (; *text && !isalpha(*text); ++text) { ; } // int isalpha(int c) проверяет, является ли передаваемый символ алфавитным
*begin = text;
for (; *text && isalpha(*text); ++text) { ; }
*end = text;
return (*begin != *end);
}
// двигаем строку
char* PullUpSubstr(char* text, size_t length)
{
for (; *text; *text = *(text + length), ++text) { ; }
return text;
}
// сравниваем 2 строки (последовательности)
int CompareSequence(char* first, char* second, size_t length)
{
for (; *first && *second && length && (*first == *second); ++first, ++second, --length) { ; }
return (length == 0);
}
// копируем 2 последовательности
char* CopySequence(char* dist, const char* source, size_t length)
{
for (; *source && length; *dist++ = *source++, --length) { ; }
return dist;
}
// ищем дубль слово, если нашли, то возвращаем указатель, иначе ноль
char* GetDuplicateWord(char* text, char* word, size_t length)
{
char* duplicate = NULL;
char* begin;
char* end;
for (; !duplicate && FindFirstWord(text, &begin, &end); text = end + 1)
{
if (((end - begin) == length) && CompareSequence(begin, word, length))
{
duplicate = begin;
}
}
return duplicate;
}
//----------------------------------------------//
// удаление всех дубль слов
size_t DeleteDuplicate(char* text, char* result)
{
size_t count = 0;
char* begin;
char* end;
char* cursor;
int find;
for (; FindFirstWord(text, &begin, &end); text = end + 1)
{
for (cursor = end + 1, find = 0; (cursor = GetDuplicateWord(cursor, begin, end - begin)) != NULL; ++find)
{
PullUpSubstr(cursor, end - begin);
}
if (find)
{
result = CopySequence(result, begin, end - begin);
*result++ = ' ';
*result = 0;
PullUpSubstr(begin, end - begin);
end = begin;
count++;
}
}
return count;
}
int main()
{
printf("Vvedite text (english): ");
char text[1024];
fgets(text, sizeof(text) - 1, stdin);
char result[1024] = { 0 };
size_t count = DeleteDuplicate(text, result);
printf("%s%s%u\n", text, result, count);
return 0;
}
Ответы (1 шт):
Функция FindFirstWord - функция для поиска первого слова начиная с позиции *text (указатель на строку)
сначала ищется начало слова последовательно перебирая все символы и проверяя, что 1) строка не закончилась, т.е. символ не равен 0, 2) что символ не является буквой
*text && !isalpha(*text)
результат (позиция/указатель на слово) записывается в переменную begin
затем ищется уже конец слова последовательно перебирая все символы и проверяя, что 1) строка не заканчивается, т.е. символ не равен 0, 2) что символ является буквой
*text && isalpha(*text)
результат (позиция/указатель на слово) записывается в переменную end
поскольку в С нет ссылок, то для записи значений приходится использовать указатель на переменную, а поскольку в переменной содержится указатель, то получается указатель на указатель - 'char** begin', 'char** end'
в качестве результата функции возвращается значение - содержит ли слово хотя бы 1 букву (не совпадает ли начало и конец найденного слова)
*begin != *end
это сделано для того, чтобы отследить было ли вообще в строке найдено хоть какое-то слово, например в строке 12345 @ ни одного слова найдено не будет
Код функции:
// ищем самое первое слово в строке
int FindFirstWord(char* text, char** begin, char** end)
{
for (; *text && !isalpha(*text); ++text) { ; } // int isalpha(int c) проверяет, является ли передаваемый символ алфавитным
*begin = text;
for (; *text && isalpha(*text); ++text) { ; }
*end = text;
return (*begin != *end);
}
Функция PullUpSubstr - функция для того, чтобы передвинуть строку на length символов влево, например 123xyz при сдвигании на 3 символа влево превратится в xyz
для этого просто происходит перезапись символов в позиции pos = i на символы из позиции pos = i + length:
*text = *(text + length)
Код функции:
// двигаем строку
char* PullUpSubstr(char* text, size_t length)
{
for (; *text; *text = *(text + length), ++text) { ; }
return text;
}
Функция CompareSequence - функция для сравнении двух строк, в которой посимвольно сравниваются строки и определяется все ли символы совпадают
// сравниваем 2 строки (последовательности)
int CompareSequence(char* first, char* second, size_t length)
{
for (; *first && *second && length && (*first == *second); ++first, ++second, --length) { ; }
return (length == 0);
}
для каждого символа проверяется - не является ли он концом строки (не является ли он 0):
*first && *second
каждый новый символ длина проверяемых символов length уменьшается на 1, если проверены все символы (т.е. строки совпадают), то длина будет равна 0, поэтому окончательно для результата сравнивается длина проверяемых символов с 0
return (length == 0);
Функция CopySequence - функция для копирования length символов из одной строки в начало второй строки
// копируем 2 последовательности
char* CopySequence(char* dist, const char* source, size_t length)
{
for (; *source && length; *dist++ = *source++, --length) { ; }
return dist;
}
копируется максимум length символов, проверяя при этом что при копировании символов не достигнут конец строки:
*source
Функция GetDuplicateWord - функция, которая ищет первый дубликат слов в строке. После того, как найдено ранее было слово, дальше с позиции где заканчивается слово начинает искаться следующее слово и сравниваться с найденным, если найденное слово совпадает с первым - считается, что дубликат найден и выдается на него указатель
// ищем дубль слово, если нашли, то возвращаем указатель, иначе ноль
char* GetDuplicateWord(char* text, char* word, size_t length)
{
char* duplicate = NULL;
char* begin;
char* end;
for (; !duplicate && FindFirstWord(text, &begin, &end); text = end + 1)
{
if (((end - begin) == length) && CompareSequence(begin, word, length))
{
duplicate = begin;
}
}
return duplicate;
}
Функция DeleteDuplicate - функция для удаления найденного ранее дубликата для этого в слове для каждого найденного слова ищутся все дубликаты и последовательно сдвигают строку на размер дубликата, чтобы затем заново искать первое слово и проверять его на дубликат
// удаление всех дубль слов
size_t DeleteDuplicate(char* text, char* result)
{
size_t count = 0;
char* begin;
char* end;
char* cursor;
int find;
for (; FindFirstWord(text, &begin, &end); text = end + 1)
{
for (cursor = end + 1, find = 0; (cursor = GetDuplicateWord(cursor, begin, end - begin)) != NULL; ++find)
{
PullUpSubstr(cursor, end - begin);
}
if (find)
{
result = CopySequence(result, begin, end - begin);
*result++ = ' ';
*result = 0;
PullUpSubstr(begin, end - begin);
end = begin;
count++;
}
}
return count;
}
В общем алгоритм простой:
в строке ищем первое слово
если слово не найдено - заканчиваем выполнение программы и выводим счетчик дубликатов
если слово найдено, то с позиции после конца слова ищем последовательно слова
найденное слово проверяется с первоначальным
если слова совпадают, то счетчик дубликатов увеличивается на 1, а строка смещается на начало позиции дубликата
опять выполняется п. 3)
опять выполняется п. 1)
возвращается счетчик дубликатов
P.S.
даже для C алгоритм очень топорный (много лишнего функционала, не используются доступные функции, например для сравнения строк), можно сделать проще, красивее и гораздо быстрее!!!
если же использовать C++ и STL, то можно сделать еще более короткий и понятный код