2009-05-03 3 views
2

В моей книге прокомментировался комментарий о том, что люди вводят запятые в целые числа и испортили вашу программу, но она не уточняла. Это заставило меня задуматься, поэтому я попытался написать небольшой алгоритм, чтобы взять std :: string и удалить все нецелые символы. Этот код компилируется, но пропускает вывод. Почему нет ничего назначенного для новой строки? Если if (isdigit (fstring [i])) оценивается как истина адреса, указывающего на сохранение цифры?Удаление нецелых чисел из строки в C++

//little algorithm to take the non-integers out of a string 
//no idea on efficiency 

#include <iostream> 
#include <string> 

int main() 
{ 
    std::cout << "Enter a number with non-integer characters: "; 

    std::string fstring; 
    getline(std::cin, fstring); 

    std::string newstring; 

    int i = 0, x = 0; 

    while (i != fstring.length()) 
    { 
     if (isdigit(fstring[i])) 
     { 
      newstring[x] = fstring[i]; 
      i++; 
      x++; 
     } 
     else 
     { 
      i++; 
     } 
    } 

    std::cout << std::endl; 
    std::cout << newstring; 
    system("PAUSE"); 
} 

Вторичный вопрос, что, возможно, принадлежит в другом месте: как вы преобразовать строку в Int (или число с плавающей точкой)?

ответ

6

newstring имеет длину 0, поэтому newstring [x], где x = 0, фактически является незаконным. Вы должны добавить в строку с помощью: newstring.append (1, fstring [I])

Для вторичного вопрос, обратите внимание на atoi(), atof(), strtol (0, strtof() функции

+1

или вместо этого используйте оператор + =. – Tom

+0

Is .append() как .push_back() для векторов? Какие аргументы он принимает? Я хотел бы знать, почему работает мой код. – jkeys

+0

К сожалению, это не учтено: строки не похожи на сырые массивы? Адрес 0 не равен первому блоку памяти? – jkeys

0
.
  • строка числа с плавающей точкой:

Вы должны #include <cstdlib>

float strtof(const char *nptr, char **endptr); 

Например:

float f = strtof("3.4",NULL); 
  • строку в целое

Вы должны #include <cstdlib>

int atoi(const char *numPtr); 

Обратите внимание, что эти C - функции, а не C++, так что вам нужно использовать метод c_str() на станд :: string, чтобы получить C-строку.

const char* c_str () const; 
5

Строки похожи на массивы, но конструктор по умолчанию для строки создает пустую строку. Почему он должен выделять больше памяти, чем нужно? Даже если это так, не сказано, сколько, или если оно будет достаточно большим для отфильтрованной копии fstring. Я впечатлен тем, что он не падает.

Простая модификация будет меняться:

std::string newstring; 

к:

std::string newstring(fstring.length(), '\0') 

А после оных петли:

newstring.resize(x); 

Это гарантирует, что newstring будет иметь по крайней мере, достаточно места (возможно, больше) во время фильтрации и будет сокращено до уровня размер, когда вы закончите фильтрацию. Вы также можете быть заинтересованы в функции std::remove_copy_if в <algorithm>.

E.g.

struct isnotdigit { bool operator()(char c) { return !isdigit(c); } }; 

std::string newstring(fstring.length(), '\0'); 
std::string::iterator i = std::remove_copy_if(fstring.begin(), 
    fstring.end(), newstring.begin(), isnotdigit()); 
newstring.erase(i, newstring.end()); 

Как для преобразования строки в целое/поплавком, в дополнение к atoi, strtol, atof, strtof и т.д. функции уже упоминалось также можно сделать с помощью библиотеки iostream:

#include <sstream> 
std::string integer("23"); 
std::istringstream iss(integer); 
int result; 
iss >> result; 

std::string floatingpoint("3.14"); 
std::istringstream iss2(floatingpoint); 
double result2; 
iss2 >> result2; 

Кроме того, если вы знакомы с PRINTF семейства функций вы можете быть заинтересованы в scanf, sscanf

const char *s = "23"; 
int result; 
sscanf(s, "%d", &result); 
+0

+1 для remove_copy_if() –

+0

Я думаю, что remove_copy_if был использован неверно: не этот код удаляет все цифры, а не удаляет все не цифры? –

+0

Правильно, вы один на один –

1

Для удаления цифр:

fstring.erase(
     std::remove_if(fstring.begin(), fstring.end(), &isdigit), 
     fstring.end()); 

Чтобы преобразовать строку в целое/поплавок/...:

int n1 = boost::lexical_cast<int>("123"); 
float n2 = boost::lexical_cast<float>("123.456"); 
+0

Вопрос заключался в том, чтобы удалить цифры, поэтому может быть немного not1 (ptr_fun (isdigit)) в порядке. Плюс я должен явно использовать isdigit для int (*) (int), чтобы заставить его работать с алгоритмами, иначе это «неизвестный тип». –

+0

А, мне нужен был только актер, потому что я лениво использовал пространство имен std. Служит мне правильно. –

+0

знаю, что isdigit имеет некоторые опасные подводные камни. вы должны убедиться, что ваша строка содержит только символы до CHAR_MAX (не те, которые выходят за рамки/ближе к UCHAR_MAX, например, знак евро). В противном случае вы можете передать отрицательные числа isdigit, если char подписан. Обычно impls используют этот int для индексации массива, чтобы определить класс символов. поэтому отрицательные целые числа являются злыми. –

2

Расширение на ответ Shing Yip в:

Чтобы удалить нецифровые:

#include <iostream> 
#include <functional> 
#include <string> 
#include <algorithm> 

using namespace std; 

int main() { 
    string fstring; 
    getline(cin, fstring); 
    fstring.erase(
     remove_if(fstring.begin(), fstring.end(), 
      not1(ptr_fun(static_cast<int(*)(int)>(isdigit))) 
     ), 
     fstring.end() 
    ); 

    cout << fstring << "\n"; 
} 

Я не уверен, почему этот static_cast необходим. Я думаю, что что-то неоднозначно об isdigit без него. [Edit: Если вы не сделаете «используя патезрасе», то вам не нужно, так что это моя вина лениться писать пример кода.]

Это спорный вопрос, является ли это какой-либо проще, чем прокатки свой собственный цикл :

#include <iostream> 
#include <string> 

using namespace std; 

int main() { 
    string fstring, ins; 
    getline(cin, ins); 
    for (string::iterator it = ins.begin(); it != ins.end(); ++it) { 
     if (isdigit(*it)) fstring.push_back(*it); 
    } 
    cout << fstring << "\n"; 
} 

и C++ 0x будет copy_if, который был вытеснен в основном случайно, и просто реализовать:

#include <iostream> 
#include <string> 
#include <algorithm> 
#include <iterator> 

int main() { 
    std::string fstring, ins; 
    std::getline(std::cin, ins); 
    std::copy_if(ins.begin(), ins.end(), 
     std::back_inserter(fstring), isdigit); 
    std::cout << fstring << "\n"; 
} 

чтобы преобразовать в целое (или поплавок):

int i = boost::lexical_cast<int>(fstring); 

Или, если у вас нет подталкивания:

#include <sstream> 

int i = 0; 
std::stringstream(fstring) >> i; 

Обратите внимание, что вы должны инициализировать I, в противном случае он не будет установлен, если fstring пуст.

Смежные вопросы