Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C++ Builder > обработка данных в Borland C++ Builder


Автор: AFenix85 20.4.2007, 11:05
Мне надо из file.dat считать данные в программе.Помогите кто может.
Файл представляет из себя таблицу,без линий(надеюсь понятно),нужно считать определенный столбец! smile Помогите как smile  

Автор: Rodman 20.4.2007, 11:12
работать с файлом можно при помощи TStringList...

но что ты имеешь ввиду под "столбцом"...

Покажи структура файла...

Автор: Anikmar 20.4.2007, 11:18
Цитата(AFenix85 @  20.4.2007,  11:05 Найти цитируемый пост)
Файл представляет из себя таблицу,без линий(надеюсь понятно),

Для меня было бы больше непонятно "Файл представляет собой таблицу с линиями"

Присоединяюсь к Rodman : структуру файла в студию!

Автор: AFenix85 20.4.2007, 11:20
Это кусок!

 tm55    tm60    tm65    tm70    tm75    tm80    tm85    tm90    vx55
4.211    4.211    4.218    4.211    4.211    4.211    4.224    4.211    -58.5
4.224    4.229    4.224    4.218    4.218    4.218    4.229    4.218    -57
4.229    4.236    4.229    4.224    4.224    4.224    4.242    4.224    -56.6
4.236    4.242    4.236    4.229    4.229    4.229    4.311    4.229    -56.4
4.242    4.248    4.242    4.236    4.236    4.236    4.324    4.236    -56.4
4.248    4.254    4.248    4.242    4.242    4.242    4.636    4.242    -56.6
4.254    4.561    4.561    4.248    4.248    4.248    4.661    4.248    -56.9
4.592    4.568    4.579    4.254    4.254    4.254    4.961    4.254    -57.3
4.611    4.574    4.611    4.311    4.311    4.311    5.161    4.311    -57.8
4.617    4.579    4.617    4.318    4.318    4.318    5.174    4.318    -58.4
4.624    4.586    4.624    4.324    4.324    4.324    5.561    4.324    -59.3
4.629    4.592    4.629    4.329    4.329    4.329    5.674    4.329    -60.3
4.636    4.611    4.636    4.336    4.336    4.336    5.879    4.336    -61.5
4.642    4.617    4.642    4.468    4.342    4.342    5.886    4.342    -62.8
4.661    4.624    4.661    4.474    4.348    4.411    5.924    4.348    -64.2
4.668    4.629    4.724    4.479    4.411    4.418    6.117    4.411    -65.6
4.674    4.636    4.879    4.486    4.418    4.429    6.836    4.418    -67.1
4.679    4.642    4.942    4.492    4.424    4.461    ******    4.424    -68.5
4.911    4.661    4.961    4.561    4.442    4.486    ******    4.429    -69.8
4.918    4.668    4.968    4.568    4.461    4.492    ******    4.442    -71.2
4.924    4.824    5.068    4.574    4.468    4.561    ******    4.461    -72.4


Как например считать tm75.То есть выбрать этот столбец и считать его! smile  smile 

Автор: Rodman 20.4.2007, 11:32
Ну тебе надо найти каким по счету идет tm75, а потом отсчитывать в каждой строке... учет пробелов нужен...

Автор: AFenix85 20.4.2007, 11:42
А как это сделать?Прочел много, а результата нет!Книги на этом форуме качал!
Если можно,то помогите примерами пожалуйста smile   

Автор: Pendalf 20.4.2007, 16:17
Когда-то товарищ просил нечто подобное. Код писался в блокноте и не компилировался, поэтому могут быть некоторые ошибки.
Код

//открываем файл на чтение и запись
FILE *in = fopen("my_file.txt", "r"); //исходный файл
FILE *out = fopen("your_file.txt", "a+"); //выходной файл

//ставим курсор в начало файла
fseek(in, 0, SEEK_SET);

//пока не конец файла с исходными данными читаем его построчно
while(feof(in) != 0) {
   char str[80]; //длина строки от балды. Здесь на самом деле лучче подбирать экскрементально
   fgets(str, strlen(str) + 1, in); //прочитали строку из файла
   strtok(str, " ");
   strtok(NULL, " "); //удалили вторую позицию 
   strtok(NULL, " "); //удалили третью позицию
   strtok(NULL, " "); //удалили четвертую позицию
   String param = strtok(NULL, " "); //высосали наш параметр
   fprintf(out, "%s", param); //записали то что отсосали в выходной файл 
   }

//закрыли файлы по окончании обработки дабы чего-нить избежать...
fclose(in); 
fclose(out);


Автор: AFenix85 20.4.2007, 16:49
Спасибо,Pendalf.за наглядный пример smile 
Если я правильно понял,теперь мне надо все это проделать для каждого элемента
этого столбца smile 
А нельзя как нибудь по проще smile 
И еще,кто знает простой способ постройки гистограммы в форме? smile  

Автор: Klin 20.4.2007, 17:22
Цитата(AFenix85 @  20.4.2007,  17:49 Найти цитируемый пост)
А нельзя как нибудь по проще

В принципе можно smile
Код

 int l=0,x=0, E_Num =0, L_Num=0;
 for (int n = 0; n<E_Num ; n++) {
  x = ( Memo1->Lines->Strings[L_Num].SubString(l+1,Memo1->Lines->Strings[L_Num].Length()) ).Pos(" ") ;
  l+=x;
 }
 ShowMessage(Memo1->Lines->Strings[L_Num].SubString(l,Memo1->Lines->Strings[L_Num].Pos(" ")).TrimLeft());


Вроде все работает. Это пример получения столбца ( E_Num ) из строки L_Num. Позже если надо, то могу и другие функции обработки написать

Автор: Anikmar 20.4.2007, 17:23
Цитата(AFenix85 @  20.4.2007,  16:49 Найти цитируемый пост)
Если я правильно понял,теперь мне надо все это проделать для каждого элемента
этого столбца  
А нельзя как нибудь по проще  


Так там же цикл по строчкам. Весь столбец и будет обработан. Куда уж проще?

Можно по-другому:
Считываем 1-ю строку. Это, если я правильно понял названия столбцов.
Ищем нужное название - запоминаем номер столбца с этим названием.
Дальше построчно считываем файл, выдираем из строки именно эту позицию.
Позиции считаются по пробелам (если там не табуляция)

А на счет гистограммки - в Билдере компонент есть для этого, ароде должен рисовать

Автор: AFenix85 21.4.2007, 05:24
Цитата(Klin @  20.4.2007,  17:22 Найти цитируемый пост)
Позже если надо, то могу и другие функции обработки написать 


Если не трудно,то напиши пожалуйста! smile  

Цитата(Anikmar @  20.4.2007,  17:23 Найти цитируемый пост)
А на счет гистограммки - в Билдере компонент есть для этого, ароде должен рисовать 


А можешь написать?

Автор: Anikmar 21.4.2007, 07:52
Цитата(AFenix85 @  21.4.2007,  05:24 Найти цитируемый пост)
А можешь написать?


Чего написать? Компонент? Я пока даже условия задачи не увидел.

Компонент называется TChart.  Если набрать его в поиске по форуму - вылезет уйма информации. Я лично с ним никогда не работал - знаю, что он есть, но мне пока не понадобился.

Автор: AFenix85 21.4.2007, 09:09
Я тебя не понял! smile 

Цитата(Anikmar @  20.4.2007,  17:23 Найти цитируемый пост)
Позиции считаются по пробелам (если там не табуляция)


А если там табуляция,то че делать smile 

Меня эта задача уже достала,че не пробую,ниче не получается.Либо виснет,либо глючит,либо ниче не происходит smile  smile  smile  

Автор: Anikmar 21.4.2007, 11:02
Цитата(AFenix85 @  21.4.2007,  09:09 Найти цитируемый пост)
Цитата(Anikmar @  20.4.2007,  17:23 )
Позиции считаются по пробелам (если там не табуляция)



А если там табуляция,то че делать  


Очевидно считать по табуляции. А можно и все сразу.
Идем по строчке. Если символ не является разделителем - то считаем, что это значение столбца. Дошли до разделителя - увеличиваем счетчик столбцов и идем по символам пока разделители не кончаться (если их несколько подряд).
Дошли опять до рабочего символа - значит начался следующий столбец - ждем пока закончится.

Я когда очень давно (не помню зачем) писал функцию, которая возвращает слово из строки по номеру - если найду - скину

Добавлено через 3 минуты и 37 секунд
Нашел. Правда она на Билдере написана, но логика понятна, изменить ее можно, можно свою написать:
Код

//---------------------------------------------------------------------------
// Функция: MAN_GetWord
//
// Возвращает слово строки по порядку
// Пустая строка - слово отсутствует
// Source - исходная строка
// Number - номер слова
// Case = 0 - в том виде в каком оно в строке
// Case > 0 - верхний регистр
// Case < 0 - нижний регистр
AnsiString MAN_GetWord(AnsiString& Source, int Number, int Case)
{
    int i;
    bool StartWord = false;
    int NumWords = 0;
    int PosWord = 0;
    int PosEnd;
    AnsiString Result;

    for (i=1;i<=Source.Length();i++)
    {
        if (Source.IsDelimiter(" ,.!@#$%^&*()-=+|\\/<>:;`",i))
        {
        // Если символ разделитель - значит слово окончилось
            StartWord = false;
            // Если дошли до нужного слова - выхожу из цикла
            if (NumWords == Number) break;
        } // if (Source.IsDelimiter(" ,.!@#$%^&*()-_=+|\\/<>:;`",i))
        else
        {
        // Символ не разделитель
            if (!StartWord)
            {
            // Если слово не в процессе
            // Запоминаю его начало
                PosWord = i;
                StartWord = true;
                NumWords++;
            } // if (!StartWord)
            else
            {
            // Если слово в процессе - передвигаю конец
                PosEnd = i;
            } // if (!StartWord) else
        } // if (Source.IsDelimiter(" ,.!@#$%^&*()-_=+|\\/<>:;`",i)) else
    } // for (i=1;i<=Source.Length();i++)

    if (NumWords == Number)
    {
    // Если нужное слово было копирую его в результат
        Result = Source.SubString(PosWord,PosEnd-PosWord+1);
        if (Case < 0) Result = Result.LowerCase();
        if (Case > 0) Result = Result.UpperCase();
    }

    return Result;
}



Добавлено через 5 минут и 16 секунд
Тьфу. Это же и есть форум по Билдеру - совсем заработался  smile 

Автор: AFenix85 21.4.2007, 14:26
Цитата(Anikmar @  21.4.2007,  11:02 Найти цитируемый пост)
Добавлено через 5 минут и 16 секунд
Тьфу. Это же и есть форум по Билдеру - совсем заработался   


Я тоже подумал,но спасибо за пояснение! smile 

Большое спасибо за пояснения и примеры всем! smile 



Автор: Klin 21.4.2007, 14:40
Код, который я писал ранее, не всегда вывод нужное значение.

Вот исходник, с основными функциями:

Автор: AFenix85 21.4.2007, 15:00
Извиняюсь перед всеми smile 

Цитата(AFenix85 @  20.4.2007,  11:20 Найти цитируемый пост)
Как например считать tm75.То есть выбрать этот столбец и считать его!    


Мне надо весь столбец считать в массив,для последующей его обработки!
Я в С++Builder'e новичек,многого не знаю! smile 

 
Цитата(Anikmar @  21.4.2007,  11:02 Найти цитируемый пост)
Добавлено через 3 минуты и 37 секунд
Нашел. Правда она на Билдере написана, но логика понятна, изменить ее можно, можно свою написать:


Извини меня за мою тупость,но не мог бы ты обьяснить то, че ты скинул smile .До меня ниче не дошло,че,где и как там все происходит smile  

Автор: AFenix85 21.4.2007, 15:29
Цитата(Klin @  21.4.2007,  14:40 Найти цитируемый пост)
Присоединённый файл ( Кол-во скачиваний: 1 ) 
  sample.zip 6,95 Kb


Посмотрел на прогу,но она не запускается,выдает ошибку:

[Linker Fatal Error] Fatal: Unable to open file 'DCLUSR.BPI'

Че это может поможешь? smile 

Автор: Klin 21.4.2007, 15:39
Пересохранил, если не заработает , значит что-то у в настройках у тебя не то. 

p.s. можешь просто создать свою программу на основе моей.


Автор: AFenix85 21.4.2007, 16:11
Ага работает,но че мне делать, если я не знаю че,что делает в проге. smile 

Klin. напиши коменты пожалуйста smile 


Да,забыл мне надо весь столбец считать в массив,для последующей его обработки!
Я в С++Builder'e новичек,многого не знаю!Помого с алгоритмом smile   

Автор: Klin 21.4.2007, 16:50
Цитата(AFenix85 @  21.4.2007,  17:11 Найти цитируемый пост)
Klin. напиши коменты пожалуйста 

Сорри, заработался...
Перемменные:
  •  Pos  - номер символа, с которого считывается ячейка
  •  LastPos - последний символ считывания
  •  text - нужен для сокращения кода, получения длинны (в процедуре изменения)
  •  NowX и NowY - номер строки и столбца
Код

 /* ПОЛУЧЕНИЕ НУЖНОЙ ЯЧЕЙКИ (Action1) */
 Pos = 0; // обнуляем Pos, иначе не будет правильных вычислений
 text = Memo1->Lines->Strings[NowY]; text+=" ";
 // присваение строки из Edit2 и добавление к ней пробела для правильности определеня

 for (int n = 0; n<NowX; n++)
  Pos+=text.SubString(Pos,text.Length()).TrimLeft().Pos(" ");
 // поиск столбца под номером из Edit1

 LastPos =  text.SubString(Pos,text.Length()).TrimLeft().Pos(" ");
 // запоминаем позицию окончания текста найденной ячейки

 text = text.SubString(Pos,LastPos).TrimLeft();
 /* запоминаем полученное значение текста (из промежутка Pos - LastPos)
    для дальнейшего использования в программе */


Код

 /* ПОЛУЧЕНИЕ ЗНАЧЕНИЯ ЯЧЕЙКИ (Button1) */
 NowX = Edit1->Text.ToInt();  //  из Edit1 - номер строки
 NowY = Edit2->Text.ToInt();  //  из Edit2 - номер столбца
 Action1->Execute();  // поиск ячейки
 Edit3->Text = text;  // вывод полученной ячейки

Код

 /* ИЗМЕНЕНИЕ ЗНАЧЕНИЯ ЯЧЕЙКИ (Button2) */

 Action1->Execute(); // поиск ячейки
 if (Pos) text+=" "; // если мы имеем дело с первым ячейкой, то добавляем длинну строки

 Memo1->Lines->Strings[Edit2->Text.ToInt()]=
 Memo1->Lines->Strings[Edit2->Text.ToInt()].Delete(Pos+1,text.Length());
 // удаление старого значения ячейки

 Memo1->Lines->Strings[Edit2->Text.ToInt()]=
 Memo1->Lines->Strings[Edit2->Text.ToInt()].Insert(AnsiString(Edit4->Text+" "),Pos+1);
 // добавление нового значения

Код

 /* УДАЛЕНИЯ ЯЧЕЙКИ (Button3) */
 Action1->Execute(); // поиск ячейки
 if (Pos) text+=" "; // если мы имеем дело с первым ячейкой, то добавляем длинну строки

 Memo1->Lines->Strings[Edit2->Text.ToInt()]=
 Memo1->Lines->Strings[Edit2->Text.ToInt()].Delete(Pos+1,text.Length());
 // удаление старого значения ячейки (полное удаление)

Код

 /* ПЕРЕДАЧА СТОЛБЦА В МАССИВ (Button4) */
 AnsiString m[30]; // Объявление массива
 NowX = Edit1->Text.ToInt();  //  Edit1 - номер строки
 for (int n = 0; n<Memo1->Lines->Count; n++)
 { NowY = n; Action1->Execute();  m[n+1] = text; }
 // добавлении в Memo2 всех строк NowX из столбца NowY

 for (int n = 1; n<Memo1->Lines->Count; n++)
  Memo2->Lines->Add(m[n]);
 // Работа с массивом (вывод данных в Memo2)

Весомый пост  smile 

Автор: AFenix85 22.4.2007, 04:55
Балин smile 
Как много инфы,ну ни че,будем фильтровать! smile  

Автор: AFenix85 22.4.2007, 05:21
klin помоги,че он ругается в написаном сверху?

[C++ Warning] Unit1.cpp(77): W8004 'NowY' is assigned a value that is never used
[C++ Warning] Unit1.cpp(77): W8004 'NowX' is assigned a value that is never used

А кто знает как сделать такую вещь:
1.В папке лежат файлы *.dat
2.*.dat содержат эти самые таблицы
3.На форме в Edit пишем название *.dat, и прога сама открывает файл, какой нужно 

Автор: Anikmar 22.4.2007, 11:28
Цитата(AFenix85 @  22.4.2007,  05:21 Найти цитируемый пост)
А кто знает как сделать такую вещь:
1.В папке лежат файлы *.dat

Воспользуйтесь диалогом TOpenDialog - тогда пользователь еще и сможет выбрать нужный файл из любого места на диске

Автор: AFenix85 22.4.2007, 11:42
Цитата(Anikmar @  22.4.2007,  11:28 Найти цитируемый пост)
Воспользуйтесь диалогом TOpenDialog 


А можно примерчик,а то я не знаю как!

Автор: Anikmar 22.4.2007, 13:16
Цитата(AFenix85 @  22.4.2007,  11:42 Найти цитируемый пост)
А можно примерчик,а то я не знаю как!


Да в общем то - 3 действия

1. Размещаем на форме нужный диалог (палитра Dialogs - там есть разные)
2. Размещаем на форме кнопку "Открыть файл"
3. В обработчике этой кнопки пишем
if (OpenDialog1->Execute())
{
    MyOpenFile(OpenDialog->FileName);
}

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

Писал по памяти - если где очепятка - я не виноват.

Автор: AFenix85 22.4.2007, 15:11
Извини Anikmar,я ошибся,мне не надо его непосредственно открывать,а надо считать нужный столбец smile 
Просто хочется,чтобы прога все делала сама,и сама искала этот файл на диске,а его имя вводить в Editе!
Также в Edite вводить название столбца и прога его нашла и считала в массив для последующей его обработки! smile 
Многого не знаю и потому прошу  smile  с коментами,если не трудно smile 

Автор: Klin 22.4.2007, 16:04
Цитата(AFenix85 @  22.4.2007,  06:21 Найти цитируемый пост)
[C++ Warning] Unit1.cpp(77): W8004 'NowY' is assigned a value that is never used
[C++ Warning] Unit1.cpp(77): W8004 'NowX' is assigned a value that is never used

Это означает, что вы не используете эти переменные в своей программе.

Цитата(AFenix85 @  22.4.2007,  16:11 Найти цитируемый пост)
а его имя вводить в Editе!

Код

 Memo1->Lines->LoadFromFile(Edit1->Text);


Цитата

Также в Edite вводить название столбца и прога его нашла и считала 


Для этого можно так написать:
Код

 AnsiString temp = Memo1->Lines->Strings[0]; temp+=" ";
  // создаем строку для временного поиска
 NowX=0; NowY=0; Action1->Execute();
  // обнуляем значения и получаем первый заголовок

while (Pos < temp.Length()) {
// до тех пор пока все проелы не найдем

 if (text.Trim() == Edit5->Text) {
  // проверяем совпадения полученного заголовка (text) и искомого (Edit5)
   Edit1->Text = NowX; // необъходимо для использования следующей функции
   Button4->Click();  // функция "ПЕРЕДАЧА СТОЛБЦА В МАССИВ"
   break;         // убиваем цикл
  }
  NowX++; Action1->Execute(); // получаем следующий заголовок
 }

Автор: GIK 22.4.2007, 16:39
Народ, сори что влезу щас не в тему, но для себя я обнаружил новшество, когда решал эту задачу. Оказывается если строка, к примеру имеет длину 21 символ, то при счтитывании с помошью функции getline(); до конца строки ( '\n' ), кол-во счытанных эллементов = длине строки +1, и + конец строки. Имеем мы к примеру файл:
FG12 HG23 RT43       
9.12 1.23 1.44  
1.45 4.67 1.45 
1.34 5.67 1.23  
Поправте если не прав.

Код

#include<conio>
#include<stdio>
#include<cstdio>
#include<stdlib>
#include<iostream>
#include<fstream>

void main()
{

  std::fstream from("C://test/test.txt", std::ios::in | std::ios::binary);
   if(!from){
    std::cout<<"Not File";
    getch();
    return;
   }
  int i=0; 
   char *ch = (char *)malloc(12);

  from.getline(ch, 123, '\n');
  int n, j; char get[5]={0};
  for(n=0; n<3; n++){
   i=from.tellg(); 
   std::cout<<i<<"\n";  //Выдаст 16, символ перед которым остоновится курсор, хотя строка, которую считали в буфер имеет длину 14 (13 по индексу) + 1 непонятный символ + конец строки "\n" 
   i+=5; 
   from.seekg(i);
   for(j=0; j<4; j++){
    from.get(get[j]); 
   }
   std::cout<<get<<"\n";
   from.getline(ch, 123, '\n'); 
  }
  char c='1';
  i=c-48;
  std::cout<<i<<"\n";
   getch();
}


Да кстати, если нужно вбить в массив именно числа, то придется конвертить побитово char символы в числа, с целыми числами это не проблема, разница между символом '1' и числом 1  = 48, а вот с нецелыми придется работать с мантисой. 

Автор: AFenix85 23.4.2007, 10:24
Цитата(Klin @  22.4.2007,  16:04 Найти цитируемый пост)
Это означает, что вы не используете эти переменные в своей программе.


Это я понял,а зачем ты их тогда мне написал,путать то зачем,мне итак плохо smile 


Напишите пожалуйста код!
1.Из Edit1 считываем, например, tm75
2.В примере моей таблицы,просмотреть 1 строку и найти номер столбца tm75
3.Как написать условие проверки  
4.Номер вывести в Memo1

Для меня,новичка,это затруднительно smile 

Автор: Klin 23.4.2007, 13:35
Цитата(AFenix85 @  23.4.2007,  11:24 Найти цитируемый пост)
Это я понял,а зачем ты их тогда мне написал,путать то зачем,мне итак плохо

Я то их в коде использовал. Это вы их упустили. smile

Цитата(AFenix85 @  23.4.2007,  11:24 Найти цитируемый пост)
Для меня,новичка,это затруднительно 

Я в своем предудущим посте, написал как это сделать для Edit5

Автор: AFenix85 23.4.2007, 13:48
Цитата(AFenix85 @  23.4.2007,  10:24 Найти цитируемый пост)
3.Как написать условие проверки  


Цитата(Klin @  23.4.2007,  13:35 Найти цитируемый пост)
Я в своем предудущим посте, написал как это сделать для Edit5 


Я имел ввиду,не как вывести,а как сделать проверку.Чтобы прога по циклу переработала 1 строку и нашла нужный столбец по названию!
А в эдит вводить что угодно!

В вашем посте я не сразу увидел и понял смысл проверки smile
 
Мне нужен перебор пробелов для последующей обработки файла, напишите пожалуйста! smile  

Автор: Klin 23.4.2007, 16:42
Цитата(AFenix85 @  23.4.2007,  14:48 Найти цитируемый пост)
Мне нужен перебор пробелов для последующей обработки файла, напишите пожалуйста!

А до этого чем занимались? smile


Цитата(AFenix85 @  23.4.2007,  14:48 Найти цитируемый пост)
Я имел ввиду,не как вывести,а как сделать проверку.Чтобы прога по циклу переработала 1 строку и нашла нужный столбец по названию!
А в эдит вводить что угодно!


Ну значит кусками будем выводить :
Код

AnsiString temp = Memo1->Lines->Strings[0]; temp+=" ";
  // создаем строку для временного поиска
 NowX=0; NowY=0; Action1->Execute();
  // обнуляем значения и получаем первый заголовок

while (Pos < temp.Length()) {
// до тех пор пока все проелы не найдем

 if (text.Trim() == Edit5->Text) {
  // проверяем совпадения полученного заголовка (text) и искомого (Edit5)
   Edit1->Text = NowX; // необъходимо для использования следующей функции
   Edit5->Text = "ОЧЕНЬ НУЖНЫЙ ТЕКСТ";
   break;         // убиваем цикл
  }
  NowX++; Action1->Execute(); // получаем следующий заголовок
 }

Заменил...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)