С: подкорректировать работу со строками
например есть слово "проводник" и предлог "од", так вот он слово "проводник" преобразует в "пров!!ник". Нужно реализовать поиск предлогов, учитывая, что после них должен идти разделитель. Массив разделителей указан, но как реализовать - ума не приложу.
среда Turbo c++
Написать надо на С
код программы:
#include<conio.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define ST 10
char* modString(char *string, char *strReplaced, char *strReplacedBy)
{
int originalStringLength, strReplacedLength, strReplacedByLength;
int posReplacingCount, posReplacingNumber;
int i, j, k;
int *numpos;
char *result;
originalStringLength = strlen(string);
strReplacedLength = strlen(strReplaced);
strReplacedByLength = strlen(strReplacedBy);
posReplacingCount = 0;
numpos = (int*)malloc(sizeof(int) * (originalStringLength / strReplacedLength + 1));
for(i = 0; i <= originalStringLength - strReplacedLength; ++i)
{
j = 0;
while(j < strReplacedLength && string[i + j] == strReplaced[j])
++j;
if(j == strReplacedLength)
{
numpos[posReplacingCount++] = i;
i += strReplacedLength - 1;
}
}
if(!posReplacingCount)
{
result = (char*)malloc(sizeof(char) * (originalStringLength + 1));
strcpy(result, string);
}
else
{
result = (char*)malloc(sizeof(char) * (originalStringLength + (strReplacedByLength - strReplacedLength) * posReplacingCount + 1));
for(i = 0, j = 0, posReplacingNumber = 0; i < originalStringLength; ++i, ++j)
if(posReplacingNumber == posReplacingCount || numpos[posReplacingNumber] > i)
result[j] = string;
else
{
for(k = 0; k < strReplacedByLength; ++k, ++j)
result[j] = strReplacedBy[k];
i+= strReplacedLength - 1;
--j;
++posReplacingNumber;
}
for( ; i < originalStringLength; ++i, ++j)
result[j] = string;
result[j] = '\0';
}
free(numpos);
return result;
}
void main()
{
FILE *f;
char *fli[ST], *pch, *ptr;
char ch, *p;
char predl[13][7]={"v","k","s","a","do","po","iz","na","od","bez","pri","pered","cherez"},
zamen[13][7]={"!","!","!","!","!!","!!","!!","!!","!!","!!!","!!!","!!!!!","!!!!!!"},
razdel[9][1]={",","."," ","\0","!","?","(",")","\""};
int i, col_st=0, j, k;
clrscr();
printf("vyberite metod vvoda:\n1 - s klaviatury\n2 - s faila temp.txt\n");
ch=getch();
if(ch==49)
{
printf("\nVvod s klaviatury\n");
printf("\nSkoka budet strok:");
scanf("%d", &col_st);
if((col_st<1)||(col_st>ST))
{
printf("error! Dolzhno byt` ne men`she 1 i ne bol`she 10 strok!");
exit(-1);
}
*fli = (char*) malloc(col_st*60);
gets(fli[0]);
for (i=0; i<col_st; i++)
{
printf("vvedite %d stroku: ", i+1);
gets(fli);
}
for (i=0; i<col_st; i++) puts(fli);
}
if(ch==50)
{
f = fopen("temp.txt", "rt+");
if (f == NULL)
printf("Oshibka otkrytiya faila s kodom %d\n",errno );
printf("\nSchytivanie s faila\nSchytivaetsya maximum %d strok\n", ST);
*fli = (char*) malloc(ST*60);
for (i=0; i<ST; i++)
{
fgets(fli, 80, f);
printf("%s\n", fli);
if(feof(f)) i=ST;
col_st++;
}
}
printf("\n-----Press enter!------\n");
getch();
for(i=0;i<col_st;i++)
for(j=0;j<13;j++)
fli=modString(fli, predl[j], zamen[j]);
for (i=0; i<col_st; i++) printf("%s\n", fli);
getch();
free(fli);
}
если кому-либо будет непонятно, что делает та или иная переменная - спрашивайте))
Навскидку могу предложить задавать предлоги с пробелом:
Доведем до безумства перед смертью - на входе
Доведем !! безумств! !!!!! смертью - на выходе
минусы - в конце слова "а" посчитало предлогом;
Некоторые предлоги в начале не считывает (Например "По");
некоторые строки из файла вообще не прочитались
Помню-помню. :) Вот только вы не лучший вариант функции modString взяли - там в конце концов получился вариант, который был одобрен Kogrom'ом, лучше уж его было использовать (хотя в нем также будут описанные вами проблемы, и его вам также пришлось бы переделывать под ваши нужды)
например есть слово "проводник" и предлог "од", так вот он слово "проводник" преобразует в "пров!!ник". Нужно реализовать поиск предлогов, учитывая, что после них должен идти разделитель. Массив разделителей указан, но как реализовать - ума не приложу.
Но подскажу по тому варианту который вы взяли. Смотрим следующий фрагмент кода (немного прокомментировал):
// с которых начинаются вхождения заменяемой строки
numpos = (int*)malloc(sizeof(int) * (originalStringLength / strReplacedLength + 1));
for(i = 0; i <= originalStringLength - strReplacedLength; ++i)
{
j = 0;
// в этом цикле производится сравнение подстроки, начинающейся с позиции i, с заменяемой строкой
while(j < strReplacedLength && string[i + j] == strReplaced[j])
++j;
if(j == strReplacedLength /* текущая подстрока является заменяемой*/ )
{
// помещаем текущую позицию i в массив numpos:
numpos[posReplacingCount++] = i;
i += strReplacedLength - 1;
}
}
Здесь, в случае обнаружения что текущая строка совпадает с заменяемой, можно добавить дополнительную проверку - следует ли в исходной строке, за заменяемой подстрокой, символ-разделитель. Если да - то тогда помещаем i в массив numpos. Сделать это можно, например, с помощью функции strchr из библиотеки string, проверяя, входит ли следующий (за проверяемой подстрокой) символ в строку символов-разделителей, только тогда строку разделителей нужно задать не в виде двумерного массива, как у вас сделано, а в виде обычной строки (только терминальный символ придется исключить):
Эту строку можно передавать в функцию modString отдельным аргументом, либо задать как глобальную переменную и использовать ее внутри функции modString. И в функции modString, используя strchr, проверять символ на вхождение в эту строку разделителей, и еще наверно отдельно учесть случай, что этот символ может быть терминальным символом.
Т.е. должно получиться что-то вроде такого:
(/*здесь вызов strchr с аргументами razdel и string*/
|| string == '\0')
)
{
numpos[posReplacingCount++] = i;
i += strReplacedLength - 1;
}
В смысле - не производит замену, если некоторые буквы отличаются регистром? Ну так это понятно почему: буквы 'П' и 'п' - это разные символы, и поэтому операция сравнения string[i + j] == strReplaced[j] в цикле while дает false. Чтобы без учета регистра сравнивать - можно использовать функцию tolower из string:
++j;
если я не ошибаюсь, то ф-ция tolower объявлена не в string.h, а в ctype.h
но даже после всего вышеперечисленного программа не реагирует. Вот переделал код по Вашим рекомендациям:
#include<conio.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>
#define ST 10
char* razdel = ",. !?()\"";
char* modString(char *string, char *strReplaced, char *strReplacedBy)
{
int originalStringLength, strReplacedLength, strReplacedByLength;
int posReplacingCount, posReplacingNumber;
int i, j, k;
int *numpos;
char *result;
originalStringLength = strlen(string);
strReplacedLength = strlen(strReplaced);
strReplacedByLength = strlen(strReplacedBy);
posReplacingCount = 0;
numpos = (int*)malloc(sizeof(int) * (originalStringLength / strReplacedLength + 1));
for(i = 0; i <= originalStringLength - strReplacedLength; ++i)
{
j = 0;
while((j<strReplacedLength)&&(tolower(string[i + j])==tolower(strReplaced[j])))
++j;
if((j==strReplacedLength)&&(strchr(string,razdel))||(string=='\0'))
{
numpos[posReplacingCount++] = i;
i += strReplacedLength - 1;
}
}
if(!posReplacingCount)
{
result = (char*)malloc(sizeof(char) * (originalStringLength + 1));
strcpy(result, string);
}
else
{
result = (char*)malloc(sizeof(char) * (originalStringLength + (strReplacedByLength - strReplacedLength) * posReplacingCount + 1));
for(i = 0, j = 0, posReplacingNumber = 0; i < originalStringLength; ++i, ++j)
if(posReplacingNumber == posReplacingCount || numpos[posReplacingNumber] > i)
result[j] = string;
else
{
for(k = 0; k < strReplacedByLength; ++k, ++j)
result[j] = strReplacedBy[k];
i+= strReplacedLength - 1;
--j;
++posReplacingNumber;
}
for( ; i < originalStringLength; ++i, ++j)
result[j] = string;
result[j] = '\0';
}
free(numpos);
return result;
}
void main()
{
FILE *f;
char *fli[ST], *pch, *ptr;
char ch, *p;
char predl[13][7]={"v","k","s","a","do","po","iz","na","ot","bez","pri","pered","cherez"},
zamen[13][7]={"!","!","!","!","!!","!!","!!","!!","!!","!!!","!!!","!!!!!","!!!!!!"};
int i, col_st=0, j, k;
clrscr();
printf("vyberite metod vvoda:\n1 - s klaviatury\n2 - s faila temp.txt\n");
ch=getch();
if(ch==49)
{
printf("\nVvod s klaviatury\n");
printf("\nSkoka budet strok:");
scanf("%d", &col_st);
if((col_st<1)||(col_st>ST))
{
printf("error! Dolzhno byt` ne men`she 1 i ne bol`she 10 strok!");
exit(-1);
}
*fli = (char*) malloc(col_st*60);
gets(fli[0]);
for (i=0; i<col_st; i++)
{
printf("vvedite %d stroku: ", i+1);
gets(fli);
}
for (i=0; i<col_st; i++) puts(fli);
}
if(ch==50)
{
f = fopen("temp.txt", "rt+");
if (f == NULL)
printf("Oshibka otkrytiya faila s kodom %d\n",errno );
printf("\nSchytivanie s faila\nSchytivaetsya maximum %d strok\n", ST);
*fli = (char*) malloc(ST*60);
for (i=0; i<ST; i++)
{
fgets(fli, 80, f);
printf("%s\n", fli);
if(feof(f)) i=ST;
col_st++;
}
}
printf("\n-----Press enter!------\n");
getch();
for(i=0;i<col_st;i++)
for(j=0;j<13;j++)
fli=modString(fli, predl[j], zamen[j]);
for (i=0; i<col_st; i++) printf("%s\n", fli);
getch();
free(fli);
}
а за тег звиняйте)) немного не тот поставил и не заметил....
char strchr(const char *str, int ch);
Функция strchr() возвращает указатель на первое вхождение младшего байта параметра ch в строку str. Если указанный символ не найден, возвращается нулевой указатель.
или мне кажеться, или программа все-таки стравнивает текущий символ?:confused:
Да, это я ошибся уже - невнимательно посмотрел в справочнике, думал что все символьные / строковые функции из C находятся в string.h. На самом деле верно вы говорите - библиотека ctype.h.
Ошибки в этом фрагменте (частично по моей немного неверной подсказке, частично - ваши):
{
numpos[posReplacingCount++] = i;
i += strReplacedLength - 1;
}
Тут во-первых - я вам неправильно сказал: вызывать strchr и сравнивать с '\0' нужно не для string, а string[i + j]. Во-вторых, вы неправильно задали список аргументов strchr - посмотрите как вы ее сейчас вызываете (выделил красным).
В правильном варианте должно быть как-то так:
{
numpos[posReplacingCount++] = i;
i += strReplacedLength - 1;
}
Вызываем текст из файла. В файле следующее:
A bez deneg - nikuda
Dovedem do bezumstva pered smehom
Dostanem iz ada cherez vremya
Priletim na parashute
Po nevedomym tropinkam
После работы программы получаем следующее:
[COLOR="Red"]!! nevedomym tropinkam[/COLOR]
Dovedem !! bezumstv[COLOR="Red"]![/COLOR] !!!!! smehom
[COLOR="#ff0000"]m !! bezumst!! !!!!! smehom[/COLOR]
Priletim n[COLOR="#ff0000"]![/COLOR] parashute
!! nevedomym tropinkam
крастным выделил там, где такого быть не должно...
вот что должно быть на выходе:
A !!! deneg - nikuda
Dovedem !! bezumstva !!!!! smehom
Dostanem !! ada !!!!!! vremya
Priletim !! parashute
!! nevedomym tropinkam
char strchr(const char *str, int ch);
Функция strchr() возвращает указатель на первое вхождение младшего байта параметра ch в строку str. Если указанный символ не найден, возвращается нулевой указатель.
Что за ошибка-то? Ошибка компиляции? По идее символ, являющийся переменной char, должен автоматически преобразоваться из char в int, при вызове функции... Но если автоматического преобразования не происходит - то тогда можно попробовать вместо string[i + j] поставить (int)string[i + j].
Хотя может быть ошибка у вас из-за того что вы неправильно вызов функции написали (со скобками напутали).
Да, сравнивался текущий - см. мой пост выше.
Вызываем текст из файла. В файле следующее:
После работы программы получаем следующее:
крастным выделил там, где такого быть не должно...
А, да... Надо сравнивать на вхождение в строку разделителей не только символ string[i + j], следующий за проверяемой подстрокой, но и символ, предшествующий подстроке - символ string[i - 1]. Как это сделать - уж это я думаю теперь догадаетесь сами :) (через ту же strchr). Только учесть надо отдельно случай, когда i = 0.
Po nevedomym tropinkam
Dovedem !! bezumstva !!!!! smehom
m !! bezumstva !!!!! smehom
Priletim !! parashute
Po nevedomym tropinkam
не только. На проверку любого из списка разделителей + ко всему строки должны оставаться такими же, только предлоги дожны быть заменены, а, как видите - вторая, да и не только, строка заменяется другой (либо частью другой) строкой.
это понял, но вот отдельный случай для нуля немного не дошло....
вот кусочек кода:
{
if(i>0)
{
if(strchr(razdel,string[i-1]))
{
numpos[posReplacingCount++] = i;
i += strReplacedLength - 1;
}
}
numpos[posReplacingCount++] = i;
i += strReplacedLength - 1;
}
ведь если i=0, то нет необходимости сравнивать предыдущий элемент
// ...
if(ch==50)
{
f = fopen("temp.txt", "rt+");
if (f == NULL)
printf("Oshibka otkrytiya faila s kodom %d\n",errno );
printf("\nSchytivanie s faila\nSchytivaetsya maximum %d strok\n", ST);
*fli = (char*) malloc(ST*60); // думаю что нужно это удалить
for (i=0; i<ST; i++)
{
// а здесь под отдельную строку выделить память:
fli = (char*)malloc(60 * sizeof(char));
fgets(fli, 80, f);
printf("%s\n", fli);
if(feof(f)) i=ST;
col_st++;
}
}
Ну и еще в циклах, где производится вызов modString, я так бы подправил (объявив в начале функции вспомогательную переменную char *tmp):
for(j=0;j<13;j++)
{
tmp = modString(fli, predl[j], zamen[j]);
free(fli);
fli = tmp;
}
Хотя как-то не очень мне нравится - для каждой замены выделять / освобождать память...
Но всеже, теперь появились другие баги
[COLOR="Red"]! !!!!!!neg - nikuda[/COLOR]
[COLOR="Red"]Dovedem !!!!ezumstv! !!!!!!!!!!om[/COLOR]
[COLOR="#ff0000"]Dostanem !!!!d! !!!!!!!!!!!!a[/COLOR]
Priletim n[COLOR="#ff0000"]![/COLOR] parashute
!! nevedomym tropinkam
"v " заменило на "!!". Должно на "! "
также крастным выделил проблемы...
#include<conio.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>
#define ST 10
const char *razdel=",. !?()\"";
char* modString(char *string, char *strReplaced, char *strReplacedBy)
{
int originalStringLength, strReplacedLength, strReplacedByLength;
int posReplacingCount, posReplacingNumber;
int i, j, k;
int *numpos;
char *result;
originalStringLength = strlen(string);
strReplacedLength = strlen(strReplaced);
strReplacedByLength = strlen(strReplacedBy);
posReplacingCount = 0;
numpos = (int*)malloc(sizeof(int) * (originalStringLength / strReplacedLength + 1));
for(i = 0; i <= originalStringLength - strReplacedLength; ++i)
{
j = 0;
while((j<strReplacedLength)&&(tolower(string[i + j])==tolower(strReplaced[j])))
++j;
if((j==strReplacedLength)&&((strchr(razdel,string[i+j])||(string == '\0'))))
{
if(i>0)
{
if(strchr(razdel,string[i-1]))
{
numpos[posReplacingCount++] = i;
i += strReplacedLength - 1;
}
}
numpos[posReplacingCount++] = i;
i += strReplacedLength - 1;
}
}
if(!posReplacingCount)
{
result = (char*)malloc(sizeof(char) * (originalStringLength + 1));
strcpy(result, string);
}
else
{
result = (char*)malloc(sizeof(char) * (originalStringLength + (strReplacedByLength - strReplacedLength) * posReplacingCount + 1));
for(i = 0, j = 0, posReplacingNumber = 0; i < originalStringLength; ++i, ++j)
if(posReplacingNumber == posReplacingCount || numpos[posReplacingNumber] > i)
result[j] = string;
else
{
for(k = 0; k < strReplacedByLength; ++k, ++j)
result[j] = strReplacedBy[k];
i+= strReplacedLength - 1;
--j;
++posReplacingNumber;
}
for( ; i < originalStringLength; ++i, ++j)
result[j] = string;
result[j] = '\0';
}
free(numpos);
return result;
}
void main()
{
FILE *f;
char *fli[ST], *tmp;
char ch, *p;
char predl[13][7]={"v","k","s","a","do","po","iz","na","ot","bez","pri","pered","cherez"},
zamen[13][7]={"!","!","!","!","!!","!!","!!","!!","!!","!!!","!!!","!!!!!","!!!!!!"};
int i, col_st=0, j, k;
clrscr();
printf("vyberite metod vvoda:\n1 - s klaviatury\n2 - s faila temp.txt\n");
ch=getch();
if(ch==49)
{
printf("\nVvod s klaviatury\n");
printf("\nSkoka budet strok:");
scanf("%d", &col_st);
if((col_st<1)||(col_st>ST))
{
printf("error! Dolzhno byt` ne men`she 1 i ne bol`she 10 strok!");
exit(-1);
}
*fli = (char*) malloc(col_st*60);
gets(fli[0]);
for (i=0; i<col_st; i++)
{
printf("vvedite %d stroku: ", i+1);
gets(fli);
}
for (i=0; i<col_st; i++) puts(fli);
}
if(ch==50)
{
f = fopen("temp.txt", "rt+");
if (f == NULL)
printf("Oshibka otkrytiya faila s kodom %d\n",errno );
printf("\nSchytivanie s faila\nSchytivaetsya maximum %d strok\n", ST);
for (i=0; i<ST; i++)
{
fli = (char*)malloc(60 * sizeof(char));
fgets(fli, 80, f);
printf("%s\n", fli);
if(feof(f)) i=ST;
col_st++;
}
}
printf("\n-----Press enter!------\n");
getch();
for(i=0;i<col_st;i++)
for(j=0;j<13;j++)
{
tmp = modString(fli, predl[j], zamen[j]);
free(fli);
fli = tmp;
}
for (i=0; i<col_st; i++) printf("%s\n", fli);
getch();
free(fli);
}
вот кусочек кода:
{
if(i>0)
{
if(strchr(razdel,string[i-1]))
{
numpos[posReplacingCount++] = i;
i += strReplacedLength - 1;
}
}
numpos[posReplacingCount++] = i;
i += strReplacedLength - 1;
}
ведь если i=0, то нет необходимости сравнивать предыдущий элемент
Здесь можно все проверки в одном условии сделать:
&& (string[i+j] == '\0' || strchr(razdel,string[i+j]))
&& (i == 0 || strchr(razdel,string[i-1])))
{
numpos[posReplacingCount++] = i;
i += strReplacedLength - 1;
}
#include<conio.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>
#define ST 10
const char *razdel=",. !?()\"";
char* modString(char *string, char *strReplaced, char *strReplacedBy)
{
int originalStringLength, strReplacedLength, strReplacedByLength;
int posReplacingCount, posReplacingNumber;
int i, j, k;
int *numpos;
char *result;
originalStringLength = strlen(string);
strReplacedLength = strlen(strReplaced);
strReplacedByLength = strlen(strReplacedBy);
posReplacingCount = 0;
numpos = (int*)malloc(sizeof(int) * (originalStringLength / strReplacedLength + 1));
for(i = 0; i <= originalStringLength - strReplacedLength; ++i)
{
j = 0;
while((j<strReplacedLength)&&(tolower(string[i + j])==tolower(strReplaced[j])))
++j;
if((j==strReplacedLength)
&&((string[i+j]=='\0')||(strchr(razdel,string[i+j])))
&&((i==0)||(strchr(razdel,string[i-1]))))
{
numpos[posReplacingCount++] = i;
i += strReplacedLength - 1;
}
}
if(!posReplacingCount)
{
result = (char*)malloc(sizeof(char) * (originalStringLength + 1));
strcpy(result, string);
}
else
{
result = (char*)malloc(sizeof(char) * (originalStringLength + (strReplacedByLength - strReplacedLength) * posReplacingCount + 1));
for(i = 0, j = 0, posReplacingNumber = 0; i < originalStringLength; ++i, ++j)
if(posReplacingNumber == posReplacingCount || numpos[posReplacingNumber] > i)
result[j] = string;
else
{
for(k = 0; k < strReplacedByLength; ++k, ++j)
result[j] = strReplacedBy[k];
i+= strReplacedLength - 1;
--j;
++posReplacingNumber;
}
for( ; i < originalStringLength; ++i, ++j)
result[j] = string;
result[j] = '\0';
}
free(numpos);
return result;
}
void main()
{
FILE *f;
char *fli[ST], *tmp;
char ch, *p;
char predl[13][7]={"v","k","s","a","do","po","iz","na","ot","bez","pri","pered","cherez"},
zamen[13][7]={"!","!","!","!","!!","!!","!!","!!","!!","!!!","!!!","!!!!!","!!!!!!"};
int i, col_st=0, j, k;
clrscr();
printf("vyberite metod vvoda:\n1 - s klaviatury\n2 - s faila temp.txt\n");
ch=getch();
if(ch==49)
{
printf("\nVvod s klaviatury\n");
printf("\nSkoka budet strok:");
scanf("%d", &col_st);
if((col_st<1)||(col_st>ST))
{
printf("error! Dolzhno byt` ne men`she 1 i ne bol`she 10 strok!");
exit(-1);
}
*fli = (char*) malloc(col_st*60);
gets(fli[0]);
for (i=0; i<col_st; i++)
{
printf("vvedite %d stroku: ", i+1);
gets(fli);
}
for (i=0; i<col_st; i++) puts(fli);
}
if(ch==50)
{
f = fopen("temp.txt", "r+");
if (f == NULL)
printf("Oshibka otkrytiya faila s kodom %d\n",errno );
printf("\nSchytivanie s faila\nSchytivaetsya maximum %d strok\n", ST);
for (i=0; i<ST; i++)
{
fli = (char*)malloc(60 * sizeof(char));
fgets(fli, 80, f);
printf("%s\n", fli);
if(feof(f)) i=ST;
col_st++;
}
}
printf("\n-----Press enter!------\n");
getch();
for(i=0;i<col_st;i++)
for(j=0;j<13;j++)
{
tmp = modString(fli, predl[j], zamen[j]);
free(fli);
fli = tmp;
}
for (i=0; i<col_st; i++) printf("%s\n", fli);
printf("\nDopisat` text v fail?(y/n)\n");
ch=getch();
if((ch==121)||(ch==13))
{
for(i=0; i<col_st;i++)
fputs(fli, f);
}
printf("Gotovo!");
getch();
free(fli);
if (fclose(f) < 0)
{
perror("\nError to close file!!!");
}
}
модераторы, пожалуйста, не удаляйте этот пост с благодарностью, ибо в нем заключен последний рабочий вариант программы