Извлечение значений из строки С++

У меня есть проблема, и я думаю, что решение может быть довольно простым, но я как бы застрял. У меня есть какой-то файл конфигурации, который я пытаюсь разобрать на С++, чтобы получить некоторые важные значения.

Это выглядит так:

информация size=32 bold=0 italic=0 unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0
common lineHeight =32 основание=27 масштабW=1024 масштабH=28 страниц=1 упаковано=0 alphaChnl=1
символов count=74
символов id=32 x= 837 y=15 width=3 height=1 xoffset=-1 yoffset=31 xadvance=8 page=0 chnl=15
char id=33 x=802 y=0 width=4 height =19 xoffset=2 yoffset=8 xadvance=8 page=0 chnl=15
char id=35 x=292 y=0 width=17 height=19 xoffset=0 yoffset=8 xadvance =16 page=0 chnl=15
char id=37 x=177 y=0 width=19 height=19 xoffset=-1 yoffset=8 xadvance=17 page=0 chnl=15
char id=38 x=216 y=0 width=18 height=19 xoffset=0 yoffset=8 xadvance=18 page=0 chnl=15

Информация, общие и символы являются базовыми/глобальными значениями. Каждая строка char должна быть сохранена в массиве (или векторе) структур с аналогичным форматом (x, y, height, offsetX, offsetY...)

Теперь я попробовал getline(), например, чтобы получить каждую строку одну за другой, а затем создать istringstream с этими строками, чтобы «искать» эти строки для нужных мне значений. Стоит отметить, что мне не нужны все эти значения, мне нужен способ просто сохранить то, что мне нужно для каждой строки.

Заранее спасибо за любую помощь здесь!


person puelo    schedule 12.08.2012    source источник


Ответы (3)


Каждая строка имеет префикс типа объекта.
Таким образом, ваш читатель должен прочитать первое слово, а затем решить, какой объект читать.

std::ifstream  file("data.txt");
std::string    type;
while(file >> type)
{
         if (type == "info")    { readInfo(file);}
    else if (type == "common")  { readCommon(file);}
    else if (type == "chars")   { readChars(file);}
    else if (type == "char")    { readChar(file);}
}

Для каждого типа объекта необходимо определить структуру для хранения данных.

// char id=32 x=837 y=15 width=3 height=1 xoffset=-1 yoffset=31 xadvance=8 page=0 chnl=15
struct CharData
{
    int   id;
    int   x;
    int   y;
    int   width;
    int   height;
    int   xoffset;
    int   yoffset;
    int   xadvance;
    int   page;
    int   chnl;
};

Теперь вам нужно определить метод для чтения данных. В C++ мы используем operator>> для чтения данных из потока.

std::istream& operator>>(std::istream& stream, CharData& data)
{
    // All the data is on one line.
    // So read the whole line (including the '\n')
    std::string        line;
    std::getline(stream, line);

    // convert the single line into a stream for parsing.
    // One line one object just makes it easier to handle errors this way.
    std::stringstream  linestream(line);

    // Assume the prefix type information has already been read (now looks like this)
    // id=32 x=837 y=15 width=3 height=1 xoffset=-1 yoffset=31 xadvance=8 page=0 chnl=15
    std::string   command;
    while(linestream >> command) // This reads one space separated command from the line.
    {
             if (command.substr(0,3) == "id=")        {data.id       = atoi(&command[3]);}
        else if (command.substr(0,2) == "x=")         {data.x        = atoi(&command[2]);}
        else if (command.substr(0,2) == "y=")         {data.y        = atoi(&command[2]);}
        else if (command.substr(0,6) == "width=")     {data.width    = atoi(&command[6]);}
        else if (command.substr(0,7) == "height=")    {data.height   = atoi(&command[7]);}
        else if (command.substr(0,8) == "xoffset=")   {data.xoffset  = atoi(&command[8]);}
        else if (command.substr(0,8) == "yoffset=")   {data.yoffset  = atoi(&command[8]);}
        else if (command.substr(0,9) == "xadvance=")  {data.xadvance = atoi(&command[9]);}
        else if (command.substr(0,5) == "page=")      {data.page     = atoi(&command[5]);}
        else if (command.substr(0,5) == "chnl=")      {data.chnl     = atoi(&command[5]);}
    }
    return stream;
}

Повторите процессы для других типов, которые вам нужно прочитать. Тогда запись команд чтения становится простой:

std::vector<CharData>    charVector;
void readChar(std::istream& stream)
{
    CharData     data;
    stream >> data;               // read the object from the stream
                                  // This uses the `operator>>` we just defined above.

    charVector.push_back(data);   // put the data item into a vector.
}

Повторите процессы для других типов.

person Martin York    schedule 12.08.2012
comment
разве оператор не должен читать только тип? остальные переменные должны быть прочитаны в зависимых от типа функциях - person Gir; 12.08.2012
comment
Незначительная очевидная опечатка: если я что-то неправильно истолковал, все экземпляры itoa выше действительно предназначены для atoi. - person Jerry Coffin; 13.08.2012
comment
Работает как шарм - нужно изменить одну вещь, кроме того, что заметил Джерри Коффин. Методам readChar нужен поток по ссылке, копирование запрещено: readChar(std::istream&stream) - person puelo; 13.08.2012

Там есть

important_value=str_from_getline.find(what_to_find);

Important_value является size_t и имеет начальную точку того, что вы ищете в строке getline().

person huseyin tugrul buyukisik    schedule 12.08.2012

Попробуйте использовать strtok или библиотеку регулярных выражений С++.

person Gir    schedule 12.08.2012
comment
Нет, не надо. strtok() - это мерзость C. В C++ есть гораздо лучшие методы. - person Martin York; 12.08.2012
comment
Ну и самое худшее, что он использует C-Strings. Затем он изменяет строку (поэтому это не настоящая функция). Затем это зависит от мутаций, чтобы продолжать работать каждый раз, когда он вызывается. - person Martin York; 12.08.2012
comment
См.: stackoverflow.com/questions/8705844/ - person Martin York; 12.08.2012