Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   Извлечение из текста нужной части (http://forum.oszone.net/showthread.php?t=191850)

Alexey271 21-11-2010 16:52 1547931

Извлечение из текста нужной части
 
Вложений: 1
Доброго времени суток!
Я не работаю в С++, поэтому прошу вас помочь!

Задача состоит в том, что бы вытащить из текстового файла (*.txt) все значения (цифры) и сортировать их по колонкам (всего 4 колонки значений).
Прикладываю файл, который пытаюсь обработать.


C++ BUILDER:

<!-- Вот мой первоначальный код. НАЧАЛО. -->
Код:

// КОД МОЖНО И НЕ СМОТРЕТЬ

int max_i = ListBox1->Items->Count; // Колличество строк (отсчет с 1)

int i=0;
                for(i; i<max_i; i++)
                {
AnsiString str = ListBox1->Items->Strings[i]; //Заполняю строковую переменную
// значениями строк ListBox1
int a, b, c, d;

//ВЫТАСКИВАЕМ ПЕРВОЕ ЗНАЧЕНИЕ В СТРОКЕ
        a = StrToFloatDef(
str.SubString  (0,str.Pos(" ")),0);
str.Delete(1,str.Pos(" "));

//ВЫТАСКИВАЕМ ВТОРОЕ ЗНАЧЕНИЕ В СТРОКЕ
        b = StrToFloatDef(
str.SubString  (0,str.Pos(" ")),0);
str.Delete(1,str.Pos(" "));

//ВЫТАСКИВАЕМ ТРЕТЬЕ ЗНАЧЕНИЕ В СТРОКЕ
        c = StrToFloatDef(
str.SubString  (0,str.Pos(" ")),0);
str.Delete(1,str.Pos(" "));

//ВЫТАСКИВАЕМ ЧЕТВЕРТОЕ ЗНАЧЕНИЕ В СТРОКЕ
        d = StrToFloatDef(
str.SubString  (0,str.Length()),0);
ListBox5->Items->Add(d);
ListBox2->Items->Add(a);
ListBox3->Items->Add(b);
ListBox4->Items->Add(c);
str.Delete(1,str.Pos(" "));


                }  // конец цикла for

                   
<!-- КОНЕЦ -->

// Да, знаю, что по идиотски сделано, но покоя не дает то, что он работает, если в строке первый символ является числом, а не пробелом

Alexey271 21-11-2010 18:48 1548009

Блин, решил я конечно эту проблему, но хотелось бы узнать как можно вытаскивать значения, если не считать "пробелы" между числами?!
Есть идеи?

Текстовый фаил загружается в ListBox1

Код:

int max_i = ListBox1->Items->Count; // Считаю количество строк в загружаемом файле

int i;
    for(i=2; i<max_i; i++) // От 2, потому что первые  две строки (0 и 1) с "херней"
    {
      AnsiString str = ListBox1->Items->Strings[i]; //Загружаю в переменную одну строку
      AnsiString a, b, c, d;


      str.Delete(1,6);
      a = str.SubString(0,str.Pos(" "));
      str.Delete(1,str.Pos(" "));

str.Delete(1,8);
b = str.SubString(0,str.Pos(" "));
str.Delete(1,str.Pos(" "));

str.Delete(1,6);
c = str.SubString(0,str.Pos(" "));
str.Delete(1,str.Pos(" "));

str.Delete(1,6);
d = str.SubString(0,str.Length());
str.Delete(1,str.Pos(" "));

}


Alexey271 21-11-2010 23:23 1548225

Код:

void __fastcall TForm1::Button2Click(TObject *Sender)
{
ListBox1->Items->Count; 
int max_i = ListBox1->Items->Count;
AnsiString a, b, c, d;
int i;
                for(i=2; i<i<max_i; i++)
                {
AnsiString str = ListBox1->Items->Strings[i];
str.Delete(1,6); //Удаляю лишние пробелы
int poitTozap = str.Pos("."); // рождаю переменную int и присваиваю ей порядковый номер первого найденного символа '.'
str.Delete( poitTozap, 1) ; // удаляю этот символ "точки"
str.Insert( ",", poitTozap); // заменяю на запятую (что бы потом переводить в float и запихивать в массив для расчетов и
 //построения графиков
a = str.SubString(0,str.Pos(" ")-1); // Загоняю в string a числа между 0 знаком и первым "пробелом"-1
str.Delete(1,str.Pos(" "));  // удаляю это строковое значение из string AnsiString str и повторяю операции с оставшимися в
 //строке символами

str.Delete(1,8);
poitTozap = str.Pos(".");
str.Delete( poitTozap, 1) ;
str.Insert( ",", poitTozap);
b = str.SubString(0,str.Pos(" ")-1);
str.Delete(1,str.Pos(" "));

str.Delete(1,6);
poitTozap = str.Pos(".");
str.Delete( poitTozap, 1) ;
str.Insert( ",", poitTozap);
c = str.SubString(0,str.Pos(" ")-1);
str.Delete(1,str.Pos(" "));

str.Delete(1,6);
poitTozap = str.Pos(".");
str.Delete( poitTozap, 1) ;
str.Insert( ",", poitTozap);
d = str.SubString(0,str.Length());
str.Delete(1,str.Pos(" "));

ListBox5->Items->Add(d);
ListBox2->Items->Add(a);
ListBox3->Items->Add(b);
ListBox4->Items->Add(c);
                }
}

Да, Все зашибись! Перегоняю каждый "столбец" в массив свой и "оло-ло", считай и строй графики!

ПРОБЛЕМА:
КАК БОЛЕЕ ГРАМОТНО РЕАЛИЗОВАТЬ ЭТОТ МЕТОД? (Я ПО ПОВОДУ ПРОБЕЛОВ В *.txt).

Drongo 22-11-2010 17:25 1548752

Погоди, не спеши так. :) Давай ещё раз по порядку.

1. Грузим файл(который прикреплён) в ListBox
2. Из этого файла извлекаем четыре столбца в четыре ListBox'a? 1 стобец - 1 ListBox?
3. Удалить лишние пробелы между столбцами

P.S. Выполнил в билдере 6, ошибка, выход за границы диапазона.

Дай время, дня два-три, подумаю...

Drongo 22-11-2010 17:48 1548769

Alexey271, Решил упрощённо, 15 строк кода. :) Я учитываю что в ListBox1 файл уже загружен.

Код:

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  TSysCharSet chSplash;
  chSplash<<' ';
  TStringList *lst = new TStringList();
  TStringList *TokenList = new TStringList();
  lst->Text = ListBox1->Items->Text;
  for(int i = 2; i < lst->Count; i++){
      ExtractStrings(chSplash, chSplash, lst->Strings[i].c_str(), TokenList);
      ListBox2->Items->Add(TokenList->Strings[0]);
      ListBox3->Items->Add(TokenList->Strings[1]);
      ListBox4->Items->Add(TokenList->Strings[2]);
      ListBox5->Items->Add(TokenList->Strings[3]);
      TokenList->Clear();
    }
  delete lst;
  delete TokenList;
}
//---------------------------------------------------------------------------


pva 22-11-2010 19:50 1548875

решение нисколько не лучше, просто сделанное по-другому, всё хранится в памяти:
Код:

// без этого билдер 4 не собирает STL
// #include <condefs.h>
// может понадобиться
// #include <vector>
// #include <algorithm>
// using namespace std;

vector<vector<double> > rows;

// считаем что в файле ровно 4 столбца, причём одинаковой длины
// иначе получится фигня

{
        ifstream input("20_1.txt");

        double x, y, tmp;

        input >> x >> y; // в начале файла 2 каких-то возможно нужных значения

        // читаем по спискам

        for(unsigned n = 0; (input >> tmp); n = (n + 1) & 3)
        {
                rows[n].push_back(tmp);
        }

        // сортируем списки

        for(unsigned n = 0; n < rows.size(); ++n)
        {       
                sort(rows[n].begin(), rows[n].end());
        }
}


Alexey271 23-11-2010 03:50 1549176

Спасибо за варианты pva и Drongo!
Оттестирую ближе к вечеру по мск!

pva и Drongo еще один вопросик?!
В текстовом файле числа записаны через "точку", поэтому мне приходится находиться точку и заменять ее на "запятую" что бы смог применить StrToFloat!
Меня, честно говоря, это настораживает, потому что эти значения используются в расчетах. Ну просто нельзя так извращаться и писать код для извлечения чисел из файла на 2-3 стр.

Код:

...
int poitTozap = str.Pos(".");
str.Delete( poitTozap, 1) ;
str.Insert( ",", poitTozap);
...


Drongo 23-11-2010 14:04 1549460

Alexey271, Тогда можно так. Использовать StringReplace - искать точку и заменять её на запятую по всему тексту. Выделил зелёным цветом где написать строку.
Код:

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  TSysCharSet chSplash;
  chSplash<<' ';
  TStringList *lst = new TStringList();
  TStringList *TokenList = new TStringList();
  lst->Text = ListBox1->Items->Text;
  lst->Text = StringReplace(lst->Text, ".", ",", TReplaceFlags()<<rfReplaceAll);
  for(int i = 2; i < lst->Count; i++){
      ExtractStrings(chSplash, chSplash, lst->Strings[i].c_str(), TokenList);
      ListBox2->Items->Add(TokenList->Strings[0]);
      ListBox3->Items->Add(TokenList->Strings[1]);
      ListBox4->Items->Add(TokenList->Strings[2]);
      ListBox5->Items->Add(TokenList->Strings[3]);
      TokenList->Clear();
    }

//  double *array = new double[ListBox2->Count];
  //for(int i = 0; i < ListBox2->Count; i++)
      //array[i] = ListBox2->Items->Strings[i].ToDouble();

  delete lst;
  delete TokenList;
}
//---------------------------------------------------------------------------


pva 24-11-2010 20:26 1550773

Цитата:

Цитата Alexey271
мне приходится находиться точку и заменять ее на "запятую" »

всё зависит от локали. StrToFloat использует локаль Windows, в которой у тебя настроена запятая. Зайди в панель управления, региональные настройки и поставь разделителем точку - тогда StrToFloat будет использовать точку. Оператор чтения из потока >> (если не переустанавливать локаль) использует локаль C++ по умолчанию, в которой используется точка. Как вариант, можно использовать сишную atof, которая использует локаль си, в которой тоже точка.
Код:

// c
//#include <stdlib.h>
//#include <math.h>
double val = atof(TokenList->Strings[0].c_str());

// c++
//#include <sstream>
// using std::istringstream

double val = 0.0;
istringstream ss(TokenList->Strings[0].c_str());
ss >> val;


Alexey271 25-11-2010 13:19 1551266

pva
Ух, буду иметь ввиду, спасибо


Время: 12:27.

Время: 12:27.
© OSzone.net 2001-