C++ simple string parsing and save to ints - c++

I have a string that look like this,
x:12812Y:121Z:1292
where there is always "X:","Y:", and "Z:"
I need to convert the numerals following each letter into a int variable, thus
int x = 12812
int y = 121
int y = 1292
Is there a way to do it?
Thanks!

Yes there is a way to do it:
Read two characters (the X: part), then read an integer. Repeat two more times.
If the "string" is in a file, I first recommend you read the whole line from the file into an std::string (using e.g. std::getline), then use std::istringstream to extract the data of each line.
If the order of the data is not fixe (e.g. X may not always be first) then check the first character to see what data the number is.
If the order is always fixed and the same, you can also store the number in an array or a vector.

using standard scanf is as simple as this:
#include<cstdio>
int main() {
int x, y, z;
char xx, yy, zz;
scanf("%c:%d%c:%d%c:%d", &xx, &x, &yy, &y, &zz, &z);
printf("%d %d %d\n", x, y, z);
return 0;
}

If the order and format is always fixed you could do something like this:
string str="x:12812Y:121Z:1292";//you might want to convert this to uppercase first
string xword,yword,zword;
istringstream ss(&str[1]);//put the string read in to string stream, jump the first x
//you may want to this in a loop
::getline(ss,xword,'Y');//will getthe x part,something like :12812
::getline(ss,yword,'Z');//get the y part, the y will not be read here, something like :121
::getline(ss,zword,'X');//get the z part
xword.erase(0,1);//remove the leading colon
yword.erase(0,1);//remove the leading colon
zword.erase(0,1);//remove the leading colon
// convert the string to int

Try this:
#include<iostream>
#include<sstream>
#include<string>
int main()
{
std::string str = "x:12812Y:121Z:1292";
std::string::size_type sz;
std::stringstream ss(str);
char tmp;
int x, y, z;
ss>>tmp;
ss>>tmp;
ss>>x;
ss>>tmp;
ss>>tmp;
ss>>y;
ss>>tmp;
ss>>tmp;
ss>>z;
std::cout<<"x:"<<x<<"\n";
std::cout<<"y:"<<y<<"\n";
std::cout<<"z:"<<z<<"\n";
return 0;
}
Output:
x:12812
y:121
z:1292

Some things can be done surprisingly elegantly without relying on a library.
This code demonstrates using the next_int function. next_int only takes up 9 lines -- the rest of the code demonstrates use with wide-character C-string, a char C-string and a std::string (through a C-string from std::string::c_str()).
#include <iostream>
#include <string>
// next_int parses a non-negative decimal integer value
// beginning at or after the passed string pointer.
// The pointer is incremented to point to the character
// which follows the parsed digits.
// If no digits follow the passed pointer, a value of
// zero is returned and the pointer is advanced to the
// string's terminating nul.
template <typename C>
inline int next_int(const C* &p) {
while(*p && (*p < C('0') || *p > C('9'))) { ++p; }
int val = 0;
while(*p >= C('0') && *p <= C('9')) {
val = val * 10 + *(p++) - C('0');
}
return val;
}
int main() {
const auto* pws = L"x:12812Y:121Z:1292";;
int x = next_int(pws);
int y = next_int(pws);
int z = next_int(pws);
std::cout << "(" << sizeof(*pws) << " Wide String) x: " << x << " y: " << y << " z: " << z << '\n';
const char* pcs = "54321,891011,0,1";
std::cout << "\n* char String\n";
for(int index=0; *pcs; ++index) {
const int value = next_int(pcs);
std::cout << " " << index << ": " << value << '\n';
}
// This example shows what happens when no digits follow the pointer
// passed to next_int. Because no digits appear in the characters
// following the final "10", the last call to next_int returns 0.
// next_int could be modified to unambiguously enumerate arbitrarily-sized
// sets of numbers, possibly by returning a magic number (like -1) if
// val was never updated by a digit, or adding a second scan, advancing
// p to the next digit or nul character, thus skipping the phantom
// parse at the end.
std::string nums = "Flight 552 to Paris cost me $400 1-way and lasted 10 hours";
const auto* pstr = nums.c_str();
std::cout << "\n* char String from std::string\n";
std::cout << " The extra 0 at the end comes from passing next_int a string containing no digits\n";
for(int index=0; *pstr; ++index) {
const int value = next_int(pstr);
std::cout << index << ": " << value << '\n';
}
}
This is the output:
(2 Wide String) x: 12812 y: 121 z: 1292
* char String
0: 54321
1: 891011
2: 0
3: 1
* char String from std::string
The extra 0 at the end comes from passing next_int a string containing no digits
0: 552
1: 400
2: 1
3: 10
4: 0

Assuming that keys are case-sensitive letters, values are always integers and relationship between key and value is important, but order of key/value pairs is not.
#include <string>
#include <sstream>
#include <iostream>
int main()
{
std::istringstream ss("x:12812Y:121Z:1292");
int x, Y, Z;
while (!ss.eof())
{
char tag, delim;
int val;
ss >> tag >> delim >> val;
switch(tag)
{
case 'x': x = val; break;
case 'Y': Y = val; break;
case 'Z': Z = val; break;
}
}
std::cout << "parsed: x=" << x << " Y=" << Y << " Z=" << Z << std::endl;
return 0;
},

Related

Code to separate the whole part and decimal part

Screenshot of the outputs i got for the codeHow to code to separate the whole part and decimal part
I wrote this code but it gives different values at times. I don't know why?
#include <iostream>
using namespace std;
int main()
{
float f, a, b;
int x, y, c;
cout << "enter the float value" << endl; cin >> f;
x = (int)f; cout << "before " << x;
a = b = f;
c = 1;
while (b != int(a))
{
b = b * 10;
a = a * 10;
c = c * 10;
}
y = (f * c) - (x * c);
cout << "after " << y;
}
enter the float value
22.47
before 22 after 46
user#user:~/cpp$ ./a.out
enter the float value
2234.127
before 2234 after 126
user#user:~/cpp$ ./a.out
enter the float value
22.335
before 22 after 334
user#user:~/cpp$ ./a.out
enter the float value
222.88
before 222 after 88
these are a few values i tried.
How to code to separate the whole part and decimal part?
I assume that you want to only represent the floating value into non-decimals part and decimals part. In that case, take the user input as an std::string, and do as follows. I hope the comments will get you through the code:
(See live example)
#include <iostream>
#include <string>
#include <cstddef> // std::size_t
int main()
{
std::cout << "enter the float value\n";
std::string strInput; std::cin >> strInput; // take the user input as std::string
std::size_t pos{ 0 };
// find the position of charector decimal point('.') using std::string::find
pos = strInput.find(".", pos);
// if the decimal point is found in the user input: x = substring starting from 0 to pos of user input.
const std::string x = pos != std::string::npos ? strInput.substr(0, pos) : strInput;
// if the decimal point is found in the user input: y = substring starting from pos + 1 to end of user input.
const std::string y = pos != std::string::npos ? strInput.substr(pos + 1) : std::string{ "" };
std::cout << "before " << x << " after " << y << '\n';
return 0;
}
sample input:
enter the float value
0123.04560
Output:
before 0123 after 04560
PS: However, like in the example given above, having zero before the separated decimal parts(both 0123 and 04560) might be unwanted. In that case, use any of the standard functions to convert them back to integers or remove zeros from from the beginning using erase-remove idiom.

What is the best way to convert unsigned integers to their octal representations and vice versa in C++?

Currently I'm using while loops:
std::string to_octal(unsigned int num)
{
int place = 1, remainder, octal = 0;
while (num != 0)
{
remainder = num % 8;
decimal /= 8;
octal += remainder * place;
place *= 10;
}
return std::to_string(octal);
}
unsigned int to_num(std::string octal)
{
unsigned int octal_n = std::stoi(octal);
int place = 1, remainder, num = 0;
while (num != 0)
{
remainder = octal_n % 10;
octal_n /= 10;
num += remainder * place;
place *= 8;
}
return num;
}
Which seems inefficient. Is there a better way to do this?
There is no such thing as decimal unsigned int, hexadecimal unsigned int or octal unsigned int. There is only one unsigned int. There is a difference only when you want to print an object of that type to the terminal or a file. From that point of view, the function
unsigned int decimal_to_octal(unsigned int decimal);
does not make sense at all. It makes sense to use:
struct decimal_tag {};
struct hexadecimal_tag {};
struct octal_tag {};
// Return a string that represents the number in decimal form
std::string to_string(unsigned int number, decimal_tag);
// Return a string that represents the number in hexadecimal form
std::string to_string(unsigned int number, hexadecimal_tag);
// Return a string that represents the number in octal form
std::string to_string(unsigned int number, octal_tag);
and their counterparts.
// Extract an unsigned number from the string that has decimal representation
unsigned int to_number(std::string const& s, decimal_tag);
// Extract an unsigned number from the string that has hexadecimal representation
unsigned int to_number(std::string const& s, hexadecimal_tag);
// Extract an unsigned number from the string that has octal representation
unsigned int to_number(std::string const& s, octal_tag);
Here's demonstrative program:
#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>
struct decimal_tag {};
struct hexadecimal_tag {};
struct octal_tag {};
// Return a string that represents the number in decimal form
std::string to_string(unsigned int number, decimal_tag)
{
std::ostringstream str;
str << std::dec << number;
return str.str();
}
// Return a string that represents the number in hexadecimal form
std::string to_string(unsigned int number, hexadecimal_tag)
{
std::ostringstream str;
str << std::hex << number;
return str.str();
}
// Return a string that represents the number in octal form
std::string to_string(unsigned int number, octal_tag)
{
std::ostringstream str;
str << std::oct << number;
return str.str();
}
// Extract an unsigned number from the string that has decimal representation
unsigned int to_number(std::string const& s, decimal_tag)
{
std::istringstream str(s);
unsigned int number;
str >> std::dec >> number;
return number;
}
// Extract an unsigned number from the string that has hexadecimal representation
unsigned int to_number(std::string const& s, hexadecimal_tag)
{
std::istringstream str(s);
unsigned int number;
str >> std::hex >> number;
return number;
}
// Extract an unsigned number from the string that has octal representation
unsigned int to_number(std::string const& s, octal_tag)
{
std::istringstream str(s);
unsigned int number;
str >> std::oct >> number;
return number;
}
int main()
{
unsigned int n = 200;
std::cout << "200 in decimal: " << to_string(n, decimal_tag()) << std::endl;
std::cout << "200 in hexadecimal: " << to_string(n, hexadecimal_tag()) << std::endl;
std::cout << "200 in octal: " << to_string(n, octal_tag()) << std::endl;
std::cout << "Number from decimal form (200): " << to_number("200", decimal_tag()) << std::endl;
std::cout << "Number from hexadcimal form (c8): " << to_number("c8", hexadecimal_tag()) << std::endl;
std::cout << "Number from octal form (310): " << to_number("310", octal_tag()) << std::endl;
}
and its output:
200 in decimal: 200
200 in hexadecimal: c8
200 in octal: 310
Number from decimal form (200): 200
Number from hexadcimal form (c8): 200
Number from octal form (310): 200
Printing numbers in different bases:
#include <iostream>
int main () {
int n = 123;
std::cout << std::dec << n << '\n';
std::cout << std::hex << n << '\n';
std::cout << std::oct << n << '\n';
return 0;
}
This function is 5x faster than #R Sahu's solution in debug compile, and 11x faster in -O2 optimized compile. It also works for any size unsigned int.
Permission granted for all manner of use.
#include <limits>
// Efficient conversion from any unsigned int type to an octal C
// string. Argument must be unsigned, but may be ANY unsigned from
// char to long long. Return value points to a NUL-terminated string
// in the buffer. Single-threaded applications are supported with an
// internal buffer and can ignore this detail. Multi-threaded
// programs must pass in their own buffer of at least the given size,
// which will be big enough to handle any octal.
template<typename T> const char* to_oct( T t, char* pcBuf = nullptr ) {
static_assert( ! std::numeric_limits<T>::is_signed,
"only works for unsigned types" );
// Each byte can add no more than 3 digits to the string. +1 for NUL.
static char cBuf[ sizeof( T ) * 3 + 1 ];
// Allow single-threaded callers to skip buffer argument.
if ( ! pcBuf )
pcBuf = cBuf;
// Move to the end of the buffer and write a terminator.
pcBuf += sizeof( T ) / sizeof( char ) * 3;
*pcBuf = '\0';
if ( t )
// Move right to left, outputting LSD, until we have no more
// to output. The size of our argument dictates the maximum
// number of loops, and our buffer is big enough to hold even
// the maximum result.
while ( t ) {
*(--pcBuf) = '0' + t % 8;
t >>= 3;
}
else
// Above loop would produce no output for 0, so handle as special case.
*(--pcBuf) = '0';
return pcBuf;
}
And of course the old C method is still working in C++: use %o Format specifier.
printf("%o", n);
use sprintf if you want it in a string (ok, that means you have to care of memory allocation to store the result, which is a drawback compared to std::oct).

atoi() Not Working with std::string::substr()

This is a snippet of my code:
#include <iostream>
#include <fstream>
#include <string>
#include <stdlib.h> // atoi()
int main() {
std::string line;
std::ifstream numbers("numbertest.txt");
if (numbers.is_open()) {
while (std::getline(numbers, line)) {
for (int i = 0; i < line.length() - 4; i++) {
for (int n = 0; n < 5; n++) {
std::cout << atoi((line.substr(i, 5)[n]).c_str());
}
I want to operate with numbers in groups of 5, from a file. Why is atoi() not working here? It says "expression must have class type" under the second parentheses on the atoi line.
line.substr(i, 5) creates a temporary std::string containing 5 characters in line from position i
std::string foo = "hello world";
int i = 2;
std::cout << foo.substr(2, 5) << '\n';
would print "llo wo".
The [n] operator returns the nth character of the substring, which is of type char, you are then calling .c_str() on that character rather than on the substring.
You can avoid the .c_str() entirely by using std::stoi, e.g.
std::cout << "line.substr(i, 5) = " << line.substr(i, 5) << '\n';
std::cout << std::stoi(line.substr(i, 5));
aoti and stoi both take a string representation of a number as their input and return the numeric value. For example:
std::string input = "123a";
// std::cout << input * 10 << '\n'; // illegal: input is a string, not a number.
int i = std::stoi(input); // converts to integer representation, i.e. 123
std::cout << i * 10 << '\n'; // outputs 1230
----- EDIT -----
You're actually asking all the wrong questions. What you want to do is take an input pattern and output all of the patterns of 5 characters in it.
Example input: "1020304050"
Example output: 10203 02030 20304 03040 30405 04050
You don't need to convert these to numbers to output them, you can just output the characters. The problem with your original code wasn't the conversion it was the incorrect sequence of operators.
std::substring is expensive, it has to create a new, temporary string, copy characters from the original into it, and then return it, and it does it for every call.
The following should achieve what you're trying to do:
while (std::getline(numbers, line)) {
for (size_t i = 0; i < line.length() - 4; i++) {
for (size_t n = 0; n < 5; n++) {
std::cout << line[i + n];
}
std::cout << '\n';
}
}
If you really want to invoke substr, you could also implement this as
while (std::getline(numbers, line)) {
for (size_t i = 0; i < line.length() - 4; i++) {
std::cout << line.substr(i, 5) << '\n';
}
}
Here's a working demonstration: http://ideone.com/mXv2z5
Try atoi( line.substr(i,5).c_str() )
Or if you want for each character
std::cout << ((line.substr(i, 5)[n]) - '0');
Or even better
std::cout << (line[i+n]) - '0');
Note that: atoi is not ascii to integer. It converts a ctype string to number. For a single character, this conversion should be done using arithmetic or lookup table.
Also there is no point converting characters to integer and then print it (back to chacters). You should better print digit character itself.
Moreover in C++, I would prefer to use stringstream instead or atoi. On C++11 there are even more advanced solutions like sto*.

Finding if a string contains a string and manipulating attached numbers

Say as part of input, a user inputted nrt:x to tell the program to calculate the nth root of x. If I wanted to send n and x to another method to simplify the nth root, I was thinking I could use std::string::find to look for "rt:". If find returns true, I then need to send n and x to another method, but how could I do that after "rt:" is found? For example, user inputs 7rt:3. Find would return true for "rt:", how could I then send 3 and 7 to another method?
if(std::string::find(rt:)) {
//manipulate numbers before/after rt: from user input
if(result will be an int) {
nthRoot(double n, double x);
}
If(result will not be an int) {
nthRootSimplify(double n, double x);
}
}
void nthRoot(double x, double n){
double nthRootSol = pow(x, double(1 / n));
}
edit: Code I have written as a solution with your guy's help. Any advice would be great. I see myself running into problems if "n" or "z" are longer than 1 int.
void findNthRoot(string x) {
if(x.find("rt:") != string::npos) {
unsigned position = x.find("rt:");
cout << position << endl;
double n = position - 1;
cout << n << endl;
double z = position + 3;
cout << z << endl;
string str1 = x.substr(n, 1);
string str2 = x.substr(z);
cout << str1 << endl;
cout << str2 << endl;
}
}
int main() {
findNthRoot("2 - 1+3rt:4");
return 0;
}
output is:
7
6
10
3
4
with the most important being that "3" and "4" are the values of str1 and str2
If you are assuming that input will always begin with n and end with the number under the radical, you can use std::string::front() to access the first element and std::string::back() to access the last element.
find would not return true. Such a find would be pretty damn useless. The real std::string::find returns the position of the found string.
Knowing the position, you can now separate your string into the "before" and "after" part using std::string::substr.

How to use string.substr() function?

I want to make a program that will read some number in string format and output it like this: if the number is 12345 it should then output 12 23 34 45 . I tried using the substr() function from the c++ string library, but it gives me strange results - it outputs 1 23 345 45 instead of the expected result. Why ?
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
int main(void)
{
string a;
cin >> a;
string b;
int c;
for(int i=0;i<a.size()-1;++i)
{
b = a.substr(i,i+1);
c = atoi(b.c_str());
cout << c << " ";
}
cout << endl;
return 0;
}
If I am correct, the second parameter of substr() should be the length of the substring. How about
b = a.substr(i,2);
?
As shown here, the second argument to substr is the length, not the ending position:
string substr ( size_t pos = 0, size_t n = npos ) const;
Generate substring
Returns a string object with its contents initialized to a substring of the current object. This substring is the character sequence that starts at character position pos and has a length of n characters.
Your line b = a.substr(i,i+1); will generate, for values of i:
substr(0,1) = 1
substr(1,2) = 23
substr(2,3) = 345
substr(3,4) = 45 (since your string stops there).
What you need is b = a.substr(i,2);
You should also be aware that your output will look funny for a number like 12045. You'll get 12 20 4 45 due to the fact that you're using atoi() on the string section and outputting that integer. You might want to try just outputing the string itself which will be two characters long:
b = a.substr(i,2);
cout << b << " ";
In fact, the entire thing could be more simply written as:
#include <iostream>
#include <string>
using namespace std;
int main(void) {
string a;
cin >> a;
for (int i = 0; i < a.size() - 1; i++)
cout << a.substr(i,2) << " ";
cout << endl;
return 0;
}
Another interesting variant question can be:
How would you make "12345" as "12 23 34 45" without using another string?
Will following do?
for(int i=0; i < a.size()-1; ++i)
{
//b = a.substr(i, 2);
c = atoi((a.substr(i, 2)).c_str());
cout << c << " ";
}
substr(i,j) means that you start from the index i (assuming the first index to be 0) and take next j chars.
It does not mean going up to the index j.
You can get the above output using following code in c
#include<stdio.h>
#include<conio.h>
#include<string.h>
int main()
{
char *str;
clrscr();
printf("\n Enter the string");
gets(str);
for(int i=0;i<strlen(str)-1;i++)
{
for(int j=i;j<=i+1;j++)
printf("%c",str[j]);
printf("\t");
}
getch();
return 0;
}
Possible solution without using substr()
#include<iostream>
#include<string>
using namespace std;
int main() {
string c="12345";
int p=0;
for(int i=0;i<c.length();i++) {
cout<<c[i];
p++;
if (p % 2 == 0 && i != c.length()-1) {
cout<<" "<<c[i];
p++;
}
}
}
Possible solution with string_view
void do_it_with_string_view( void )
{
std::string a { "12345" };
for ( std::string_view v { a }; v.size() - 1; v.remove_prefix( 1 ) )
std::cout << v.substr( 0, 2 ) << " ";
std::cout << std::endl;
}
The string constructor can be used to get a copy of a substring.
string(const string& str, size_t pos, size_t n)
For example...
b = string(a, i, 2); // substring of a from position i, including 2 characters
This differs from substr in that the length n cannot be omitted. I offer this only as an alternative, not as an improvement.