Различают 0-строку и не-0-строку

Мы все знаем, как преобразовать строку в число, т.е.

int str2num(const string& str)
{
stringstream is(str);
int result;
return is >> result ? result : 0;
};

Мой вопрос, который я хочу иметь возможность различать, когда строка не может быть преобразована в число, но не 0, например:

1.) "0" => 0
2.) "0dasd" => 0
3.) "" => 0
4.) "some string" => 0 but true
5.) "345" => 345

Я хочу быть в состоянии обнаружить случай (4).
Единственная идея, которая у меня есть, это поиск строки !! .find() или что-то..
Есть ли у stringstream какой-либо способ указать на эту ситуацию?


РЕДАКТИРОВАТЬ: некоторые уточнения:
Как num2str() Функция Я в порядке, когда разговор не удается и / или возвращается 0, функция также return 0 то есть (cases:1,2,3,4),
Но тогда в case 4Я хочу, чтобы иметь возможность обнаружить его внутри функции, так что, как вы сказали, бросьте err… или вернуть внеполосные данные, используя пару<> или вне переменной.

Или, чтобы быть более ясным, я хочу обнаружить:

если is >> num returns 0 (ex:"0","0.0","000", "0sad","asd0ss") действительно ли это НОЛЬ или это строка, которая не подлежит преобразованию в число I.E. различать 0-строку и не-0-строку

PS>
Моя путаница, вероятно, также возникает, потому что я не уверен, какие случаи 0-in-a-string интерпретируются как 0-num или just-string при преобразовании.
Неужели я запутал еще больше 🙂 или сейчас стало понятнее?
Я хочу реализовать что-то в духе семантики Perl.


РЕДАКТИРОВАТЬ 2: Спасибо за все примеры того, как точно вернуть данные за пределами, я действительно ценю их .. Я имею в виду действительно …
(Я, вероятно, буду использовать пару<>, не хочу использовать повышение или C++11 семантики пока нет).
Но меня больше интересовало «что такое струнный поток 0-string а также non-0-string а как обнаружить разницу?

0

Решение

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

template<typename F> int str2num(const string& str, F&& f) {
stringstream is(str);
int result;
if (is >> result) return result;
return f();
}
int str2num(const string& str) {
return str2num(str, [] -> int {
throw std::runtime_error("Parse failure!");
});
}
int str2num(const string& str, int def) {
return str2num(str, [=] {
return def;
});
}

В качестве магического значения по умолчанию выбрано 0 — возможно, 32 — нормальное значение по умолчанию для тех, кто хочет попытаться разобрать целое число. 0 также может быть значимым значением отдельно от ошибки разбора. Если вы хотите использовать значение по умолчанию, вам нужно, чтобы пользователь явно указал его, потому что ваша функция случайного ввода-вывода имеет без понятия что значимым может быть значение по умолчанию.

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

2

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

Довольно легко проверить, успешно ли вы что-то конвертировали. Различить ваш третий и четвертый случаи будет немного сложнее, хотя трактовать «нет данных для преобразования» как «успешно преобразованных что-то» не кажется (мне), хотя и имеет большой смысл. Если вы можете рассматривать случаи 3 и 4 как неудачные преобразования, а остальные — как успешные, это довольно просто: просто проверьте состояние потока после попытки преобразования:

#include <sstream>
#include <string>
#include <iostream>

int main(){
char const *inputs[] = { "0", "0dasd", "", "some string", "345"};

for (int i=0; i<5; i++) {
std::istringstream buf(inputs[i]);
int val;

if (buf>>val)
std::cout << "Converted : \"" << inputs[i] << "\" To: " << val << "\n";
else
std::cout << "Could not convert: \"" << inputs[i] << "\" To int\n";
}
return 0;
}

Который производит:

Converted : "0" To: 0
Converted : "0dasd" To: 0
Could not convert: "" To int
Could not convert: "some string" To int
Converted : "345" To: 345

Если вы действительно хотите относиться к случаю 3 как к успешному, я думаю, не потребовалось бы много времени, чтобы добавить специальную обработку для пустой строки, которая всегда успешно конвертируется.

2

Вам необходимо вернуть два бита информации: одно целое число с результатом преобразования и один флаг, указывающий успех или нет. Условие ошибки также можно обработать, вызвав исключение, но обычно внешние данные никогда не бывают «исключительными», и ошибки синтаксического анализа должны рассматриваться как обычный поток управления, а не как исключение.

Результат будет выглядеть примерно так:

template <typename T>
boost::optional<int> parse_as(std::string const & s)
{
if (s.empty()) { return T(); }

T result;

return std::istringstream(s) >> result ? result : boost::none;
}

Использование: auto n = parse_as<int>(str);и проверьте, установлен ли результат.


Альтернативное извлечение токена, требующее совпадения всей строки:

std::istringstream iss(s);

return iss >> result >> std::ws && iss.get() == EOF ? result : boost::none;
1

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

  1. Строка empty() и вы вернетесь 0,
  2. Преобразование прошло успешно, и вы возвращаете вале.
  3. Преобразование завершается неудачно, и вы делаете что-то, чтобы указать на ошибку, например, вы бросаете исключение.
0

Спасибо всем, кто прокомментировал.
Вот что я имел в виду:

#include <iostream>
#include <string>
#include <sstream>
#include <assert.h>
using namespace std;
#define pBool std::pair<bool,int>

pBool str2num(const string& str) {
istringstream is(str);
pBool rv(false,0);
if (str == "0E0") {//Zero but true
rv = std::make_pair(true,0);
} else {
is >> rv.second;//convert
//cout << "fail?:" << is.fail() << endl;
//logical XOR : !fail != !0?
if ( !is.fail() != (rv.second == 0) ) rv.first = true;
//      if (!is.fail() && rv.second != 0) rv.first = true;//successful conversion
//      if (is.fail() && rv.second == 0) rv.first = true;
};
return rv;
};

template<class T>
void dump_pair(T& p) {
cout << "Bool:" << p.first << endl;
cout << "Val :" << p.second << endl;
}

int main() {

cout << ">>0E0" << endl;
pBool rv1 = str2num("0E0");
dump_pair(rv1);

cout << ">>0" << endl;
pBool rv2 = str2num("0");
dump_pair(rv2);

cout << ">>0.0dsad" << endl;
pBool rv3 = str2num("0dsad");
dump_pair(rv3);

cout << ">>456ttt" << endl;
pBool rv4 = str2num("456ttt");
dump_pair(rv4);

cout << ">>adttt" << endl;
pBool rv5 = str2num("ad555ttt");
dump_pair(rv5);

return 0;
}

====OUTPUT====
>>0E0
Bool:1
Val :0
>>0
Bool:0
Val :0
>>0.0dsad
Bool:0
Val :0
>>456ttt
Bool:1
Val :456
>>adttt
Bool:1
Val :0
0
По вопросам рекламы [email protected]