Почему я не могу преобразовать это регулярное выражение в строку в целое или прямо в целое число? (C ++)

Я прочитал несколько сообщений StackExchange и других страниц о преобразовании строк в целые числа, но это не работает. Это последнее, что я попробовал:

if (infile.is_open())
{
while (getline (infile,line))
{

regex_match(line,matches,exp);

regex_match((string)matches[1], time0, exp_time);

buffer << time0[1];
str = buffer.str();

str.append("\0");cout << atoi(str.c_str()) << '\n';

last_match = matches[2];
buffer.str(string());
}
infile.close();
}

Я не могу думать ни о каких других способах. Я попробовал обычное преобразование в строку в char * в целое число. Я попытался преобразовать его в строку, а затем с помощью stoi () преобразовать его в целое число. Я попытался добавить к нему символ NULL («\ 0»), я тоже попытался добавить его в буфер. Я также попробовал atof () и stof (). Stoi () и stof () завершают работу программы. atoi () и atof () всегда возвращают 0, всегда.


Вот SSCCE, с проблемой признакам (atoi(str.c_str()) не должно быть 0):

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif

#include <iostream>
#include <fstream>
#include <string>
#include <regex>

#include <sstream>

using namespace std;int main(int argc, char* argv[])
{
regex exp("^(.+),(.+),.+,.+,(.+),.+,.+$");
regex exp_time("^(.+)-(.+)-(.+)");
smatch matches;
smatch time0;
string line;
ifstream infile(argv[1]);
string last_match;
stringstream buffer;
string str;int i = 0;

if (infile.is_open())
{
while (getline(infile, line))
{

regex_match(line, matches, exp);

regex_match((string)matches[1], time0, exp_time);

buffer << time0[1];
str = buffer.str();

str = time0[1].str();
str.append("\0");cout << atoi(str.c_str()) << " " << time0[1] << '\n';

last_match = matches[2];
buffer.str(string());
i++;
}
infile.close();
}

return 0;
}

На вход будет CSV-файл со следующими значениями:

1996-09-04,19.00,19.25,18.62,18.87,528000,0.79
1996-09-03,19.00,19.37,18.75,19.00,1012800,0.79
1996-08-30,19.87,20.12,19.37,19.62,913600,0.82
1996-08-29,20.87,21.12,19.75,19.75,1987200,0.82
1996-08-28,20.12,22.12,20.12,21.12,5193600,0.88
1996-08-27,19.75,20.37,19.75,20.12,1897600,0.84
1996-08-26,20.12,20.12,19.75,19.75,388800,0.82
1996-08-23,19.75,20.25,19.75,19.75,1024000,0.82
1996-08-22,18.62,20.00,18.25,19.87,1921600,0.83
1996-08-21,19.12,19.25,18.25,18.62,688000,0.78
1996-08-20,19.62,19.62,19.12,19.12,494400,0.80
1996-08-19,19.37,19.62,19.37,19.62,428800,0.82
1996-08-16,19.50,19.87,19.12,19.37,864000,0.81

Вы бы запустить программу с program.exe filename.csv

Вот более короткая программа с более очевидными проблемами:

1

Решение

Ваша проблема в этой строке:

regex_match((string)matches[1], time0, exp_time);

Вы не можете передать временную строку в качестве соответствия теме регулярного выражения, потому что содержимое строки все еще должно присутствовать при запросе результатов поиска. Результат (string)matches[1] уничтожается в конце текущего полного выражения (то есть в следующей точке с запятой); когда вы получите время для запросов time0[1] на следующей строке time0 match ссылается на строку, которая больше не существует, что является неопределенным поведением.

6

Другие решения

Давайте разберемся с этим на примере: вот что происходит в моей среде VS2012:

введите описание изображения здесь

Там есть ошибка в buffer << time0[1]; линия.

В этой строке я на самом деле называю станд :: ostream :: оператор<<
передавая его результат СТД :: match_results :: оператор [] который является ссылка на объект std :: sub_match.

Этот объект может быть преобразован в string_type (псевдоним basic_string используется для символов, на которые ссылается тип итератора), поскольку для него определено преобразование.

Итак, я делаю что-то:

buffer << (string with the contents of sub_match object).

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

введите описание изображения здесь

«первый«поле, которое является итератор к началу матча, пропал, отсутствует. Этот итератор является двунаправленный итератор, указывающий на вашу строку: так должно быть, что-то случилось с вашей строкой.

Если вы посмотрите, как (опять же, в среде VS2012) алгоритма regex_match функция определяется:

template<class _StTraits,
class _StAlloc,
class _Alloc,
class _Elem,
class _RxTraits> inline
bool regex_match(
const basic_string<_Elem, _StTraits, _StAlloc>& _Str, <--- take a look here
match_results<typename basic_string<_Elem, _StTraits, _StAlloc>::
const_iterator, _Alloc>& _Matches,
const basic_regex<_Elem, _RxTraits>& _Re,
regex_constants::match_flag_type _Flgs =
regex_constants::match_default)
{   // try to match regular expression to target text
return (_Regex_match(_Str.begin(), _Str.end(),
&_Matches, _Re, _Flgs, true));
}

Понятно, что принимает ссылка на const basic_string, его НЕ копировать его как-то, ни возиться с этим.

Вы можете симулировать то же поведение с помощью следующего кода:

std::string::iterator myFirstElement; // every random-access iterator is a bidirectional iterator

void takeAReference(std::string& mystring)
{
// Here mystring is valid!
myFirstElement = mystring.begin();
}int main(int argc, char* argv[])
{

takeAReference(string("hello dear"));

// Iterator is now NO MORE VALID! Try to inspect it / use it
....
}

и попробуй сам. На моей машине это точно не сработает, и даже если это сработает, вы можете быть уверены, что рано или поздно это вас разочарует.

Вот почему у вас странные результаты. Простым решением может быть просто расширить область видимости вашей строки:

int main(int argc, char* argv[])
{
regex exp("^(.+),(.+),.+,.+,(.+),.+,.+$");
regex exp_time("^(.+)-(.+)-(.+)");
smatch matches;
smatch time0;
string line;
ifstream infile("testfile.txt");
string last_match;
stringstream buffer;
string str;int i = 0;

if (infile.is_open())
{
while (getline(infile, line))
{

regex_match(line, matches, exp);

std::string first_date = (string)matches[1]; <--!!

regex_match(first_date, time0, exp_time);

buffer << time0[1];
str = buffer.str();

str = time0[1].str();
str.append("\0");

cout << atoi(str.c_str()) << " " << time0[1] << '\n';

last_match = matches[2];
buffer.str(string());
i++;
}
infile.close();
}

return 0;
}
3

Вы уверены, что ваше регулярное выражение соответствует тому, что вы хотите?

например, регулярное выражение "^(.+)-(.+)-(.+)$" будет соответствовать всей строке в вашем входном файле примера, как, например, он соответствует вся линия:

1996-09-04,19.00,19.25,18.62,18.87,528000,0.79

поскольку .+ части будут совпадать с чем угодно (вкл. — символы и т. д.).

Так что если вы хотите соответствовать просто 1996-09-04 тогда вы можете попробовать регулярное выражение \d{4}-\d{1,2}-\d{1,2} или что-то типа того. Вы можете попробовать регулярное выражение в этом онлайн-инструмент регулярных выражений

Также другой регулярное выражение ^(.+),(.+),.+,.+,(.+),.+,.+$ выглядит подозрительно для меня, действительно ли вы хотите соответствовать любой строка, которая имеет 6 запятых, по крайней мере 1 символ между ними? Помните, что . очень жадное регулярное выражение

ОБНОВИТЬ: Я действительно думаю, что ваш первый регулярный выражение слишком жадный, понимаете пример здесь

2

int atoi (const char * str);

Попробуйте использовать массив символов вместо string,

0

Я думаю, что принцип KISS может быть применен здесь, чтобы получить лучшее решение, чем использование регулярных выражений. Просто прочитайте в каждом поле, используя istream, Регулярное выражение является излишним ПО МОЕМУ МНЕНИЮ.

#include <iostream>
#include <string>
#include <fstream>
using namespace std;

struct date_t
{
int year, month, day;
};

struct data_t
{
date_t date;
float f1, f2, f3, f4;
int i;
float f5;
};

istream & operator>>(istream & in, date_t &date)
{
char d1, d2;  // dummy chars for the hyphens
return in >> date.year >> d1 >> date.month >> d2 >> date.day;
}

istream & operator>>(istream & in, data_t &data)
{
char d1, d2, d3, d4, d5, d6;  // dummy chars for the commas
return in >> data.date >> d1 >> data.f1 >> d2 >> data.f2 >> d3
>> data.f3 >> d4 >> data.f4 >> d5 >> data.i >> d6 >> data.f5;
}

ostream & operator<<(ostream & out, const date_t &date)
{
return out << date.year << '-' << date.month << '-' << date.day;
}

ostream & operator<<(ostream & out, const data_t &data)
{
return out << data.date << ',' << data.f1 << ',' << data.f2 << ','
<< data.f3 << ',' << data.f4 << ',' << data.i << ',' << data.f5;
}int main(int argc, char* argv[])
{
ifstream infile(argv[1]);

data_t data;
while(infile >> data) {
cout << "Here is the data: " << data << endl;
}

infile.close();

return 0;
}

Черт возьми, iostream тоже немного перебор. Вот решение C с использованием fscanf,

#include <stdio.h>
#include <stdio.h>

struct date_t
{
int year, month, day;
};

struct data_t
{
struct date_t date;
float f1, f2, f3, f4;
int i;
float f5;
};

int read_data(FILE *fid, struct data_t *data)
{
return fscanf(fid, "%d-%d-%d,%f,%f,%f,%f,%d,%f",
&(data->date.year), &(data->date.month), &(data->date.day),
&(data->f1), &(data->f2), &(data->f3), &(data->f4), &(data->i), &(data->f5));
}

int main(int argc, char* argv[])
{
FILE *fp = fopen(argv[1], "rt");

struct data_t data;

while(read_data(fp, &data) == 9) {
printf("Here is your data: %d-%02d-%02d,%.2f,%.2f,%.2f,%.2f,%d,%.2f\n",
data.date.year, data.date.month, data.date.day,
data.f1, data.f2, data.f3, data.f4, data.i, data.f5);
}

return 0;
}

Видите, насколько короче и легче понять это? scanf спецификатор формата может без труда захватить формат ваших данных, и это гораздо проще в использовании, чем регулярное выражение. Обратите внимание, что вам не нужно разбивать данные на токены, а затем анализировать каждый токен. Вы сразу получаете анализируемый числовой вывод.

-1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector