Нуждаюсь в основной помощи, анализирующей строку в C++

C++ не является моим предпочтительным языком.

У меня есть файл, который содержит это:

e 225,370 35,75

Я хочу разделить e, 225, 370, 35 и 75 друг от друга в символ и ints, но я испытываю затруднения. Я пытался делать все, что я нашел онлайн и в моей книге C++, и тем не менее она не удается. Помогите.

У меня было бы более легкое время, делая это в Java.

14
задан bmargulies 2 February 2010 в 02:56
поделиться

7 ответов

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
        ifstream f("a.txt"); // check for errors.

        char ch,dummy;
        int i1,i2,i3,i4;

        f>>ch>>i1>>dummy>>i2>>i3>>dummy>>i4;

        cout<<ch<<endl<<i1<<endl<<i2<<endl<<i3<<endl<<i4<<endl;

        return 0;
}
-2
ответ дан 1 December 2019 в 12:13
поделиться

Если у вас есть контроль над форматом, то будет (слегка) легче читать, если вы уберёте запятые, и просто введете

e 225 370 35 75

С этим форматом код Пуаты_ для чтения данных будет работать [отредактировать: он с тех пор обновил свой код, чтобы он явно читал и пропускал запятые]. В противном случае, вам нужно будет явно пропустить запятые:

.
char ingore1, ignore2;
char ch;
int i[4];

file >> ch >> i[0] >> ignore1 >> i[1] >> i[2] >> ignore2 >> i[3];

[Редактирование: если у вас паранойя или вам действительно необходимо проверить ваш вход, на этом этапе вы можете проверить, что игнорирует1 и игнорирует2 содержат запятые. ]

Однако, в большинстве случаев данные, вероятно, связаны, поэтому Вы захотите прочитать целую строку в одну структуру (или класс):

struct data { 
    char ch;
    int i[4];

    std::istream &operator>>(std::istream &is, data &d) { 
        char ignore1, ignore2;
        return is >> ch >> i[0] >> ignore1 >> i[1] >> i[2] >> ignore2 >> i[3];
    }
};

Сделав это, Вы можете прочитать весь объект data одновременно:

std::ifstream infile("my data file.txt");
data d;

infile >> d;

Или, если у Вас есть целый файл, полный этих данных, Вы можете прочитать их все в вектор:

std::vector<data> d;

std::copy(std::istream_iterator<data>(infile), 
    std::istream_iterator<data>(),
    std::back_inserter(d));
4
ответ дан 1 December 2019 в 12:13
поделиться

Если вы хотите использовать старомодный C Runtime

FILE * pf = fopen(filename, "r");
char e;
int  a, b, c, d;
int ii = fscanf(pf, "%c %d,%d %d,%d", &e, &a, &b, &c, &d);
if (ii < 5) 
   printf("problem in the input file");
fclose (pf);

Редактировать: добавлена ​​проверка ошибок на основе комментариев из DreamLax

3
ответ дан 1 December 2019 в 12:13
поделиться

Библиотека панели инструментов C ++ (СТРТК) имеет следующее решение вашей проблемы:

int main()
{ 
   std::string data("e 225,370 35,75");
   char c1;
   int i1,i2,i3,i4;
   strtk::parse(data,", ",c1,i1,i2,i3,i4);
   return 0;
}

больше примеров можно найти здесь

13
ответ дан 1 December 2019 в 12:13
поделиться

Если вы делаете это в C++, вы (почти наверняка) не должны использовать что-то вроде:

data *primary = new data[primarypcs]();

Вместо этого вы должны использовать что-то вроде:

struct data {
    std::string filename;
    std::string size;
};

std::vector<data> primary(primarypcs);

В этом случае вы, как правило, можете управлять памятью гораздо проще: определите вектор в области, где он необходим, и когда он выходит из области, память будет освобождена автоматически.

Использование массива new (например, new x [y] ) в C++ - это то, без чего вам лучше обойтись. Когда-то (15 лет назад или около того) это был почти единственный доступный инструмент, так что его (обиды) использование было почти неизбежным - но этот день уже давно, и это было, наконец, 10 лет, так как был действительно хороший повод использовать его.

Поскольку неизбежно есть комментарий о «кроме как в реализации чего-то вроде вектора», я отмечу, что нет, даже когда вы реализуете вектор, вы не используете новый массив - вы (косвенно, через распределитель) используете :: оператор new для выделения необработанной памяти, размещение нового для создания объектов в этой памяти, и явные вызовы dtor для уничтожения объектов.

-121--3909770-

Как говорили другие, в показанном фрагменте есть две явно неправильные вещи:

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

Ваш вызов memset () может быть упрощен и исправлен с помощью:

memset(primary, 0, primarypcs * sizeof *primary);

Существует еще одна тонкая проблема с вашим кодом: стандарт C не гарантирует, что все биты-ноль является константой нулевого указателя (т.е. NULL), поэтому memset () не является правильным способом установить указатель на NULL . Портативный способ сделать то, что вы хотите сделать:

size_t i;
for (i=0; i < primarypcs; ++i) {
    primary[i].filename = NULL;
    primary[i].size = NULL;
}

Чтобы выделить память для имя файла и размер , это зависит от того, что вы хотите. Предположим, что имя файла требует n байт, а размер - m . Затем ваш цикл меняется на что-то подобное:

size_t i;
for (i=0; i < primarypcs; ++i) {
    size_t n, m;
    /* get the values of n and m */
    primary[i].filename = malloc(n * sizeof *primary[i].filename);
    primary[i].size = malloc(m * sizeof *primary[i].size);
}

Вы можете опустить умножение на sizeof * primary [i] .filename и sizeof * primary [i] .size , если хотите: C гарантирует, что sizeof (char) будет 1. Я написал выше для полноты и для случая, когда имя файла и размер изменить типы.

Также обратите внимание, что если filename является последовательностью длины k , то для него необходимы (k + 1) байт из-за завершения 0 (так что n = = k + 1 выше).

Если бы я предположил, вы хотите, чтобы size сохранял длину соответствующего имени файла ? В этом случае size должен быть не char * , а size _ t . Но поскольку я не знаю, как вы планируете использовать имя файла и размер , я не уверен.

Проверьте возвращаемое значение malloc () . Возвращает значение NULL для ошибки. Я опустил чек из вышеуказанного кода для простоты.

Ваша публикация также помечена как C++, поэтому, если вы хотите использовать C++, также доступно решение на C++.

-121--3909771-

Предполагая, что вы прочитали данные в строки...

  1. strchr подобен String.index.
  2. strtol подобен Integer.parseInt ()

Что еще нужно?

2
ответ дан 1 December 2019 в 12:13
поделиться

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

#include <iostream>
#include <boost/tokenizer.hpp>
#include <string>
#include <vector>

using namespace std;

...

typedef boost::tokenizer<boost::char_separator<char> > tokenizer;

string teststring("e 225,370 35,75");
boost::char_separator<char> separators(", ");
tokenizer tokens(teststring, separators);
vector<string> substrings;
for (tokenizer::iterator iter = tokens.begin(); iter != tokens.end(); ++iter)
{
    substrings.push_back(*iter);
}

и, вуаля, у вас все ваши подстроки в аккуратном векторе. CHAR находится в подставках [0] как std :: string, а следующие значения int находятся в подстрадавших значениях [1], а те, которые следуют, также как std :: string. Вам нужно будет преобразовать их в целочисленные значения. Для этого я предлагаю вам посмотреть на StringStream.

2
ответ дан 1 December 2019 в 12:13
поделиться
#include <fstream>

/* ... */

ifstream file;
file.open("yourfile.txt");
char c, dummy;
int i[4];
file >> c >> i[0] >> dummy >> i[1] >> i[2] >> dummy >> i[3];
file.close();
2
ответ дан 1 December 2019 в 12:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: