| 
			| 
					
						| sd 
								Постоялец    Offline | 
								|  | «  : 26-10-2011 16:25 »  |  | 
 
 Всем привет. Задание такое: создать программу обработки учебника по программированию с использованием классов: символ, слово, предложение и т.п. Заменить табуляции и последовательности пробелов одним пробелом. То есть, у меня есть файл с текстом (см. в аттаче). Необходимо прочитать текст из этого файла и обработать его. Я написал класс слово (Word.h): class Word {char *wrd;
 int len;
 
 void SetWord(char *word);
 public:
 Word(void): wrd(0), len(0) {}
 Word(char *word);
 Word(const Word &obj);
 ~Word(void);
 
 int GetLen(void) const {return len;}
 int CharCount(char ch) const;
 char GetFirstSymbol(void) const {return *wrd;}
 void GetWord(char *string, int begindx, int endindx);
 
 friend ostream &operator<<(ostream &stream, Word &obj);
 friend istream &operator>>(istream &stream, Word &obj);
 Word operator=(const Word &obj);
 Word operator=(char *word);
 };
 
и класс предложение, являющееся массивом слов и завершающееся одним из "завершителей" (!, ., ?). Sentence.h class Sentence {int len;
 int size;
 Word *wrds;
 char *sntnce;
 
 void SetSentence(char *sentence);
 bool IsSeparator(char symbol);
 void GetWords(void);
 void DelRepeatSpaces(char *sentence);
 public:
 Sentence(void): len(0), size(0), wrds(0) {}
 Sentence(char *sentence);
 Sentence(const Sentence &obj);
 ~Sentence(void);
 
 int GetWordsCount(void);
 int GetLen(void) const {return strlen(sntnce);}
 
 friend ostream &operator<<(ostream &stream, Sentence &obj);
 friend istream &operator>>(istream &stream, Sentence &obj);
 Sentence operator=(const Sentence &obj);
 Sentence operator=(char *sentence);
 };
 
А вот что делать дальше - я не придумал. Надо создать класс текст, который будет массивом предложений. Проблема в том, что бы считать из файла количество предложений, выделить необходимую память для всех предложений и записать в каждый из элементов массива предложений эти предложения. Плюс ко всему надо сохранить пунктуацию, т.е. обзацы. Подскажите пожалуйста, как реализовать класс текст. |  
						| 
								| 
 
										 c++.txt  (1.7 Кб - загружено 1076 раз.)
									 |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| DneprSMV | 
								|  | « Ответ #1 : 26-10-2011 17:24 »  |  | 
 
 а почему ты не используешь хотябы CString, CStringArray или подобное - там хотябы задача прибивания пробелов или других повторов решается одним вызовом. Массивы, списки ?  |  
						| 
								|  |  
								|  |  Записан | 
 
 "Не слушайте никаких советов, в том числе и этот" (Сократ ?) |  |  | 
	| 
			| 
					
						| sd 
								Постоялец    Offline | 
								|  | « Ответ #2 : 26-10-2011 17:26 »  |  | 
 
 а почему ты не используешь хотябы CString, CStringArray или подобное - там хотябы задача прибивания пробелов или других повторов решается одним вызовом. Массивы, списки ? 
 Да вопрос не в том, что бы использовать имеющиеся классы типа CString. Меня и мой класс с моими функциями устраивает. Тут вопрос в том, как все это прочитать из файла и загрузить в массив предложений. |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| DneprSMV | 
								|  | « Ответ #3 : 26-10-2011 17:44 »  |  | 
 
 так в чем проблема, если разбирать файл "с лету" - fgetc(),если через буфер (считать весь файл в память, затем разбор) - fgets()  ?
 Или ты имеешь ввиду выделение из потока ?
 
 ps  (?)
 редактор:абзац   : предложение: слово
 :формат  : разметка  . . . .
 :разметка . . . .
 
 
 |  
						| 
								|  |  
								| « Последнее редактирование: 26-10-2011 17:51 от DneprSMV » |  Записан | 
 
 "Не слушайте никаких советов, в том числе и этот" (Сократ ?) |  |  | 
	| 
			| 
					
						| sd 
								Постоялец    Offline | 
								|  | « Ответ #4 : 26-10-2011 17:49 »  |  | 
 
 Проблема в том, что размер файла я заранее не знаю. И не знаю, какую память выделять под буфер. Потом, в буфер считается часть файла до перехода на новую строку, т.е. 1 обзац. |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| DneprSMV | 
								|  | « Ответ #5 : 26-10-2011 17:52 »  |  | 
 
 это учебная задача или реально, где неизвестно какой будет файл - 1 к или 1 гиг ?Добавлено через 23 минуты и 57 секунд: Проблема в том, что размер файла я заранее не знаю. И не знаю, какую память выделять под буфер. Потом, в буфер считается часть файла до перехода на новую строку, т.е. 1 обзац.
 Смотря как будешь считывать и из какого файла. Если обычный текстовый - у тебя считвывается не "абзац" а текстовая строка, и не обязательно это предложение. Сторка - завершается символами 0x0D 0x0A (или просто 0x0A). Если такой формат - используй fgets()-fgetc()   char str1[500]; while( !feof(fd) ) int rc = fgets(str1,500, fd ); Если формат который оперирует абзацами, разметкой итд - напр. RTF - то самому писать будет тяжко и бессмысленно. ------------ в твоем файле в строке (в смысле ограничения 0D-0A) записан абзац. За одно fgets считывание в буфере - соответственно абзац. Длину строки-абзаца принимай из более-менее разумной - например до нескольких кб. Хотя можно узнать хар-ки файла - длину, выделить память по длине, и считать файл в двоичном режиме. Далее все операции - с памятью. Можно считать-обработать и в режиме фильтра, но это сложнее. |  
						| 
								|  |  
								| « Последнее редактирование: 26-10-2011 18:16 от DneprSMV » |  Записан | 
 
 "Не слушайте никаких советов, в том числе и этот" (Сократ ?) |  |  | 
	| 
			| 
					
						| sd 
								Постоялец    Offline | 
								|  | « Ответ #6 : 26-10-2011 18:31 »  |  | 
 
 Задача учебная. Файл я прикрепил в первом сообщении, он обычный текстовый.
 Т.е., после
 char str1[500];
 while( !feof(fd) )  {
 int rc = fgets(str1,500, fd );
 GetSentencesFrom(str1);
 }
 в переменой str1 я получу абзац? и потом смогу разбить его на предложения. И таким образом считаю все абзацы и разделю их на предложения?
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| RuNTiME | 
								|  | « Ответ #7 : 26-10-2011 18:48 »  |  | 
 
 sd, если задача учебная и нет особых претензий к производительности и эффективности программы, то можно использовать функцию realloc(), которая динамически изменяет размер заранее выделенного блока памяти функцией malloc() и возвращает указатель на новый блок. Т.е. общая стратегия получается таковой (цифры могут быть и другими): 1. Если есть еще строки, выделяем блок памяти под новую строку размером 512 байт 2. Считываем из файла строку в этот буфер, если конец строки не найден, а буфер закончился увеличиваем блок памяти функцией realloc() еще на 512 байт и продолжаем считывать строку до тех пор, пока не найдем конец строки. 3. Нашли конец строки, идем в п.1 Таким образом можно считать весь файл, что каждая строка будет храниться в отдельном блоке памяти. Ну либо использовать готовый класс, как писал DneprSMV . В них уже реализован подобный алгоритм. Да и чтобы не привязывать свою программу к MFC и другим библиотекам реализующим CString посоветую использовать классы из STL к примеру std::string. P.S: Информация по функциям выделения и освобождения памяти: http://www.cplusplus.com/reference/clibrary/cstdlib/malloc/ |  
						| 
								|  |  
								| « Последнее редактирование: 26-10-2011 18:54 от RuNTiME » |  Записан | 
 
 Любимая игрушка - debugger ... |  |  | 
	| 
			| 
					
						| DneprSMV | 
								|  | « Ответ #8 : 26-10-2011 19:23 »  |  | 
 
 sd,  Задача учебная. Файл я прикрепил в первом сообщении, он обычный текстовый.
 Т.е., после
 char str1[500];
 while( !feof(fd) )  {
 int rc = fgets(str1,500, fd );
 GetSentencesFrom(str1);
 }
 в переменой str1 я получу абзац? и потом смогу разбить его на предложения. И таким образом считаю все абзацы и разделю их на предложения?
 
 Да, помоему этого достаточно (не буквально - надо пару операторов дописать - работа с файлом).  Возьми хелповский пример по fgets. осле fgets() в буфере получаешь считанную строку (в содержательном смысле - это абзац из документа). он заканчивается символом 0x00.RuNTiME ,  Во входном файле могут быть строки произвольной длины - как раз бы прошло CString - чтобы не отвлекаться на обработку-укладку строк наразвес. Достаточно один раз выделить буфер достаточного размера, и использовать его повторно в цикле, а уже разобранную из него информацию упаковывать в классовую модель со списками-массивами, выделением памяти.  За STL - да. |  
						| 
								|  |  
								|  |  Записан | 
 
 "Не слушайте никаких советов, в том числе и этот" (Сократ ?) |  |  | 
	| 
			| 
					
						| RuNTiME | 
								|  | « Ответ #9 : 26-10-2011 19:33 »  |  | 
 
 Достаточно один раз выделить буфер достаточного размера, и использовать его повторно в циклеDneprSMV , Безусловно можно, я всего лишь предложил самый наипростейший вариант. Повторно использовать память можно и нужно. Если говорить о парсинге чего - либо, то можно вообще обойтись буфером фиксированного размера для считывания и разбора файла и динамическими строками для хранения информации в классах. |  
						| 
								|  |  
								|  |  Записан | 
 
 Любимая игрушка - debugger ... |  |  | 
	| 
			| 
					
						| DneprSMV | 
								|  | « Ответ #10 :  26-10-2011 20:24 »   |  | 
 
 class MyTextProcesor { . . .  }  MyTextProcesor mtp;
 int err;
 mtp.Clear();
 err = mtp.LoadFile("C++.txt");
 err = mtp.Parse();
 if(err) .....
 else
 mtp.PrintResult();
 
 
 
 
 
 
 |  
						| 
								|  |  
								|  |  Записан | 
 
 "Не слушайте никаких советов, в том числе и этот" (Сократ ?) |  |  | 
	| 
			| 
					
						| sd 
								Постоялец    Offline | 
								|  | « Ответ #11 : 26-10-2011 21:43 »  |  | 
 
 А можно чуть чуть подробнее про функции LoadFile и Parse? |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| DneprSMV | 
								|  | « Ответ #12 : 27-10-2011 08:32 »  |  | 
 
 sd,   так как успехи ? выкладывай   LoаdFile - загрузка текста из файла в память (полностью). Выделение памяти в рамках class MyTextProcesor Parse - собственно разбор загруженной информации на абзацы-предложения-слова и уапковка в объекты class Word, Sentence + .... Можно еще добавить .TrimSpace() и .TrimTab() (или могут входить как protected и отрабатывать скрыто при загрузке файла) |  
						| 
								|  |  
								|  |  Записан | 
 
 "Не слушайте никаких советов, в том числе и этот" (Сократ ?) |  |  | 
	| 
			| 
					
						| sd 
								Постоялец    Offline | 
								|  | « Ответ #13 : 27-10-2011 18:05 »  |  | 
 
 Хотел сделать так: Txt::Txt(char *filename) {ifstream in(filename);
 char str[1024];
 
 if(!in) {
 cout<<"Can not open file "<<filename;
 exit(1);
 }
 
 int count=0, len=0, indx=0, size=0;
 char ch;
 //Считаем количество предложений
 while((ch=in.get())!=EOF) {
 size++;
 
 if(isEndOfSentence(ch))
 count++;
 }
 
 sntnces=new Sentence[count]; //выделяем для них памят
 
 in.close();
 in.open(filename);
 
 if(!in) {
 cout<<"Can not open file "<<filename;
 exit(1);
 }
 //выделяем предложения и выводим их на экран
 while((ch=in.get())!=EOF) {
 len=1;
 while(!isEndOfSentence(ch)) {
 len++;
 ch=in.get();
 }
 int pos=in.tellg();
 in.seekg(pos-len, ios::beg);
 in.getline(str, len+1);
 cout<<str<<endl;
 in.seekg(pos+1, ios::beg);
 }
 in.close();
 }
Проблема в том, что выводится только первое предложение, а дальше нет. |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Вад | 
								|  | « Ответ #14 : 27-10-2011 20:27 »  |  | 
 
 А зачем так сложно - открывать файл, пересчитывать предложения, второй раз открывать и пытаться читать? Я бы делал всё сразу на ходу. И, поскольку задача пока учебная, забьём пока на слишком длинные предложения, переполняющие буфер. Или простой буфер на что-нибудь, контролирующее свою длину - std::deque, например. Или вообще std::string. Получится что-то типа Sometype buf;std::ifstream input(name);
 char c;
 while (!input.eof()) {
 input.get(c);
 if (isSeparator(c) && buf.size()) {
 // перекладываем содержимое буфера куда надо - это наше предложение.
 // и очищаем буфер
 }
 else {
 // кладём c в конец буфера
 }
 }
 
Кстати, сам разделитель тоже надо добавлять в предложение, или нет? Я исходил из того, что не надо.Добавлено через 3 минуты и 8 секунд: ЗЫ. Кстати, не обязательно повторно открывать файловый поток. Можно просто сделать seekg в начало файла. |  
						| 
								|  |  
								| « Последнее редактирование: 27-10-2011 20:30 от Вад » |  Записан | 
 |  |  | 
	| 
			| 
					
						| DneprSMV | 
								|  | « Ответ #15 : 28-10-2011 09:18 »  |  | 
 
 sd,  по-моему сложновато. Ты все операции хочешь проделать в конструкторе ? (по большому счету, он в начале может быть вообще пустой, Txt::Txt() {) ). Твой текст состоит из абзацев, абзац состоит из предложений, предложения состоят из слов и знаков препинания. Символы веделять в качестве объектов - можно да(а смысл ?) наподобие объекта pixel::pixel(x.y) в графике)  а можно нет . +форматирование. -------- Как бы я делал помолчу, тк. не хочу испортить "обедню" своей метОдой    Но в любом случае вначале надо выделить классы, их методы-интерфейсы. У тебя в конструкторе совмещены 2 операции - чтение файла и его обработка. У меня некоторые представления, что в конструкторе операции по выделению памяти и инициализации объекта. Чтение и обработку я бы вынес в методы-функции. Или "верх" ты стремишься свести к  Txt MyTxt("file"); MyTxt.Yahoo(); ?  Если при работе конструктора произойдет ошибка - кто ее обработает ? (кроме exit(1) ) Обработанную-выделенную инф я бы располагал в виде списков текст - список абзацев абзац - список предложений предложение - список слов и знаков пунктуации с методами Txt.GetAbzatz(....) Abzatz.GetSentence(....) Sentence.GetWord(...) или нечто подобное. У тебя есть ф-ии GetWord(). Попробуй черново прописать программу "сверху" - с красивых ворот   Отладочную печать удобно делать не через поток, а printf - если Win32 Console printf("Отладка строка=<%s> n=%d", ptr_string, n); // n - число int |  
						| 
								|  |  
								|  |  Записан | 
 
 "Не слушайте никаких советов, в том числе и этот" (Сократ ?) |  |  | 
	| 
			| 
					
						| sd 
								Постоялец    Offline | 
								|  | « Ответ #16 : 28-10-2011 21:18 »  |  | 
 
 Сделал так как сделал. Вроде сдал и вроде прокатило. Спасибо вам.Сейчас начну делать след. задание - написание словаря. Буду обращаться наверное.
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	|  |