Parse int from a string without regex? - c++

If I have a string where there is some word and some number (like "Text 125"), is it possible to get this number and convert it to int without using regex?

Yes, you could use a stringstream if you know that it's a word followed by a number.
std::stringstream ss("Text 125");
std::string buffer; //a buffer to read "Text" into
int n; //to store the number in
ss >> buffer >> n; //reads "Text" into buffer and puts the number in n
std::cout << n << "\n";
Edit: I found a way to do it without needing to declare a pointless variable. It's a bit less robust though. This version assumes that there is nothing after the number. std::stoi will work regardless of the number of spaces between the word and the number.
std::string str("Text 125");
int n = std::stoi(str.substr(str.find_first_of(' ') + 1));
std::cout << n << std::endl;

If you know exactly the format of the expected string, i.e. that it
always starts with "Text"
followed by a space
followed by a number
and then ends
(so in regex terms, it's /^Text (\d+)$/)
you can combine std::find and std::substr.
const std::string inputStr = "Text 125";
const std::string textStr = "Text ";
const std::size_t textPos = inputStr.find(textStr);
const std::size_t numberPos = textPos + textStr.length();
const std::string numberStr = inputStr.substr(numberPos);
const int numberInt = std::atoi(numberStr.c_str());
However, that only works in these specific circumstances. And even if /^Text (\d+)$/ is the only expected format, other input strings might still be possible, so you'll need to add the appropriate length checks, and then either throw an exception or return an invalid number or whatever you need to happen for invalid input strings.
#DanielGiger's answer is more generally applicable. (It only requires the number to be the second string, covering the more general case of /^\S+\s+(\d+)/)

Related

getting the substring that does not contain the first character in the string

If the string was abcdef how do I get bcdef. I tried
cout << str.substr(1,'\0')<< endl;
but that didn't work.
What about a char array?
#include <iostream>
using namespace std;
int main() {
std::string str = "abcdef";
cout << str.substr (1);
return 0;
}
Try it live: http://ideone.com/AueOXR
if you take a look at the documentation for string::substr:
string substr (size_t pos = 0, size_t len = npos) const;
Generate substring
Returns a newly constructed string object with its value initialized to a copy of a substring of this object.
The substring is the portion of the object that starts at character position pos and spans len characters (or until the end of the string, whichever comes first).
http://www.cplusplus.com/reference/string/string/substr/
That means: if you don't specify a second parameter a default one that goes all the way to the end of the string is assumed.
Try
cout << str.substr(1)<< endl;
Of course, the documentation of string tells you everything you need to know ...
Make it simpler:)
std::cout << str.substr( 1 ) << std::endl;
The other way and I think more effective is to use member function c_str if the string does not contain embedded zeroes
std::cout << str.c_str() + 1 << std::endl;
substr(position, length) will return the string started at the position index and ending at length characters after position.
You need to change the \0 to either the end of the string index or to nothing because it will default to returning the rest of the string if you don't have a second parameter.
str.substr(1) will return bcdef
str.substr(1, 5) will also return bcdef

Read into std::string using scanf

As the title said, I'm curious if there is a way to read a C++ string with scanf.
I know that I can read each char and insert it in the deserved string, but I'd want something like:
string a;
scanf("%SOMETHING", &a);
gets() also doesn't work.
Thanks in advance!
this can work
char tmp[101];
scanf("%100s", tmp);
string a = tmp;
There is no situation under which gets() is to be used! It is always wrong to use gets() and it is removed from C11 and being removed from C++14.
scanf() doens't support any C++ classes. However, you can store the result from scanf() into a std::string:
Editor's note: The following code is wrong, as explained in the comments. See the answers by Patato, tom, and Daniel Trugman for correct approaches.
std::string str(100, ' ');
if (1 == scanf("%*s", &str[0], str.size())) {
// ...
}
I'm not entirely sure about the way to specify that buffer length in scanf() and in which order the parameters go (there is a chance that the parameters &str[0] and str.size() need to be reversed and I may be missing a . in the format string). Note that the resulting std::string will contain a terminating null character and it won't have changed its size.
Of course, I would just use if (std::cin >> str) { ... } but that's a different question.
Problem explained:
You CAN populate the underlying buffer of an std::string using scanf, but(!) the managed std::string object will NOT be aware of the change.
const char *line="Daniel 1337"; // The line we're gonna parse
std::string token;
token.reserve(64); // You should always make sure the buffer is big enough
sscanf(line, "%s %*u", token.data());
std::cout << "Managed string: '" << token
<< " (size = " << token.size() << ")" << std::endl;
std::cout << "Underlying buffer: " << token.data()
<< " (size = " << strlen(token.data()) << ")" << std::endl;
Outputs:
Managed string: (size = 0)
Underlying buffer: Daniel (size = 6)
So, what happened here?
The object std::string is not aware of changes not performed through the exported, official, API.
When we write to the object through the underlying buffer, the data changes, but the string object is not aware of that.
If we were to replace the original call: token.reseve(64) with token.resize(64), a call that changes the size of the managed string, the results would've been different:
const char *line="Daniel 1337"; // The line we're gonna parse
std::string token;
token.resize(64); // You should always make sure the buffer is big enough
sscanf(line, "%s %*u", token.data());
std::cout << "Managed string: " << token
<< " (size = " << token.size() << ")" << std::endl;
std::cout << "Underlying buffer: " << token.data()
<< " (size = " << strlen(token.data()) << ")" << std::endl;
Outputs:
Managed string: Daniel (size = 64)
Underlying buffer: Daniel (size = 6)
Once again, the result is sub-optimal. The output is correct, but the size isn't.
Solution:
If you really want to make do this, follow these steps:
Call resize to make sure your buffer is big enough. Use a #define for the maximal length (see step 2 to understand why):
std::string buffer;
buffer.resize(MAX_TOKEN_LENGTH);
Use scanf while limiting the size of the scanned string using "width modifiers" and check the return value (return value is the number of tokens scanned):
#define XSTR(__x) STR(__x)
#define STR(__x) #x
...
int rv = scanf("%" XSTR(MAX_TOKEN_LENGTH) "s", &buffer[0]);
Reset the managed string size to the actual size in a safe manner:
buffer.resize(strnlen(buffer.data(), MAX_TOKEN_LENGTH));
The below snippet works
string s(100, '\0');
scanf("%s", s.c_str());
Here a version without limit of length (in case of the length of the input is unknown).
std::string read_string() {
std::string s; unsigned int uc; int c;
// ASCII code of space is 32, and all code less or equal than 32 are invisible.
// For EOF, a negative, will be large than 32 after unsigned conversion
while ((uc = (unsigned int)getchar()) <= 32u);
if (uc < 256u) s.push_back((char)uc);
while ((c = getchar()) > 32) s.push_back((char)c);
return s;
}
For performance consideration, getchar is definitely faster than scanf, and std::string::reserve could pre-allocate buffers to prevent frequent reallocation.
You can construct an std::string of an appropriate size and read into its underlying character storage:
std::string str(100, ' ');
scanf("%100s", &str[0]);
str.resize(strlen(str.c_str()));
The call to str.resize() is critical, otherwise the length of the std::string object will not be updated. Thanks to Daniel Trugman for pointing this out.
(There is no off-by-one error with the size reserved for the string versus the width passed to scanf, because since C++11 it is guaranteed that the character data of std::string is followed by a null terminator so there is room for size+1 characters.)
int n=15; // you are going to scan no more than n symbols
std::string str(n+1); //you can't scan more than string contains minus 1
scanf("%s",str.begin()); // scanf only changes content of string like it's array
str=str.c_str() //make string normal, you'll have lots of problems without this string

convert a string to integer in c++ without losing leading zeros

hello i have a problem with converting a string of numbers to integer.
the problem is that using atoi() to convert the string to integer i loose the leading zeros.
can you please tell me a way to do that without loosing the leading zeros?
#include <fstream>
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
struct Book{
int id;
string title;
};
struct Author{
string firstName;
string lastName;
};
Author authorInfo[200];
Book bookInfo[200];
void load ( void )
{
int count = 0;
string temp;
ifstream fin;
fin.open("myfile.txt");
if (!fin.is_open())
{
cout << "Unable to open myfile.txt file\n";
exit(1);
}
while (fin.good())
{
getline(fin, temp, '#');
bookInfo[count].id = atoi(temp.c_str());
getline(fin, bookInfo[count].title, '#');
getline(fin, authorInfo[count].firstName, '#');
getline(fin, authorInfo[count].lastName, '#');
count++;
}
fin.close();
}
Ok, so I don't think you actually WANT to store the leading zeros. I think you want to DISPLAY a consistent number of digits in the output.
So, for example, to display a fixed size id with 5 digits [note that an id of 100000 will still display in 6 digits - all it does here is make sure it's always at least 5 digits, and fill it with '0' if the number is not big enough], we could do:
std::cout << std::setw(5) << std::setfill('0') << id << ...
Alternatively, as suggested in other answers, you don't want to use the ID in a form that is an integer, you could just store it as a string - unless you are going to do math on it, all that it changes is that it takes up a tiny bit more memory per book.
An integer does not have leading zeroes. Or perhaps, more correctly, it has between zero and an infinite number of them. The numbers 42, 042 and 000000042 (other than in the source code where a leading 0 indicates a different base) are all forty-two.
If you want to keep the leading zeroes, either leave it as a string or store more information somewhere as to how big the original string was. Something like this would be a good start:
#include <iostream>
#include <iomanip>
#include <cstring>
#include <cstdio>
#include <cstdlib>
int main (void) {
// Test data.
const char *sval = "0042";
// Get original size.
int size = strlen (sval);
// Convert to int (without leading 0s).
// strtol would be better for detecting bad numbers.
int ival = atoi (sval);
// Output details.
std::cout << sval << " has size of " << size << ".\n";
std::cout << "Integer value is " << ival << ".\n";
std::cout << "Recovered value is " << std::setw(size)
<< std::setfill('0') << ival << ".\n";
return 0;
}
which outputs:
0042 has size of 4.
Integer value is 42.
Recovered value is 0042.
A = strlen(string) returns the number of characters in your string (say number of digits comprehensive of leading zeros)
B = log10(atoi(string)) + 1 returns the number of digits in your number
A - B => number of leading zeros.
Now you can format those as you prefer.
There's no such thing as "leading zeros" in a number. "Leading zeros" is a property of a specific notation, like decimal ASCII representation of a number. Once you convert that notation to a conceptually abstract numerical representation, such metric as "number of leading zeros" is no longer applicable (at least in decimal terms). It is lost without a trace.
A number is a number. It doesn't have any "zeros", leading or otherwise.
The only thing you can do is to memorize how many leading zeros you had in the original notation (or how wide was the field), and then later, when you will convert the number back to decimal ASCII representation, re-create the proper number of leading zeros using that stored information.
BTW, in your case, when the input number represents a book ID with some pre-determined formatting (like leading zeros), you might consider a different approach: don't convert your book ID to int. Keep it as a string. It is not like you are going to have to perform arithmetic operations on book IDs, is it? Most likely all you'll need is relational and equality comparisons, which can be performed on strings.
I have encountered this type of problem last month!
I think you can use the Format() method provided by Class CString:
CString::Format() formats and stores a series of characters and values in the CString. Each optional argument (if any) is converted and output according to the corresponding format specification in pszFormat or from the string resource identified by nFormatID.
For example:
CString m_NodeName;
m_NodeName.Format(_T("%.4d"),Recv[2]*100+Recv[3]);
// %.4d means the argument will be formatted as an integer,
// 4 digits wide, with unused digits filled with leading zeroes
For the detail you can find here:
http://msdn.microsoft.com/zh-cn/library/18he3sk6(v=vs.100).aspx
If you need the leading zeros, then int is not the correct data type to use. In your case you may be better off just storing the original string.
There is no way of storing an int with leading 0s.
What you may want to do instead, is have a class do it for you:
class intWithLeadingZeros {
int number;
int numberOfLeadingZeros;
intWithLeadingZeros( string val )
{
// trivial code to break down string into zeros and number
}
string toString() {
// trivial code that concatenates leading 0s and number
}
};

c++ int store as character in char* conversion without any API

how can we store int value in char* as representing character in c++.. for example, i want to store 10..char* p is a character pointer and i want to store 10 as character in that pointer...because i want to write iteration that generates character stream based on integer value.how to do char concatenation with integer(as char) with The similar java code be as:
for(int i=0; i<10; i++)
{
string temp=value+i;//here i want to use char* to represent string in c++
System.out.println(temp);
}
I know you said C++, but you also said char* so i am going to treat it as C. With C, you can't really do concatenation like that. The best way to do it would be to calculate the number of characters required, malloc that, then just store the characters in the char array. And remember to free it when you're done using it! In C, you have to do everything yourself!
I'm a little confused about what you're trying to do, but here's some information that I think will probably help you work it out:
In C++, you should primarily use std::string to hold strings of characters.
In regular C, the convention is to use a char* to hold a list of characters - these char*'s have to be null terminated ending in \0 so that your code knows where to stop printing the string of characters.
Preferring the C++ way, you can concatenate strings with the + operator:
Here's an example:
std::string myString = "H";
myString += "e";
myString += "l";
std::cerr << myString; //prints "Hel" to console.
You can also use a string stream which can mix data types:
std::stringstream ss;
ss << "h" << "e" << 7 << myCustomType << std::endl;
One other thing that's good to know is you can store an integer value in a char and it will work out the ascii representation when you print it.
For example:
char x = 65; //x = capital A.

In C++ How can I tell the difference between integers and characters?

I am currently learning C++ and I have been asked to make a program which will calculate the interest that would be paid on a deposit of a given size. One of the requirements is that we display an error message when non-integer data is entered.
I however cannot work out how to detect if non-integer data has been entered. If anyone could provide an example of how this problem is solved it would be much appreciated!
You don't have to check yourself. The expression (std::cin >> YourInteger) evaluates to a bool, whcih is true if and only if YourInteger was succesfully read. This leads to the idiom
int YourInteger;
if (std::cin >> YourInteger) {
std::cout << YourInteger << std::endl;
} else {
std::cout << "Not an integer\n";
}
this should be a clear enough starting point.
char* GetInt(char* str, int& n)
{
n = 0;
// skip over all non-digit characters
while(*str && !isdigit(*str) )
++str;
// convert all digits to an integer
while( *str && isdigit(*str) )
{
n = (n * 10) + *str - '0';
++str;
}
return str;
}
You need to find out if the input value contains non numeric characters. That is, anything other than 0-9.
You have to first take input as string and then verify if every digit is indeed numeric.
You can iterate the string and test if each character is a valid digit using the built in function isdigit() defined in <cctype>. You might also want to allow for a single comma if you're working with decimal numbers.