Distinguishing between numbers and other symbols [c++] - c++

I'm reading a text file and extracting pieces of information of it by means of parsing (line by line).
Here is an example of the text file:
0 1.1 9 -4
a #!b .c. f/
a4 5.2s sa4.4 -2lp
So far, I'm able to split each line using empty spaces ' ' as separators. So I can save, for example, the value of "1.1" into a string variable.
What I want to do (and here is where I'm stuck) is to determine if the piece of information that I'm reading represents a number. Using the previous example, these strings do not represent numbers: a #!b .c. f/ a4 5.2s sa4.4 -2lp
Alternatively, these strings do represent numbers: 0 1.1 9 -4
Then I would like store the strings that represent numbers into a double type variable (I know how to do the conversion to double part).
So, How can I distinguishing between numbers and other symbols? I'm using c++.

You can do this:
// check for integer
std::string s = "42";
int i;
if(!s.empty() && (std::istringstream(s) >> i).eof())
{
// number is an integer
std::cout << "i = " << i << '\n';
}
// check for real
s = "4.2";
double d;
if(!s.empty() && (std::istringstream(s) >> d).eof())
{
// number is real (floating point)
std::cout << "d = " << d << '\n';
}
The eof() check makes sure that the number is not followed by non numeric characters.

Assuming a current (C++11) compiler, the easiest way to handle this is probably to do the conversion using std::stod. You can pass this the address of a size_t that indicates the location of the first character that could not be used in the conversion to double. If the entire input converted to double, it will be the end of the string. If it's any other value, at least part of the input didn't convert.
size_t pos;
double value = std::stod(input, &pos);
if (pos == input.length())
// the input was numeric
else
// at least part of the input couldn't be converted.

Related

C++ Numerical Input Validation

I'm used to Python and I'm now learning C++ which is a bit more complicated to me. How can I modify the input so that it fits the description in the comment at the top of my code? I tried to include if (input[0]!='.' &&...) but it just returns 0. I want it to be included as part of the number. Same with the characters after the first character of the input.
I also don't know how I can separate numbers with more than three digits (starting from the end of the number obviously) with a comma (so 1000000 should be returned as 1,000,000).
/*
* The first character can be a number, +, -, or a decimal point
* All other characters can be numeric, a comma or a decimal point
* Any commas must be in their proper location (ie, separating hundreds from thousands, from millions, etc)
* No commas after the decimal point
* Only one decimal point in the number
*
*/
#include <iostream>
#include <cmath>
#include <climits>
#include <string>
int ReadInt(std::string prompt);
int ReadInt(std::string prompt)
{
std::string input;
std::string convert;
bool isValid=true;
do {
isValid=true;
std::cout << prompt;
std::cin >> input;
if (input[0]!='.' && input[0]!='+' && input[0]!='-' && isdigit(input[0]) == 0) {
std::cout << "Error! Input was not an integer.\n";
isValid=false;
}
else {
convert=input.substr(0,1);
}
long len=input.length();
for (long index=1; index < len && isValid==true; index++) {
if (input[index]==',') {
;
}
else if (isdigit(input[index]) == 0){
std::cout << "Error! Input was not an integer.\n";
isValid=false;
}
else if (input[index] == '.') {
;
}
else {
convert += input.substr(index,1);
}
}
} while (isValid==false);
int returnValue=atoi(convert.c_str());
return returnValue;
}
int main()
{
int x=ReadInt("Enter a value: ");
std::cout << "Value entered was " << x << std::endl;
return 0;
}
Writing parsing code is tricky. When parsing, it is easy to make a mess of the control flow. I suggest dividing up the I/O from the validation code: make a separate function bool IsVaildInt(const std::string& s) that returns whether s is a valid input, and do the prompts outside in a calling function.
It helps to think through systematically for every character what constitutes a valid input. If you are familiar with regexes, like cigien suggested, that may be a good way of organizing your approach even if you end up writing the parsing code by hand instead of using a regex library.
Here are the requirements that you posted:
* The first character can be a number, +, -, or a decimal point
* All other characters can be numeric, a comma or a decimal point
* Any commas must be in their proper location (ie, separating hundreds
from thousands, from millions, etc)
* No commas after the decimal point
* Only one decimal point in the number
That's a lot of logic, but it's doable. It sounds like you are working on this as an exercise to master C++ basics, so I won't post any code. Instead, here's an outline for how I would approach this:
Test that the first character is either 0-9, +, -, or decimal point. If it's not, return invalid.
Search the string for whether it has a decimal point. If it does, remember its position.
Loop over the remaining characters, in reverse starting from the last character.
Separate from the loop index, make a counter that says what the current digit place is (... -1 for tenths, 0 for ones, 1 for tens, 2 for hundreds, ...). If the string has a decimal point, use that vs. the string length to determine the digit place of the last character.
If a character is a comma, check that it is in a valid location compared to the current digit place. If not, return invalid.
Otherwise, if the character is a decimal point, it must be the one identified earlier. If not, that means there are multiple decimal points, so return invalid.
Otherwise, the character must be a digit 0-9, and the digit place counter should be incremented. If the character is not a digit, return invalid.
Finally, if the loop makes it all the way through without hitting an error, return that the string is valid.

accessing a strings elements using [] prints random results

So, I am making a mid square hashing function as part of a project for school, and I am perplexed how my computer is taking two random string elements out of a string when I am only asking for one element. Here is a tiny example in code below.
string squaredKey = "54756";
int middleDigit = (ceil(stringSquareKey.length()/2));
cout << squaredKey[middleDigit] << endl; // this prints out 7 as expected
string temp = to_string(squaredKey[middleDigit]);
cout << temp << endl; // This prints out 55 for some reason.
I don't know exactly what the problem is, but I think it has something to do with to_string(). Let me know if you would like to see more code.
std::to_string is for converting numbers to strings. And an unfortunate fact of C++ is that char is also a number in its own right, though it's commonly used to represent ASCII values.
What to_string(squaredKey[middleDigit]); is doing is taking the ASCII value '7' (not 7) and converting it to a decimal number, which is 55.
You should use the std::string constructor that accepts a char and a count:
std::string temp(1, squaredKey[middleDigit]);
std::to_string converts a numeric value to std::string, so its input is treated as a numeric value. stringSquareKey.length()/2 gives character value '7', which corresponds - when treated as a numeric value - to ASCII code 55.
So your code is the same as string temp = to_string(55).

How do I convert an std::stringstream to a uintptr_t and maintain the hex value?

Currently, I am attempting to calculate offsets from a pointer address, and the number of offsets to be calculated can change, so the approach must be done dynamically.
I start by looping for the number of offsets I am trying to calculate, each offset is 4 bytes apart, thus I multiply the current iteration by 4, and then attempt to convert the resulting value to a hex address, and store it back in the uintptr_t as a hex value.
This value, in theory, should be the offset I am looking for.
In reality, that is not the case, the value seems to be getting converted back to an integer and stored in the uintptr_t variable.
Expected Output:
4
8
C
10
14
(etc)
Actual Output
4
8
12
16
20
(etc)
Code
for (int i = 1; i < totalEntities + 1; i++)
{
// Define a stringstream to store the hex value.
std::stringstream ss;
// Define a value that will be converted to hex.
uintptr_t valueToHex = i * 4;
// Convert valueToHex to Hex, and store the result in stringstream ss.
ss << std::hex << valueToHex;
// Convert stringstream ss to a uintptr_t stored in valueToHex
ss >> valueToHex;
// Output result
std::cout << valueToHex << std::endl;
}
uintptr_t represents a value of an integer. It does not represent textual representation of that value. The base of the number is not part of the value. 0xC, 12, 014 are indistinguishable values regardless of their different representation.
The base is part of the textual representation. All information besides the value (i.e. all representational details) is lost when an integer is extracted from a character stream.
You can either:
a) Extract a string instead, and insert the extracted string into the output stream. Strings retain most of the textual representation (an exception being that system specific new-line character sequences are converted to \n) or
b) Use std::hex to insert the integer into the output stream in the representation that you want.
seems like you just want to output an integer as a hex string. ie
for (int i = 1; i < numEntities + 1; i++)
{
std::cout << std::hex<< i*4 << std::endl;
}

c++ convert integer to 8 char hex, drop the first two char so that it is only a 6 char hex, and convert back to an integer

I have been searching and experimenting for many, many, hours now, and so far I have not been able to adapt any of the solutions I have come across to do what I want.
My goal is to take an integer (538214658) and convert it into an 8 character hex string (020148102). Then I want to drop the first two characters (0148102) and convert it back into an integer(1343746) which I am using as a key in a map array.
The solutions I've seen so far just convert an integer into hex string, but don't take into account the desired digit length.
I am able to print out just the first 6 characters using the following code:
Console_Print("%06X", form ? form->refID : 0)
So I thought that maybe I could use that technique to store it into a string, and then use iostream or sstream to convert it back to an integer, but none of my searches turned up anything I could use. And all of my experiments have failed.
Some help would be greatly appreciated.
EDIT: Below is my solution based on Klaus' suggestion:
uint32_t GetCoreRefID(TESForm* form)
{
uint32_t iCoreRefID = 0;
if (form)
{
uint32_t iRefID = (uint32_t)(form->refID);
iCoreRefID = iRefID & 0x00ffffff;
}
return iCoreRefID;
}
There is no need to convert to a string representation.
Look the following example:
int main()
{
uint32_t val = 538214658 & 0x00ffffff;
std::cout << std::hex << val << std::endl;
std::cout << std::dec << val << std::endl;
}
You have to learn that a value is still only a value and is not dependent on the representation like decimal or hex. The value stored in a memory area or a register is still the same.
As you can see in the given example I wrote your decimal value representation and remove the first two hexadecimal digits simply by do a bitwise and operation with the hexadecimal representation of a mask.
Furthermore you have to understand that the printing with cout in two different "modes" did not change the value at all and also not the internal representation. With std::dec and std::hex you tell the ostream object how to create a string from an int representation.

c++ convert character to integer using ASCII

I am working on a little c++ project that receives a char array input from the user. Depending on the value, I am converting it to an int. I understand there are better ways of doing this but I thought I'd try to convert it through ASCII to allow other uses later on. My current code for the conversion is:-
int ctoi(char *item){
int ascii, num = 0;
ascii = static_cast<int>(item[0]);
if(ascii >= 49 && ascii <=57){
num = ascii - 48;
}else{
return 0;
}
ascii = static_cast<int>(item[1]);
if(ascii >= 48 && ascii <=57){
num = num * 10;
num = num + (ascii - 48);
}else{
return 0;
}
return num;
}
It receives a input into the char array item[2] in the main function and passes this to the conversion function above. The function converts the first char to ASCII then the decimal value of the ASCII to num if its between 1 and 9, then it converts the second char to ASCII, if it is between 0 and 9, it times the value in num by 10 (move along one unit) and adds the decimal value of the ASCII value. At any point it may fail, it returns the value 0 instead.
When I cout the function after receiving a value and run this code in a console, it works fine for single digit numbers (1 - 9), however when I try to use a double digit number, it repeats digits such as for 23, it will output 2233.
Thanks for any help.
I wonder how you're reading the input into a two-character array. Note that it's customary to terminate such strings with a null character, which leaves just one for the actual input. In order to read a string in C++, use this code:
std::string s;
std::cin >> s;
Alternatively, for a whole line, use this:
std::string line;
getline(std::cin, line);
In any case, these are basics explained in any C++ text. Go and read one, it's inevitable!