going through a string of characters and extracting the numbers? - c++

Given a string of characters, how can I go through it and assign all the numbers within that string into an integer variable, leaving out all other characters?
I want to do this task when there is a string of characters already read in through gets(), not when the input is read.

unsigned int get_num(const char* s) {
unsigned int value = 0;
for (; *s; ++s) {
if (isdigit(*s)) {
value *= 10;
value += (*s - '0');
}
}
return value;
}
Edit: Here is a safer version of the function.
It returns 0 if s is NULL or cannot be converted to a numeric value at all. It return UINT_MAX if the string represents a value larger than UINT_MAX.
#include <limits.h>
unsigned int safe_get_num(const char* s) {
unsigned int limit = UINT_MAX / 10;
unsigned int value = 0;
if (!s) {
return 0;
}
for (; *s; ++s) {
if (value < limit) {
if (isdigit(*s)) {
value *= 10;
value += (*s - '0');
}
}
else {
return UINT_MAX;
}
}
return value;
}

This is a simple C++ way to do that:
#include <iostream>
#include <sstream>
using namespace std;
int main(int argc, char* argv[]) {
istringstream is("string with 123 embedded 10 12 13 ints", istringstream::in);
int a;
while (1) {
is >> a;
while ( !is.eof() && (is.bad() || is.fail()) ) {
is.clear();
is.ignore(1);
is >> a;
}
if (is.eof()) {
break;
}
cout << "Extracted int: " << a << endl;
}
}

Look up the strtol function from the standard C library. It allows you to find the part of a character array that is a number, and points to the first character that isn't a number and stopped the parsing.

You can use sscanf: it works like scanf but on a string (char array).
sscanf might be overkill for what you want though, so you can also do this:
int getNum(char s[])
{
int ret = 0;
for ( int i = 0; s[i]; ++i )
if ( s[i] >= '0' && s[i] <= '9' )
ret = ret * 10 + (s[i] - '0');
return ret;
}

Related

(C++) String to Double converter is inaccurate and totally wrong with negative numbers. What am i doing wrong?

Our teacher gave us this exercise:
"Given a string like '-5,14' write a function that returns the float value of -5,14
I used double here just to test the precision, but it also didn't work with floats.
[also i'm from Europe, we use the comma instead of the dot. Oh also we aren't allowed to use the type string and bool, we have to "make" them like in C]
This is what i came up with, and it seems to work a little bit. Positive numbers are similar, but wrong, and given a negative number, the result is similar to 10 times the positive of the given number.
It should work like this:
I read the string into an array of characters;
I check if the first character is a minus. if so, subtract 1 from the number of integer figures because i will count them later starting from index 0;
I count the number of integer figures with a loop from the start of the array to the ',' character;
I count the number of decimal figures with a loop from after the ',' to the end of the string;
[Keep in mind for the next step that, following the ASCII table, the code for the character of a number is that number + 48]
I add to the result variable every integer figure multiplied by ten to the power of whatever place in the number it has.
I do the same for the deicmal values but with the negative exponent.
if the number was negative, i multiply the result with -1.
But for some reason it's not working properly. The lower the number is, the less accurate it is (given 4,5 the result is 9, but given 345,543 the result is 350,43)
#include <iostream>
#define EOS '\0'
#define DIM 100
#define TRUE 1
#define FALSE 0
void leggiN(char* c)
{
std::cout << "Insert a number: ";
std::cin >> c;
}
double stof(char* str)
{
double Result = 0;
double ascii_to_int = 48;
int i = 0;
int j = 0;
int IntegerDigits = 0;
int DecimalDigits = 0;
int CommaIndex;
int isNegative = FALSE;
if (str[0] == '-')
{
IntegerDigits = -1;
isNegative = TRUE;
}
while (str[i] != ',')
{
++IntegerDigits;
++i;
}
CommaIndex = i;
++i;
while (str[i] != EOS)
{
++DecimalDigits;
++i;
}
for (i = (CommaIndex - 1); i >= 0; --i)
{
Result += (str[i] - ascii_to_int) * (std::pow(10, j));
++j;
}
j = 0;
for (i = (CommaIndex + 1); str[i] != EOS; ++i)
{
Result += (str[i] - ascii_to_int) * (std::pow(10, -j));
++j;
}
if (isNegative == 1)
Result = Result * -1;
return Result;
}
int main()
{
char str[DIM];
leggiN(str);
std::cout << stof(str);
}
use j = 1 to start your second for loop. You are trying to raise 10 to the power of -0
j = 1;
for (i = (CommaIndex + 1); str[i] != EOS; ++i)
{
Result += (str[i] - ascii_to_int) * (std::pow(10, -j));
++j;
}
If your code return 9.0 when you enter "4,5", your problem has nothing to do with imprecision.
There are other problems in your code, I've tried to un it and got a SEGFAULT...
#include <iostream>
#define EOS '\0' // 0 being such a special value, there is no need to
// define a named constant for it.
#define DIM 100
#define TRUE 1 // the language defines boolean values, avoid defining
#define FALSE 0 // unnecessary named constants for something that already
// exists.
void leggiN(char* c)
{
std::cout << "Insert a number: ";
std::cin >> c; // Inserting from cin to a char* is a BIG no-no.
// some compilers won't even allow it, for good reasons
// i.e.: what is the length of the array pointed to?
}
double stof(char* str) // you are indicating that you may modify str?
{
double Result = 0;
double ascii_to_int = 48; // this is a terrible name.
int i = 0;
int j = 0;
int IntegerDigits = 0;
int DecimalDigits = 0;
int CommaIndex;
int isNegative = FALSE;
if (str[0] == '-') // is str a valid pointer? what happens if NULL ??
{
IntegerDigits = -1;
isNegative = TRUE;
// you fail to skip the sing character, should have ++i here.
}
while (str[i] != ',') // what happens if there is no ',' in the string?
{ // you should check for str[i] == 0.
++IntegerDigits;
++i;
}
CommaIndex = i;
++i;
while (str[i] != EOS)
{
++DecimalDigits; // why do you count decimal digits?
++i; // you do not use this result anyway...
}
for (i = (CommaIndex - 1); i >= 0; --i)
{
// what happens if you have non-digit characters? they participate
// in the conversion??
// you call std::pow(), but do not include <cmath> at the top of the file.
// isn't str[i] - '0' clearer ?
Result += (str[i] - ascii_to_int) * (std::pow(10, j));
++j;
}
j = 0;
for (i = (CommaIndex + 1); str[i] != EOS; ++i)
{
Result += (str[i] - ascii_to_int) * (std::pow(10, -j));
++j;
}
if (isNegative == 1) // you had defined constants fot this, but don't use them.
Result = Result * -1;
return Result;
}
int main()
{
char str[DIM];
leggiN(str);
std::cout << stof(str);
}
Here is one way to achieve what you want.
#include <iostream>
#include <string>
const char DECIMAL_POINT = ','; // we'll use a named constant here....
// usually, we'd have to check the locale
// for regional specific information.
// works like atod(), conversion stops at end of string of first illegal character.
double stof(const char* str) {
// check input, must be not null, not empty
if (!str || str[0] == 0)
return 0;
int i = 0;
bool isNegative = false;
// take care of leading sign
if (str[0] == '-' || str[0] == '+') {
isNegative = (str[0] == '-');
++i;
}
// convert integer part.
double result = 0;
while ('0' <= str[i] && str[i] <= '9') {
result = (result * 10) + (str[i] - '0');
++i;
}
// only do decimals if they are there.
if (str[i] != DECIMAL_POINT)
return (isNegative) ? -result : result;
++i; // skip decimal point
double decimals = 0;
double multiplier = .1;
while ('0' <= str[i] && str[i] <= '9') {
decimals += (str[i] - '0') * multiplier;
++i;
multiplier *= .1;
}
result += decimals;
return (isNegative) ? -result : result;
}
int main() {
// always use std::string to read strings from cin.
std::string str;
std::cout << "Insert a number: ";
std::cin >> str;
std::cout << "in: " << str << " out: " << stof(str.c_str()) << '\n';
return 0;
}

Return all codes - String

Assume that the value of a = 1, b = 2, c = 3, ... , z = 26. You are given a numeric string S. Write a program to return the list of all possible codes that can be generated from the given string.
For most of the cases this code works but it gives wrong output for inputs which have numbers greater than 26. For eg: 12345.
#include <iostream>
#include <string.h>
using namespace std;
using namespace std;
int atoi(char a)
{
int i=a-'0';
return i;
}
char itoa(int i)
{
char c='a'+i-1;
return c;
}
int getCodes(string input, string output[10000]) {
if(input.size()==0)
{
return 1;
}
if(input.size()==1)
{
output[0]=output[0]+itoa(atoi(input[0]));
return 1;
}
string result1[10000],result2[10000];
int size2;
int size1=getCodes(input.substr(1),result1);
if(input.size()>1)
{
if(atoi(input[0])*10+atoi(input[1])>10&&atoi(input[0])*10+atoi(input[1])<27)
{
size2=getCodes(input.substr(2),result2);
}
}
for(int i=0;i<size1;i++)
{
output[i]=itoa(atoi(input[0]))+result1[i];
}
for(int i=0;i<size2;i++)
{
output[i+size1]=itoa(atoi(input[0])*10+atoi(input[1]))+result2[i];
}
return size1+size2;
}
int main(){
string input;
cin >> input;
string output[10000];
int count = getCodes(input, output);
for(int i = 0; i < count && i < 10000; i++)
cout << output[i] << endl;
return 0;
}
if i give input 12345, the output is:
"
abcde
awde
lcde
l"
instead of :
"
abcde
awde
lcde"
i got it fellow members. i did not initialised the size2 variable to zero. also i didn't use >= operator.
int getCodes(string input, string output[10000]) {
if(input.size()==0)
{
output[0]="";
return 1;
}
if(input.size()==1)
{
output[0]=itoa(atoi(input[0]));
return 1;
}
string result1[10000],result2[10000];
int size2=0;
int size1=getCodes(input.substr(1),result1);
if(input.size()>1)
{
if(atoi(input[0])*10+atoi(input[1])>=10&&atoi(input[0])*10+atoi(input[1])<27)
{
size2=getCodes(input.substr(2),result2);
}
}
int k=0;
for(int i=0;i<size1;i++)
{
output[k++]=itoa(atoi(input[0]))+result1[i];
}
for(int i=0;i<size2;i++)
{
output[k++]=itoa(atoi(input[0])*10+atoi(input[1]))+result2[i];
}
return k;
}
this is the final code for getCodes function. Thanks everyone :)
You can do that more simply with something like this:
#include <utility>
#include <string>
#include <vector>
#include <iostream>
using namespace std;
void getCodesRec(unsigned int num, string& current, vector<string>& result)
{
// First and last chars for the codes
static constexpr char FIRST_CHAR = 'a';
static constexpr char LAST_CHAR = 'z';
if (num == 0)
{
// When there is no more number add the code to the results
result.push_back(current);
}
else
{
// Add chars to the existing code
unsigned int next = num;
unsigned int rem = next % 10;
unsigned int f = 1;
// While we have not gone over the max char number
// (in practice this loop will run twice at most for a-z letters)
while (next > 0 && rem <= (unsigned int)(LAST_CHAR - FIRST_CHAR) + 1)
{
next = next / 10;
if (rem != 0) // 0 does not have a replacement
{
// Add the corresponding char
current.insert(0, 1, FIRST_CHAR + char(rem - 1));
// Recursive call
getCodesRec(next, current, result);
// Remove the char
current.erase(0, 1);
}
// Add another number
f *= 10;
rem += f * (next % 10);
}
}
}
vector<string> getCodes(unsigned int num)
{
vector<string> result;
string current;
getCodesRec(num, current, result);
return result;
}
int main()
{
unsigned int num = 12345;
vector<string> codes = getCodes(12345);
cout << "Codes for " << num << endl;
for (string& code : codes)
{
cout << "* " << code << endl;
}
return 0;
}
Output:
Codes for 12345
* abcde
* lcde
* awde

Detecting if input is a string or an integer

Please tell me what is wrong in my approach.
#include <iostream>
#include <string>
using namespace std;
string datatype(string x) {
for (int k = 0; k < strlen(x.c_str());) {
for (int i = 0; i < 10; i++) {
char z = i;
if (x[k] == z) {
k++;
}
else {
return "string";
}
}
}
return "int";
}
int main() {
string inp;
cin >> inp;
cout << datatype(inp);
}
Whatever i enter, it always returns "string".
I have seen the other questions posted here but please tell me what is wrong in my approach.
The standard library has the isdigit function that tells you if the char is a digit.
Here you check that each char of your input is a digit, as soon as a character that is not a digit is found string is returned, else int.
For example 1234 returns int, sdf returns string.
string datatype(string str) {
for (unsigned char c : str) {
if (!isdigit(c)) {
return "string";
}
}
return "int";
}
Edit:
This solution also handles leading - and +. It will return int for -10 and +10 but returns string for +1+1 or -10+10.
string datatype(string str) {
if (str.size() == 1) {
return isdigit(str[0]) ? "int" : "string";
}
bool isInt = true;
for (int i = 1; i < str.size(); i++) {
isInt = isInt && isdigit(static_cast<unsigned char>(str[i]));
if (!isInt) {
break;
}
}
if (isInt) {
unsigned char c = str[0];
isInt = isInt && (c == '-' || c == '+' || isdigit(c));
}
return isInt ? "int" : "string";
}
First of all Include (cstring) as header since x.c_str is not in iostream and string. Then,
When you are doing char z=i; here you are not storing the character equivalent of i in z but the ascii value of i.
Next, You are returning string at the first mismatch between i and x[k]. You should return string if you cannot find a match with any of the possible 10 digits.
You can have a look at the modified code.
#include <iostream>
#include<cstring>
#include <string>
using namespace std;
string datatype(string x) {
for (int k = 0; k < strlen(x.c_str());k++) {
int flag=0;
for (int i = 0; i < 10; i++) {
// char z = i;
if ((x[k]-'0') == i || (k==0 && x[k]=='-')) {
flag=1;
break;
}
}
if(flag==0)
return "string";
}
return "int";
}
int main() {
string inp;
cin >> inp;
cout << datatype(inp);
}

Printing numbers from 'char array' how to make them numbers not digits

I have an expression, which is stored in a char array char equation[101];The input is via cin.getline();
I want to print all numbers from the expression, using a function void printAllNumbers(const char* equation)
for example: input : 24cd[*43-28/5*93}9(ks)
output:
24
43
28
5
93
9
How do I go about doing this: I go through the array, and if I find a digit, I print it. However, they come as digits, not as numbers.
void printAllNumbers(const char* equation){
for (int i=0; i < strlen(equation); i++){
if (equation[i]== '1' || equation[i]== '2' || equation[i]== '3' || equation[i]== '4'|| equation[i]== '5'|| equation[i]== '6'|| equation[i]== '7'|| equation[i]== '8'||equation[i]== '9')
cout << equation[i] << endl;
}
}
here some simplified variant using some old-fashioned c-style:
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <iostream>
int main() {
const int len = 101;
char s[len] = {'\0'};
std::cin.getline(s, len);
int i = 0;
while (i < len) {
char t[len] = {'\0'}; // here will the every next number be extracted
int j = -1;
while (isdigit(s[i]) && i < len && j < len) {
t[++j] = s[i++];
}
if (0 <= j) {
printf("%s\n", t); // just print the number as string. here would the conversion to int, unsisigned int or whatsoever take place
}
++i;
}
}
char t[] holds the string number. you can conver't it to number using the standard library functions.
When you're scanning through the string you can be in one of two states: scanning a number and scanning something that's not a number. When you're scanning a number, accumulate the digits; when you hit something that isn't a number, write out the accumulated value. Like this:
const char *str = "24cd[*43-28/5*93}9(ks)";
bool in_number = false;
int value;
while (*str) {
if (isdigit(*str)) {
if (!in_number) {
in_number = true;
value = *str - '0';
} else {
value += *str - '0';
}
} else if (in_number) {
std::cout << value << '\n';
in_number = false;
}
++str;
}
Try Somthing like this:
#include <sstream>
#include <iostream>
#include <cctype>
int main(int argc, char *argv[])
{
int j=0;
char equation[101]{'2','4','c','d','[','*','4','3','-','2','8','/','5','*','9','3','}','9','(','k','s',')'};
char number[j];
for (int i=0; i < sizeof(equation); i++)
{
if (isdigit(equation[i]))
{
number[j++] = equation[i];
}
}
std::cout << number << std::endl;
}

C++ make a string to int function

I usually program in python which has a string to integer converter built in but when i use C++ it doesn't seem to work so I decided to make my own.
this is what i made so far
C++:
int strtoint(string str)
{
int values [str.length()];
int return_value = 0;
for (int i=0; i < str.length(); ++i)
if(str.at(str.length()-1-i) == '1')
values[i] = 1;
else if(str.at(str.length()-1-i) == '2')
values[i] = 2;
else if(str.at(str.length()-1-i) == '3')
values[i] = 3;
else if(str.at(str.length()-1-i) == '4')
values[i] = 4;
else if(str.at(str.length()-1-i) == '5')
values[i] = 5;
else if(str.at(str.length()-1-i) == '6')
values[i] = 6;
else if(str.at(str.length()-1-i) == '7')
values[i] = 7;
else if(str.at(str.length()-1-i) == '8')
values[i] = 8;
else if(str.at(str.length()-1-i) == '9')
values[i] = 9;
for (int i=0; i < str.length(); ++i)
return_value += values[i]^(10*i);
return return_value;
}
I seem to get very weird answers like "12" returns 13 and "23" returns 11.
I know about stoi but I prefer to make my own so I can learn C++.
Three problems I can see on a quick look.
The first is that
int values [str.length()];
is not valid C++. It is using a feature from the 1999 C standard, which some C++ compilers support as an extension, but it is still not valid C++.
The second is lack of handling of 0s or errors (non-digit characters) in input.
The third is the statement
return_value += values[i]^(10*i);
^ is a bitwise XOR operator in C++. Not mathematical exponentiation.
A couple of other minor tips.
You can probably simplify your code a lot by using iterators.
Also, with all standard character sets, the roman digits are sequential, starting with '0'. So a simple way to convert a digit to the numeric value you want is digit - '0', which will convert '0' to 0, '1' to 1, .... '9' to 9.
In C++ I use std::stringstream to convert std::string to int. Simple example I found:
#include <sstream>
#include <iostream> //used for cout
int main()
{
std::string str = "12345";
std::istringstream ss(str);
int i;
ss >> i;
if (ss.fail())
{
// Error
}
else
{
std::cout << "The integer value is: " << i;
}
return 0;
}
Mistakes in your code you can find in #Peter answer.
You could simplify this a lot with the char conversion where you just subtract the value of '0' and the use of iterators, especially reverse iterators which make it simpler to calculate the value.
#include <cmath>
#include <string>
/*! Converts a char to an integer.
* #param c the character to convert
* #return the integer value [0-9] or -1 if not convertible
*/
int chartoint(const char c)
{
auto value = (c - '0');
if (value < 0 || value > 9)
{
value = -1;
}
return value;
}
/*! Converts a string to an integer.
* #param string the string to convert
* #return the converted integer value or 0 if not convertible
*/
int strtoint(const std::string& string)
{
auto integer = 0;
const auto begin = string.rbegin();
for (auto it = begin, end = string.rend(); it != end; ++it)
{
const auto current = chartoint(*it);
if (current == -1)
{
integer = 0;
break;
}
else
{
const auto factor = static_cast<int>(std::pow(10, (it - begin)));
integer += factor * current;
}
}
return integer;
}
Test run:
#include <cassert>
int _tmain(int argc, _TCHAR* argv[])
{
assert(strtoint("1") == 1);
assert(strtoint("1x") == 0);
assert(strtoint("12") == 12);
assert(strtoint("10") == 10);
return 0;
}