Помощь - Поиск - Пользователи - Календарь
Полная версия: Удалить из текста символ!
Форум «Всё о Паскале» > Современный Паскаль и другие языки > Ада и другие языки
Child of Bodom
Люди помогите плиз срочно. скоро сессия а немогу прогу сделать чтоб работала.
вообщем суть такова: надо считать файл, и если в нем попадается заданный символ, удалить его, но потом надо будет вернуть обратно. например, удалим пробелы из строки файла:

__ABC_____FDC__
чтобы допустим получилось
2,3ABC5,3FDC2,0

Получается что цифра перед запятой - это количество пробелов или последовательно идущих символа, а после запятой - через сколько символов опять будет пробел. Причем сделать мне это надо именно так (препод так сказал)

Язык программирования С++ Builder но тут вроде нету неизвестных функций
вот что получилось

void __fastcall TForm1::delClick(TObject *Sender)
{
char p[255];
sym=Edit->Text;
output=fopen ("WWW.txt","w");
u=0;
g=sym[1]; - это символ который надо удалить
i=0;
c=',';
while (!feof(input)) пока не конец файла
{
if (feof(input)) break;

fgets (p,255,input); считываем строку
for (i=1;i<strlen(p);i++) пока не конец строки
{
u=0; nu=0; u- количество подряд идущих пробелов например; nu-через сколько символов опять будет пробел
if (p[i]==g) {
k=i;
while (p[i]==g){ считаем кол-во повторов символа
u++;
i++;
}
while (p[i]!=g){ считаем через сколько опять пробел будет
i++;
nu++; }
s=IntToStr(u);
r=s[1];
fwrite (&r,sizeof(char),1,output);
fwrite (&c,sizeof(char),1,output);
s=IntToStr(nu);
r=s[1];
fwrite (&r,sizeof(char),1,output);}
else
{
while (p[k]==g)
k++;
fwrite (&p[k],sizeof(char),1,output);}

}

}
fclose (input);
fclose (output);
Mem->Clear();
output=fopen ("WWW.txt","r");
Mem->Lines->LoadFromFile("WWW.txt");
}
Lapp
М
Почему в паскалевском разделе?.. Переношу в С.

volvo
Child of Bodom, так что-ли:

#include <fstream.h>
...
void __fastcall TForm1::Button1Click(TObject *Sender)
{
const int max_size = 256;
char buffer[max_size];

ifstream in_file("G:\\www.txt", ios::in);
ofstream out_file("G:\\www2.txt", ios::out);

char to_delete = ' ';
int count = 0;
while(!in_file.eof()) {
in_file.getline(buffer, max_size);

AnsiString result = "";
for(char *p = buffer; *p; p++) {
while(*p != to_delete) p++;

while(*p == to_delete) {
count += 1;
p++;
}
AnsiString after = "";
for(; *p && *p != to_delete; *p++) {
after += *p;
}
result +=
IntToStr(count) + "," + IntToStr(after.Length()) + after;
count = 1;
}
out_file << result.c_str() << endl;
}
out_file.close();
in_file.close();

Memo1->Lines->LoadFromFile("G:\\www2.txt");

}


?
Child of Bodom
Цитата(volvo @ 18.12.2007 16:35) *

Child of Bodom, так что-ли:

#include <fstream.h>
...
void __fastcall TForm1::Button1Click(TObject *Sender)
{
const int max_size = 256;
char buffer[max_size];

ifstream in_file("G:\\www.txt", ios::in);
ofstream out_file("G:\\www2.txt", ios::out);

char to_delete = ' ';
int count = 0;
while(!in_file.eof()) {
in_file.getline(buffer, max_size);

AnsiString result = "";
for(char *p = buffer; *p; p++) {
while(*p != to_delete) p++;

while(*p == to_delete) {
count += 1;
p++; // вот тут че то не понятно
}
AnsiString after = "";
for(; *p && *p != to_delete; *p++) { // и вот это
after += *p;
}
result +=
IntToStr(count) + "," + IntToStr(after.Length()) + after;
count = 1;
}
out_file << result.c_str() << endl;
}
out_file.close();
in_file.close();

Memo1->Lines->LoadFromFile("G:\\www2.txt");

}


?




немного не понимаю в тех местах. Да и вроде все то, вроде так понятно. я так почти и делал(я эту лабу переделываю 10 раз наверно). Короче у меня часто возникает проблемы с этими char , *char, char [] вот и получается что допустим в новый файл с цифрами записывалось нормально(как то получилось один раз), но когда обратно восстанавливать по этим цифрам заданный символ наступают проблемы с этими чарами . Допустим я создал множество из цифр и типа считывается посимвольно и типа если входит в множество тогда их там преобразовываю считываю, но получается что никогда не совпадает, то есть никогда во множество то не входят цифры. Вот с этим в основном проблемы.
А это вообще C++ Builder 6 или 2007 ?

volvo
Цитата
А это вообще C++ Builder 6 или 2007 ?

А тут не используется ничего такого, что изменилось бы, начиная с 6 версии. Я бы сказал, никаких специальных "примочек" Билдера тут вообще не используется. За исключением AnsiString и IntToStr все остальное - стандартные средства С++...

Теперь о том, что тебе не было понятно. Смотри:

// пробегаем по всей строке buffer, используя указатель на строку
for(char *p = buffer; *p; p++) {

// Сначала - пропускаем все символы, которые НЕ являются удаляемыми (т.е., пока
// очередной символ не является удаляемым, увеличиваем p, что означает переход
// к следующему символу строки buffer). По окончании этого цикла while переменная
// p будет указывать на первый удаляемый символ.
while(*p != to_delete) p++;

// Теперь надо посчитать, сколько удаляемых символов идут подряд
// Опять же увеличиваем указатель, пока текущий символ равен to_delete
// одновременно с этим, кстати, еще и увеличиваем счетчик (count)
while(*p == to_delete) {
count += 1;
p++; // что тут тебе было не понятно - я не знаю, это и есть переход на следующий символ строки
}

// В этой строке будут храниться все символы, следующие ПОСЛЕ удаляемых,
// для того чтобы вычислить расстояние до следующей группы пробелов (ну, или чего там у тебя)
AnsiString after = "";

// Здесь - использование преимуществ цикла for
// ОБЫЧНО в цикле for указываются начальные значения переменных ";" условие продолжения
// цикла ";" и оператор, выполняемый при переходе на следующую итерацию...
// У меня нет первого парамента, то есть, начальное значение p я не задаю, его значение останется
// таким же, каким и было при выходе из предыдущего цикла while...

// А вот продолжаться этот for будет, пока не будет достигнут конец строки
// (*p равносильно *p != 0, то есть, как только *p станет равным 0 - конец строки - цикл прервется)
// и очередной символ не будет являться пробелом (как только дойдем до следующего пробела -
// цикл тоже прервется)
for(; *p && *p != to_delete; *p++) {
// Что же делаем в цикле?
// Очень просто: добавляем очередной просмотренный символ в строку
after += *p;
}

// Ну, и собираем изо всех элементов результат, который нужен: счетчик пробелов, запятая,
// сколько символов будет до следующего пробела и сама строка до следующего пробела
result +=
IntToStr(count) + "," + IntToStr(after.Length()) + after;

// Не забываем сбросить счетчик, чтобы при следующем подсчете пробелов он считал правильно
count = 1;
}


А вообще-то тебе надо разобраться с указателями (это вообще рабочий инструмент в С++, без понимания, как они работают, тебе будет очень сложно что-то написать) и со строками.
Child of Bodom
Цитата(volvo @ 18.12.2007 21:34) *


А вообще-то тебе надо разобраться с указателями (это вообще рабочий инструмент в С++, без понимания, как они работают, тебе будет очень сложно что-то написать) и со строками.


Круто. Вроде все теперь понял. Спасибо. Да на лекциях про указателя я наверно спал просто или в дурака играл. не помню.

Это седня попробую. А вот теперь при нажатии на вторую кнопку. надо все это вернуть из второго файла(т.е заданный символ в те места где он стоял) вот и там вот делать так чтоб допустим если цифра встречается сравнивать ее с множеством чисел если совпадает, то и т.д. .... Так наверно сделать??
volvo
Восстановление исходной строки я бы делал так:

void __fastcall TForm1::Button2Click(TObject *Sender)
{
const int max_size = 256;
char buffer[max_size];

int count = 0, after = 0;

ifstream infile("G:\\www2.txt", ios::in); // Это - "закодированный" файл
ofstream out_file("G:\\www3.txt", ios::out); // Сюда будет помещен результат...
char char_to_insert = ' ';

while(!infile.eof()) {
AnsiString result = "";
infile.getline(buffer, max_size);

char *p = buffer;
for(; *p; p++) {
if((sscanf(p, "%d,%d", &count, &after))) {
for(int i = 0; i < count; i++) {
result += char_to_insert;
}
p += (IntToStr(count) + "," + IntToStr(after)).Length() - 1;
}
else result += *p;
}
out_file << result.c_str() << endl;
}
out_file.close();
infile.close();

Memo1->Lines->LoadFromFile("G:\\www3.txt");
}

О том, что именно здесь делает sscanf - читай здесь, я уже объяснял как подобный фрагмент работает:
Задача по строкам
Child of Bodom
А вот еще у меня вопросик. Можно ли по этой технологии считывать не только текстовый файл но и .dat .dll ну или просто не только текстовый файл???
volvo
В принципе, если ты знаешь формат файла, который читаешь - то достаточно просто открыть файл как бинарный:
ifstream infile("myfile.dat", ios::in|ios::binary);
и работать с ним.
Child of Bodom
void __fastcall TForm1::delClick(TObject *Sender)
{
const int max_size = 256;
char buffer[max_size];

input=fopen (vibor->FileName.c_str(),"r"); // тут из диалогового окна
output=fopen ("WWW.txt", "w");
sym=Edit->Text;
char to_delete = sym[1];
int count = 0;
while(!feof(input)) {
fgets (buffer,max_size,input);
AnsiString result = "";
for(char *p = buffer; *p; p++) {
while(*p != to_delete) p++;

while(*p == to_delete) {
count += 1;
p++;
}
AnsiString after = "";
for(; *p && *p != to_delete; *p++) {
after += *p;
}
result +=
IntToStr(count) + "," + IntToStr(after.Length()) + after;
count = 1;
}
out_file << result.c_str() << endl; // вот а как тут мне заменить тогда
}
fclose(input);
fclose(output);
Mem->Lines->LoadFromFile("WWW.txt");

}





А можешь сказать как там будет и ваще правильно ли будет так как я переделал, а то препод не поверит мне что я такой умный типа. Честно говоря мне си ваще не прет, вот паскаль это круто smile.gif) поэтому ваще вот помощи прошу
volvo
Вот так там будет:
void __fastcall TForm1::Button6Click(TObject *Sender)
{

const int max_size = 256;
char buffer[max_size];

if(!vibor->Execute()) return; // У тебя в коде не запускается OpenDialog

FILE *input = fopen (vibor->FileName.c_str(),"rt"); // Открываем ТЕКСТОВЫЙ файл = "rt"
FILE *output = fopen ("WWW.txt", "wt"); // и здесь тоже текстовый
AnsiString sym = Edit->Text;
char to_delete = sym[1];
int count = 0;
while(!feof(input)) {
buffer[0] = '\0'; // Буфер надо сбрасывать
fgets(buffer,max_size,input);
AnsiString result = "";
for(char *p = buffer; *p; p++) {
while(*p != to_delete) p++;

while(*p == to_delete) {
count += 1;
p++;
}
AnsiString after = "";
for(; *p && *p != to_delete; *p++) {
after += *p;
}
result +=
IntToStr(count) + "," + IntToStr(after.Length()) + after;
count = 1;
}
fprintf(output, "%s\n", result.c_str()); // Вывод в файл
}
fclose(input);
fclose(output);
Mem->Lines->LoadFromFile("WWW.txt");

}

P.S. Не имей привычки часто пользоваться глобальными переменными (или слишком много ненужного запихивать в класс) - это может тебе навредить...
Child of Bodom
Так вывод я попробую по аналогии сделать. Спасибо большое за помощь, за советы.Попробую следовать им. Ща попробую все это скомпилить. Прикольно будет если получитсья
Child of Bodom
Слушай че то не то получается. Например, пишу удалить пробел а он еще часть текста удаляет:
Исходный файл:

Превед я тупой робот пните меня чтоб я начал работать

Полученный файл:

1,1я2,5робот2,4меня2,1я2,8работать
volvo
		for(char *p = buffer; *p; p++) {
// while(*p != to_delete) p++; // Эту строку можешь удалить...

while(*p == to_delete) {
count += 1;
p++;
}
У меня на твоем примере отработало...
Child of Bodom
оооо круто работает!!!! Спасибо smile.gif))
ура ща буду смотреть кнопку возвращения обратно текста этого smile.gif)
Child of Bodom
ой я скоро покончу с собой:(( препод начал проверять: открыл текстовый файл, одну строку нормально проработало. он говорит а че ты мне тока одну , давай я напишу текст и посмотрим как будет удаляться. ну вот он написал :

    на поле танки грохотали_                       //    _ это пробел поставил чтоб видно было
солдаты шли в последний бой_
а молодого китайца_
несли с пробитой головой_


Вот а после кодирования вот что получилось:

7,2на1,4поле1,5танки1,9грохотали1,1
1,2х1,3Х‰1,3Х‰1,3¤G’1,1„
4,7солдаты1,3шли1,1в1,9последний3,3бой1,1

3,1а1,8молодого1,7китайца1,1
1,3ний3,3бой1,1

7,5несли1,1с1,8пробитой1,7головой


я понимаю что уже достал вас но мне ее надо последний срок в понедельник, а я ваще не чаю что уж теперь сделать. Помогите прошу!!!
volvo
А теперь расскажи, что ИМЕННО ты вводишь? У тебя в конце каждой строки что расположено? Перевод строки? Что же ты хотел? Я тебе для чего в самом начале говорил делать это через поток ifstream + метод getline? Потому что этот метод читает всю строку, не включая символ перевода строки. Ты переделал по-своему, теперь ищи в buffer-е после прочтения символ '\n' и выкидывай его из буфера (т.е., заменяй символом '\0'). Тогда получишь в результате обработки файла

    na pole tanki grohotali_
soldaty shli v posledniy boy_
a molodogo komandira_
nesli s probitoi golovoy_
вот такой результат в Memo:
4,2na1,4pole1,5tanki1,9grohotali
4,7soldaty1,4shli1,1v1,9posledniy3,3boy
3,1a1,8molodogo1,9komandira
7,5nesli1,1s1,8probitoi1,7golovoy
(пробелы в конце строки будут тоже выброшены из рассмотрения, при обратной конвертации надо будет добавить в конец строки еще один пробел) или переписывай алгоритм с нуля... Я больше с FILE* (при использовании C++ Builder-а) извращаться не буду. В С++ есть гораздо более подходящие для этого средства...


Добавлено через 19 мин.
Хотя, если я правильно понимаю, что именно должно получиться, попробуй вот это:
void __fastcall TForm1::Button6Click(TObject *Sender)
{
const int max_size = 256;
char buffer[max_size];

if(!vibor->Execute()) return;
FILE *input = fopen (vibor->FileName.c_str(),"rt");
FILE *output = fopen ("G:\\WWW4.txt", "wt");
AnsiString sym = Edit->Text;
char to_delete = sym[1];
int count;
while(!feof(input)) {
buffer[0] = '\0';
fgets(buffer,max_size,input);

AnsiString result = "";
for(char *p = buffer; (*p) && (*p != '\n'); p++) {
count = 0;

while(*p == to_delete) {
count += 1;
p++;
}
AnsiString after = "";
for(; *p && *p != '\n' && *p != to_delete; *p++) {
after += *p;
}
p -= 1;
result +=
IntToStr(count) + "," + IntToStr(after.Length()) + after;
}
fprintf(output, "%s\n", result.c_str());
}
fclose(input);
fclose(output);
Mem->Lines->LoadFromFile("G:\\WWW4.txt");

}

Child of Bodom
Спасибо большое еще раз. Вроде пашет.ну при определенных параметрах. может прокатит
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.