Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Как извлечь числовое значение из HTML


Автор: kresh 24.3.2008, 11:02
Всем привет! Есть вопрос ,как извлечь данные из HTML  файла без применения специальных средств по Xml(т.е препод сказал
что это можно сделать используя только с++). Вот файл из которого надо извлечь данные

Код

CHF<td nowrap>1 швейцарский франк<td align
=right>2 128.76<tr><td align=centrer>


Надо извлечь  число 2128.76 и записать его в переменную. Я делал так

1. Получал  указатель на место в строке где находиться точка, а как дальше считать число двигаясь от этой точки(разделителя) чего то не пойму.
Вот  мой код

Код

#include "stdafx.h"
#include <string>
#include <fstream>
#include <iostream>
#include <cctype>
float kurs;

using namespace std;
void ERASE(char szData[5000])


    ifstream TempBank("TempBank.txt");

    if (!TempBank){cout<<"\n File not open";}
    
    TempBank>>szData[2697];
    cout<<szData;
//преобразуем  С-строку в объект класса string с помощью конструктора(СТАНДАРТНЫЙ КЛАСС)
     
    char AUD[]="CHF";
    char gg[]=".";
    char *pdest;
    char *KURSS;

   //  stszData=szData;
    //for (int i=0;i<2696;i++){
    
        pdest=strstr(szData,AUD);/*поиск подстроки в строке,в 
                                 случае положительного результата
                                  возвращает указатель на элемент из szData*/

        if(pdest!=NULL){cout<<"\n index="<<pdest;
        KURSS=strstr(pdest,gg);
        cout<<"\n ==================================================================================";
        cout<<"\n===="<<KURSS;

Автор: Alek86 24.3.2008, 11:11
1. Я бы препода наколол - использовав бустовский регексп smile (или вообще xml-parser - он же на сях )
2. Не очень понятно задание. Только для этой строки нужно выделить только это число? Если так, то можно найти в строке
Код
CHF<td nowrap>1 швейцарский франк<td align
=right>2 128.76<tr><td align=centrer>

строки
Код
right>

и
Код
<tr>

то, что между ними - и есть число 2 128.76
(или вообще посчитать самому где оно находится и сделать substr

Автор: kresh 24.3.2008, 11:43
тАК ПОДСЧИТАТЬ МЕСТО РАСПОЛОЖЕНИЕ ЧИСЛА ЭТО ПРОСТО, А ВОТ СДЕЛАТЬ ТАК ЧТОБ ЧИСЛО ИЗВЛЕКАЛОСЬ НЕ ЗАВАСИМО ОТ ЕГО РАСПОЛОЖЕНИЯ ВОТ ЭТО ВОПРОС!  пРЕПОД ГОВОРИТ ЧТО ТИПА НАДО ИСКАТЬ РАЗДЕЛИТЕЛЬ -ТОЧКУ И ОТ НЕЁ ДВИГАТЬСЯ ДАЛЬШЕ ИСПОЛЬЗУЯ ФУНКЦИИ ДЛЯ ИЗВЛЕЧЕНИЯ ЧИСЛОВЫХ ПОСЛЕДОВАТЕЛЬНОСТЕЙ,ЧТО ОНА ИМЕЛА ВВИДУ ВИГ ЕЁ ЗНАЕТ.

Автор: Alek86 24.3.2008, 11:53
В общем если другие не хотят тебе помогать, то я вот налабал (как раз вспомнил работу с stl)
Работает не всегда верно. Коли уж не будет других вариантов, можешь попытаться разобраться smile

Код

#include <iostream>
#include <algorithm>
#include <locale>

bool IsPoint(char i_ch) {
  return i_ch == '.';
}

struct IsIntegralDigit {
  IsIntegralDigit() : m_delimiter(0) {}
  bool operator()(char i_ch) {
    bool res = (i_ch >= '0' && i_ch <= '9');
    if (3 == m_delimiter++) {
      bool is_space = (i_ch == ' ');
      res |= is_space;
      if (is_space)
        m_delimiter = 0;
    }
    return res;
  }
private:
  size_t m_delimiter;
};

int main() {
  std::string str = "wds dasd as12 232 323.456sdfdf";
  std::string::const_iterator it_end = str.end();
  std::string::const_iterator it_beg = str.begin();
  std::string::const_iterator it_point = std::find_if(str.begin(), str.end(), IsPoint);
  std::string::const_iterator it_after = it_point;
  // find digits after point
  if (it_point != it_end)
    for (++it_after; it_after != it_end && isdigit(*it_after); ++it_after);
  // find digits before point
  std::string::const_iterator it_before = it_point;
  IsIntegralDigit is_integral_digit;
  if (it_point != it_beg)
    for (--it_before; it_before != it_beg && is_integral_digit(*it_before); --it_before);
  ++it_before; // now it's on digit or space
  if (*it_before == ' ')
    ++it_before;
  if (it_before != it_after)
    std::copy(it_before, it_after, std::ostream_iterator<char>(std::cout));
}

Автор: inside_pointer 24.3.2008, 13:40
Попробуй вот такую ещё
Код

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* 
 * Выдернуть число 2 128.76
 *
 * 1: CHF<td nowrap>1 швейцарский франк<td align
 * 2: =right>2 128.76<tr><td align=centrer>
 *
 */       

int main()

{
    char str[500] = "CHF<td nowrap>1 швейцарский франк<td align=right>2 128.76<tr><td align=centrer>";
    char chislo[10];
        
    int i, j;
    double n;
    
    for (i = strcspn(str, "."); str[i-1] != '>'; --i)
        ;
    
    for (j = 0; str[i+j] != '<'; ++j) {
        if (str[i+j] == ' ')
            ++i;
        chislo[j] = str[i+j]; 
        chislo[j+1] = '\0';
    }
        
    n = strtod(chislo, NULL);

    printf("%.2f\n", n);

    return 0;
}

//
 

Автор: profispb 24.3.2008, 14:45
Модератор: Сообщение скрыто.

Автор: Alek86 24.3.2008, 14:49
profispb, интересно как ты учтешь пробел каждые 3 символа?

Автор: profispb 24.3.2008, 16:06
Цитата(Alek86 @ 24.3.2008,  14:49)
profispb, интересно как ты учтешь пробел каждые 3 символа?

Я написал примерно, а нафиг в данной задачи их учитывать, если нам надо просто выбрать из текста цифры?

Если надо учитывать, то можно ещё одно условие ввести!)

Автор: Alek86 24.3.2008, 16:12
1. не ругайся, это не чат
2. посмотри внимательней на представленную строку HTML-кода
3. учитывать легче всего начиная с точки, потому препод был прав

Автор: profispb 24.3.2008, 16:54
Цитата(Alek86 @ 24.3.2008,  16:12)
1. не ругайся, это не чат
2. посмотри внимательней на представленную строку HTML-кода
3. учитывать легче всего начиная с точки, потому препод был прав

1. Я не ругался... а слегка выразился!))
2. Если исходить из пердставленной строки тогда, да.(В принципе вообще в лоб можно решить, но эт не интересно, эт интересно только когда тебе минут через 10 сдавать, а у тебя ещё ничего не написано) !
3. А при универсальности, лучше так как я предложил!)

Автор: Alek86 24.3.2008, 16:57
Цитата(profispb @  24.3.2008,  16:54 Найти цитируемый пост)
а слегка выразился!

Цитата(profispb @  24.3.2008,  14:45 Найти цитируемый пост)
<censored 8>...


при универсальности нужно регексп для таких задач применять
или вообще xml-парсер

Автор: profispb 24.3.2008, 17:05
Цитата(Alek86 @ 24.3.2008,  16:57)
Цитата(profispb @  24.3.2008,  16:54 Найти цитируемый пост)
а слегка выразился!

Цитата(profispb @  24.3.2008,  14:45 Найти цитируемый пост)
<censored 8>...


при универсальности нужно регексп для таких задач применять
или вообще xml-парсер

Я с тобой соглашусь, но ведь у человека обычная учебная задачка, смысла в xml-парсере нет!)))

Автор: kresh 24.3.2008, 18:26
Цитата(profispb @ 24.3.2008,  14:45)
Цитата(kresh @ 24.3.2008,  11:43)
тАК ПОДСЧИТАТЬ МЕСТО РАСПОЛОЖЕНИЕ ЧИСЛА ЭТО ПРОСТО, А ВОТ СДЕЛАТЬ ТАК ЧТОБ ЧИСЛО ИЗВЛЕКАЛОСЬ НЕ ЗАВАСИМО ОТ ЕГО РАСПОЛОЖЕНИЯ ВОТ ЭТО ВОПРОС!  пРЕПОД ГОВОРИТ ЧТО ТИПА НАДО ИСКАТЬ РАЗДЕЛИТЕЛЬ -ТОЧКУ И ОТ НЕЁ ДВИГАТЬСЯ ДАЛЬШЕ ИСПОЛЬЗУЯ ФУНКЦИИ ДЛЯ ИЗВЛЕЧЕНИЯ ЧИСЛОВЫХ ПОСЛЕДОВАТЕЛЬНОСТЕЙ,ЧТО ОНА ИМЕЛА ВВИДУ ВИГ ЕЁ ЗНАЕТ.

Я считаю что препод немного не прав!
Алгоритм решения такой:
1) Создать массив из цифр от 0 до 9
2) Читаем файл посимвольно
3) Далее делаем цикл и проверяем каждый символ.
В цикле надо ещё несколько условий
3.1) Если символ равен одному символу из массива цифр, то проверять следю стоящую и т.д. и заносить в буферную переменную, потом в нужную переменную.
3.2) Если символ равен одному символу из массива цифр, то занести в нужную переменную.
4) Вывести переменную на экран...

<censored 8>... как-то коряво, но суть понятна надеюсь.. просто щас под рукой компилятора нету.... так бы накорябал..)))

Весь прикол в том что данная страничка  с кодом HTML загружается из инета и данное числовое значение 
Код
CHF<td nowrap>1 швейцарский франк<td align
=right>2 128.76<tr><td align=centrer>

постоянно меняется! Народ я все таки непонял как все таки число 2128.76 передать полностью,а не почастям? smile 

Автор: Alek86 24.3.2008, 18:43
от точки влево надо искать все цифры, ( + каждый третий символ может быть пробелом). как найдется символ, что ни цифра ни пробел, закончить поиск
а вправо просто цифры.
получишь начало и конец числа

Автор: profispb 24.3.2008, 20:20
Цитата(Alek86 @ 24.3.2008,  18:43)
от точки влево надо искать все цифры, ( + каждый третий символ может быть пробелом). как найдется символ, что ни цифра ни пробел, закончить поиск
а вправо просто цифры.
получишь начало и конец числа

Мне даже стало интересно, что ты так к пробелам то привезался, если выбрать только цифры надо?)

Автор: inside_pointer 25.3.2008, 00:09
Цитата(profispb)

Я написал примерно, а нафиг в данной задачи их учитывать, если нам надо просто выбрать из текста цифры?

Там есть цифры которые не надо, в данном случае одна, а в любом случае их может быть больше, да ещё и с каждой стороны.

Цитата(kresh)

Народ я все таки непонял как все таки число 2128.76 передать полностью

Даже если ты захочешь передать сразу, всё равно у тебя получится тогда два числа из-за пробела 2 и 128.76

Можешь конечно посчитать количество цифр до точки в числе 128.76, а потом умножить первое число 2 на 10 в такой(посчитанной) степени и прибавить 2000 к 128.76, или степень реализовать через цикл с тремя шагами.

Автор: kresh 25.3.2008, 10:28
Цитата(inside_pointer @ 25.3.2008,  00:09)

Даже если ты захочешь передать сразу, всё равно у тебя получится тогда два числа из-за пробела 2 и 128.76Можешь конечно посчитать количество цифр до точки в числе 128.76, а потом умножить первое число 2 на 10 в такой(посчитанной) степени и прибавить 2000 к 128.76, или степень реализовать через цикл с тремя шагами.






Спасибо inside_pointer smile   за идею,я её начал развивать, для лучшего чтения числа я решил  преобразовать символьный массив в string и удалить из документа все пробелы.Но вот почему то при выполнение программы в том виде в которым вы писали программа не продвигается дальше точки!Сейчас думаю над этими вопросами!  smile  smile 

Автор: inside_pointer 25.3.2008, 11:40
Цитата(kresh)

Но вот почему то при выполнение программы в том виде в которым вы писали программа не продвигается дальше точки!

Может быть потому что это язык С а не С++, а может быть потому что у меня линукс а не виндовс.
В итоге получается double число слитное.

Автор: inside_pointer 25.3.2008, 21:14
На винде тоже всё работает.

Автор: creatorcode 26.3.2008, 00:07
Вот наваял. Вроде работает.  smile
Код

#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
#include <cmath>
void main()
{
    string tmp,s="CHF<td nowrap>1 швейцарский франк<td align=right>2 128.76<tr><td align=centrer>";
    string::const_iterator i=find(s.begin(),s.end(),'.'),j=i;
    for (--i;isdigit(*i) || isspace(*i);--i);
    for (++j;isdigit(*j);++j);
    remove_copy(i+1,j,back_inserter(tmp),' ');
    double result=atof(tmp.c_str());
    cout<<result<<endl;
}

Автор: kresh 26.3.2008, 01:23
Спасибо всем друзья за помощь!   smile 

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