C++ ifstream read only integers - c++

I have a txt file with numbers with this format 12345678-A plus some random numbers and text in between. I need to read the file and save only the 8 digit integrers to an array. How do I do it?
Current code I have, works if there are numbers only:
const int MAX = 1000;
ifstream file("file.txt");
int data;
int index = 0;
int bigdata[MAX];
while (!file.eof() && index < MAX)
{
file >> data;
if (data > 20000000 && data < 90000000)
{
bigdata[index] = data;
index++;
}
}
Sample of input text:
48251182-D 6,5 6
49315945-F 7 3
45647536-I 3,5 3
45652122-H 7 6,5
77751157-L 2 2,5
75106729-S 2 5
77789857-B 4 3 3,5 3
59932967-V 4 8,5
39533235-Q 8 8,5
45013275-A 5 2
48053435-Y 6 8
48015522-N 3,5 4
48015515-T
48118362-B 7,5 3,5
39931759-Q 5,5 3
39941188-D 3,5 1,5
39143874-I 3,5 4
48281181-O 6,5 6

If all you need is to strip out the first number in each line then you can use the stream's operator >> to read in the integer part and then use std::getline to consume the rest of the line. Using
std::vector<int> data;
ifstream fin("file.txt");
int number;
std::string eater;
while (fin >> number) // get first 8 digit number. stops at the '-'
{
data.push_back(number);
std::getline(fin, eater); // consume the rest of the line
//now we are on the next line
}
// now data has all of the numbers that start each line.

You need this:
...
#include <string>
...
string line;
while (getline(file, line)) // read the whole line
{
int data = stol(line); // get number at start of line (stops
// automatically at the '-' sign
// data is the 8 digit number
// process data here...
...
}
...

One solution to this problem would be to read the stream character by character and search for 8-digit numbers:
static const int MAX = 1000;
int index = 0;
int bigdata[MAX];
int value = 0;
int digits = 0;
for (auto c = file.get(); c != EOF 0; c = file.get())
{
if (c >= '0' && c <= '9')
{
value = (digits ? (value * 10) : 0) + (c - '0');
++digits;
if (digits == 8)
{
if (index < MAX)
bigdata[index++] = value;
digits = 0;
}
} else
{
digits = 0;
}
}
The code reads byte by byte and builds an integer number if decimal digits are read. If the digit count reaches 8 the number is stored and the integer number buffer is reset. The integer number buffer is reset immediatly if the character read is not a decimal digit.
istream.get() returns EOF if reading past the end of the file so no need for a call to the .eof() member function.
Please note that this code stores all 8-digit numbers. You have to add another test if you need only numbers in the range 20000000..90000000.
If your lines are always starting with an 8-digit number followed by a minus then you could use this simple solution which I would recommend because of improved readability.
std::string buffer;
std::vector<int> target;
while (std::getline(file, buffer))
target.push_back(atoi(buffer.c_str()));
But this solution does not check for the presence of a valid number and simply stores 0 for each line not starting with a number.

Related

How to convert integers represented as string to ASCII symbols?

I have an input string that can look like this: "126022034056098012". It is a result of concatination of ASCII codes of symbols that I've read from some file. The codes are 126 22 34 56 98 12 for example. The problem is how to decode this string back into characters? Note: the string mustn't contain any delimiters other than digits (\,| and so on). What should I do next?
I figured out a way that uses map of ASCII symbols: key->string with numeric representatoin of ASCII symbol, value->ASCII symbol. In the loop, I accumulate the incoming digits in a string until the string matches some key in the map. When matched, I convert the resulting code into a character. I continue until I run out of input data. But this method works good with strings and txt-files but don't work with binary files.
function that makes string of characters from string of ASCII codes:
string Utils::from_number_to_ascii(string number, int size) {
Utils ut;
while(number.size() % 3) {
number = "0" + number;
}
string out;
for (int i = 0; i < size;){
string st;
auto it = ut.triple_dict.end();
while (it == ut.triple_dict.end() && i < size){
st += number[i++];
it = ut.triple_dict.find(st);
}
out += it->second;
st = "";
}
return out;
}
filling the map:
Utils::Utils() {
for (int i = 0; i <= 255; i++){
string s = to_string(static_cast<int>(i));
if (s.size() == 1) {
s = "00" + s;
} if (s.size() == 2){
s = "0" + s;
}
triple_dict.insert(make_pair(s, static_cast<unsigned char>(i)));
}
}
It's not hard to see that I fill the container with three bytes: if the ASCII code of symbol is two-digit number I append it with "0", if code of symbol is one-digit number I append it with "00" to make code three-digit number. I do this for unambiguous decoding of symbol.
If each ascii code is represented by exactly 3 digits, we can do this pretty easily with a loop:
std::string toAscii(char const* digits, size_t size) {
std::string output(size / 3, '\0');
for(char& c : output) {
char d0 = *digits++; // Get 3 digits
char d1 = *digits++;
char d2 = *digits++;
int ascii_value = (d0 - '0') * 100 + (d1 - '0') * 10 + (d2 - '0');
c = (char)ascii_value;
}
return output;
}
Example usage
I have a c-string with the example input, as well as a string with the expected output. This program verifies that they're equal.
int main() {
auto&& input = "126022034056098012";
std::string expected_output = {char(126), char(22), char(34), char(56), char(98), char(12)};
std::cout << (toAscii(input, sizeof(input)) == expected_output); // Prints true
}
Does fstream.write() add '\0' to the end of the file?
No. If your string contains the 0 character, it'll add it, but not otherwise. We can test this for ourselves with some pretty short example code.
#include <fstream>
#include <iostream>
#include <string>
int main()
{
{
std::ofstream file("test.txt");
std::string message = "Hello!";
file.write(message.data(), message.length());
// file gets closed automatically
}
{
std::ifstream file("test.txt");
while (file)
{
std::cout << file.get() << '\n';
}
// file gets closed automatically
}
}
When I compile and run this code, it outputs the following. Each value corresponds to the value of the corresponding character in "Hello!", except for the last one. The -1 indicates that you've reached the end of the file, but if you were using a method like file.read it wouldn't show up. The \0 doesn't appear anywhere in the file.
72
101
0
108
111
33
-1

How to check if numbers 0 to 9 have appeared atleast once in a stream of numbers in C++?

There is a stream of incoming numbers (in Base 10, could be any number having 'n' digits, say the stream could be 123, 8, 670, 4835134, 50243)
I have to check if all the digits 0 to 9 have appeared after reading the entire stream.
Ex. if stream is 123, 8, 670, 48351934, 50243, then the answer is "TRUE" (from 0 till 9, a number has appeared at least once)
if the stream is 123, 8, 670, 4835134, 50243, then the answer is "FALSE" because 9 did not appear in any of the numbers in the stream
Fix - 1
I thought I can take Can take OR from 0 till 9 and have it (allORresult)
Calucatate OR of all the numbers in the stream (streamORresult)
If the set bits of allORresult and streamORresult are similar, then we can conclude all the numbers,0 to 9 have appeared atleast once in the numbers of the stream.
Fix - 2
Take the naive approach! Decompose the number starting from ones digit (%10 then /10) and set a flag for each digit. If all the digits are encountered, then return TRUE
Just throwing a function that may come in handy:
#include <iostream>
#include <vector>
using namespace std;
bool findAllDigits(istream & i){
vector<int> digits(0);
int tmp; char c; bool found;
while(i >> c){//read one char
if(isdigit(c)){//check if it is a number
tmp = c - '0';//convert char to int
found = false;
for(size_t i = 0; i < digits.size(); ++i){
if(tmp == digits[i]){
found = true; break;
}
}
if(!found){//if this number wasn't in the vector yet
digits.push_back(tmp);
}
}
}
return digits.size() == 10;//return true if all the digits are in the stream
}
IDEONE
More compact function that uses stl:
#include <algorithm>
bool findAllDigits(istream & i){
vector<char> digits(0); char c;
while(i >> c)//read one char
if(isdigit(c) && find(digits.begin(), digits.end(), c)==digits.end())//check if it is a number and not in the vector
digits.push_back(c);
return digits.size() == 10;//return true if all the digits are in the stream
}
IDEONE
The bit manipulation will not help you for this problem:
decimal binary
123 0111 1011
2 0000 0010
OR 0111 1011
You have either to convert the number to strings (or keep them as such) and process the characters that represent the digits, or you have to iterate using %10 to get the last digit and use /10 to process the next digit.
I leave you finish your exercise with this hint on your own.
you can scan the entire stream and use flags for each number form 0-9
http://ideone.com/yJ13SM
#include <iostream>
#include<stdio.h>
using namespace std;
int main() {
char ch;
int flags[10];
do{
ch=getchar();
cout<<ch;
if(ch>='0' && ch<='9')
flags[ch-'0'] = 1;
}while(ch!='\n'); // some condition to stop scanning further
int flag = 0;
for(int i=0;i<=9;i++)
if(!flags[i])
flag++;
if(flag)
cout<<"some digit was missing";
else
cout<<"good coverage";
return 0;
}

How to parse out integers from a line with characters and integers

For a C/C++ assignment, I need to take an input line, starting with the character 's', followed by UP TO 3 separate integers. My issue is that, without vectors, I don't know how to account for an unknown number of integers (1-20).
For example, a test input would look like:
s 1 12 20
It was suggested to me to use cin.getline and take the whole line as a string, but how would I know where each integer would lie in a character array because of the possibility of single or double digits, let alone the number of integers in said string?
Construct a std::istringstream from the contents of the line, then keep using operator>> into an int, until it fail()s, stuffing each integer into a std::vector (after using the operator>> initially, once, to take care of the leading character).
You can mimic vectors using dynamic memory allocation. Initially create an array of size 2, using int *a = new int[2];
When this array fills up, make a new array of double the size, copy the old array in the new one and reassign a to the new array. Keep doing this until you have met the requirement.
EDIT
So getting the numbers through the string stream, if the array fills up, you could do:
int changeArr(int *a, int size){
int *b = new int[size*2];
for(int i=0;i<size;i++){
b[i] = a[i];
}
a = b;
return size*2;
}
int getNos(istringstream ss){
int *a = new int[2];
int cap = 2, i=0, number;
while(ss){
if(i>=cap){
cap = changeArr(a, cap);
}
ss >> a[i];
i++;
}
}
I have skipped the part about the first character, but I guess you can handle that.
Without vectors, you have a couple of approaches. (1) read an entire line at a time and tokenize the line with strtok or strsep, or (2) use the standard features built into strtol to walk down the string separating values with the pointer and end-pointer parameters to the function.
Since you know the format, you can easily use either. Both 1 & 2 above do the same thing, you are just using the tools in strtol to both tokenize and convert to a number in a single step. Here is a short example for handling a string followed by an unknown number of digits on each line:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
enum { BASE = 10, MAXC = 512 };
long xstrtol (char *p, char **ep, int base);
int main (void) {
char buf[MAXC] = "";
while (fgets (buf, MAXC, stdin)) { /* for each line of input */
char *p, *ep; /* declare pointers */
p = buf; /* reset values */
errno = 0;
printf ("\n%s\n", p); /* print the original full buffer */
/* locate 1st digit in string */
for (; *p && (*p < '0' || '9' < *p); p++) {}
if (!*p) { /* validate digit found */
fprintf (stderr, "warning: no digits in '%s'\n", buf);
continue;
}
/* separate integer values */
while (errno == 0)
{ int idx = 0;
long val;
/* parse/convert each number in line into long value */
val = xstrtol (p, &ep, BASE);
if (val < INT_MIN || INT_MAX < val) { /* validate int value */
fprintf (stderr, "warning: value exceeds range of integer.\n");
continue;
}
printf (" int[%2d]: %d\n", idx++, (int) val); /* output int */
/* skip delimiters/move pointer to next digit */
while (*ep && *ep != '-' && (*ep < '0' || *ep > '9')) ep++;
if (*ep)
p = ep;
else
break;
}
}
return 0;
}
/** a simple strtol implementation with error checking.
* any failed conversion will cause program exit. Adjust
* response to failed conversion as required.
*/
long xstrtol (char *p, char **ep, int base)
{
errno = 0;
long val = strtol (p, ep, base);
/* Check for various possible errors */
if ((errno == ERANGE && (val == LONG_MIN || val == LONG_MAX)) ||
(errno != 0 && val == 0)) {
perror ("strtol");
exit (EXIT_FAILURE);
}
if (*ep == p) {
fprintf (stderr, "No digits were found\n");
exit (EXIT_FAILURE);
}
return val;
}
(the xstrtol function just moves the normal error checking to a function to unclutter the main body of the code)
Example Input
$ cat dat/varyint.txt
some string 1, 2, 3
another 4 5
one more string 6 7 8 9
finally 10
Example Use/Output
$ ./bin/strtolex <dat/varyint.txt
some string 1, 2, 3
int[ 0]: 1
int[ 1]: 2
int[ 2]: 3
another 4 5
int[ 0]: 4
int[ 1]: 5
one more string 6 7 8 9
int[ 0]: 6
int[ 1]: 7
int[ 2]: 8
int[ 3]: 9
finally 10
int[ 0]: 10
You can provide a bit of tidying up, but this method can be used to parse an unknown number of values reliably. Look it over and let me know if you have any questions.
Since vectors aren't allowed, you'll need to find out how many numbers are in the line before you can make an array to hold them.
I won't just give you the entire code, since this is homework, but I'll show you what I would do to solve your problem.
If your lines will always look like this: "s number" or "s number number" or "s number number number", then you can easily find the number of numbers in the line by counting the spaces!
There will be one space in any string with one number (between the s and that number), and one more space for each number that follows the first.
So let's count the spaces!
int countSpaces(string s) {
int count = 0;
for (int i = 0; i < s.size(); i++) {
if (s[i] == ' ') {
count++;
}
}
return count;
}
Passing these strings:
string test1 = "s 123 4 99999";
string test2 = "s 1";
string test3 = "s 555 1337";
to the countSpaces function will give us:
3
1
2
And with that information, we can make an array with the correct size to hold each value!
EDIT
Now I realize that you're having trouble grabbing the numbers from the string.
What I would do, is use the above method to find the number of numbers in the line. Then, I would use the std::string.find() function to determine where, and if, any spaces are in the string.
So let's say we had the line: s 123 45 678
countSpaces would tell us we have 3 numbers.
Then we make an array to hold our three numbers. I would also cut off the s part so you don't have to worry about it anymore. Note that you can use std::stoi to turn a string into a number!
Now we can loop while find(' ') doesn't return -1.
In our loop, I would take the substring from 0 to the first space, like so:
num = std::stoi( myLine.substr(0, myLine.find(' ') )
Then you can cut off the part you just used:
myLine = myLine.substr( myLine.find(' ') );
This will grab a number off the front of your string, then chop off that number from the string, and repeat the process while there is still a space in the string.
EDIT:
If you aren't guaranteed to have one space between each number, then you can delete excess spaces before doing this method or you can do it during the countSpaces loop. At that point, it would make more sense to call the function countNums or such.
An example function to remove stretches of spaces and replace them with one space:
void removeExtraSpaces(string s) {
bool inSpaces = (s[0] == ' ');
for (int i = 1; i < s.size(); i++) {
if (s[i] == ' ') {
if(inSpaces) {
s.erase(i);
} else {
inSpaces = true;
}
} else if(inSpaces) {
inSpaces = false;
}
}
}

organizing strings using a hash table C++

I'm writing a code that:
asks for a string
converts that string into it's ascii value
then send this number to folding function that only take the first 8 digits
from the right , split it into 3 numbers , add them together ,then take the first 3 digits from the right as well
this number with 3 digits is the order of the the string in an array of pointers that represent the hash table
For example: If I input the string "abclmn" -> 979899100108109110 -> folding function 08109110 split the number into 3 numbers like so -> 081,091,10 -> 81+91+10=182
and 182 is where the string "abclmn" should be inserted in the hash table
This is my code:
#include<iostream>
#include<cmath>
#include<string>
#include<queue>
using namespace std;
int folding(long int num1)
{
int num;
num=num1%100000000;
int x=num/100000;
int y=(num%100000)/100;
int z=num%100;
int w=(x+y+z)%1000;
return w;
}
int main()
{
string s;
cout<<"input the variable name"<<endl;
cin>>s;
int* a=new int [s.length()];
for (int i=0;i<(s.length());++i)
{
a[i]=(int)s[i];
}
queue<int> q;
for (int i=0;i<(s.length());++i)
{
if (a[i]<10) q.push(a[i]);
else
if ((a[i]>9)&&(a[i]<100))
{
q.push(a[i]/10);
q.push(a[i]%10);
}
else if (a[i]>100)
{
q.push(a[i]/100);
q.push((a[i]%100)/10);
q.push(a[i]%10);
}
}//filling the number in a queue
long int num=0;
for (int i=(q.size());i>0;--i)
{
num=num+(q.front()*pow(10*1.0,i-1));
q.pop();
}
cout<<"the answer"<<folding(num)<<endl;
system("pause");
return 0;
}
My problem is that I don't know how long the string will be
so if the string is too along the output is going to be a random value
and that's because I'm using long int for the output value and it's not enough.
So is there a solution for this or another way to get the same result?
Thanks for help.
convert that string into it's ascii value
then send this number to
folding function that only take the first 8 digits from the right ,
split it into 3 numbers , add them together ,then take the first 3
digits from the right as well
Well, since you're only interested in the last 8 digits, we don't need to convert the entire string to its ASCII representation.
Let's try traversing backwards along the string and building our number that way.
int getDigits( std::string s ) {
long long int digits = 0;
int runningLength = 0;
int prevLength = 0;
for ( auto it = s.rbegin(); it != s.rend(); ++it ) {
runningLength += prevLength;
//if digits is a 7 digit number then appending a 3 digit number would overflow an int
digits += (long long int)*it * pow(10, runningLength);
//we have to work out the length of the current digit
//so we know how much we need to shift by next time
int dLength = 0;
for ( int d = *it; d > 0; dLength++, d /= 10 );
prevLength = dLength;
if ( digits >= 100000000 ) break;
}
return digits % 100000000;
}
then send this number to folding function that only take the first 8
digits from the right , split it into 3 numbers , add them together
,then take the first 3 digits from the right as well
Your code looks fine for that.
The code to split the string into digits would be a lot neater if you worked in base 16 (and assumed printable ASCII only).

Reading a list of characters and storing in an array

I am having issues with the following code and I cant figure out why out of loop is not being printed. With this code I want the program to ignore any spaces inputted by the user and after a space is inputted the number previously entered is stored in an array location. Like this I want 6 and 78 to be stored in 2 array locations not store them individually as 6 7 8.
This is my code:
while ((in=getchar()) != '0')
{
if (in == ' ')
{
printf("space\n ");
continue;
}
else
{
printf("assigning\n ");
input[i]=in;
}
i++;
}
printf("Out of Loop");
My output when inputting 5 6 78 is:
assigning
space
assigning
space
assigning
assigning
assigning
With this output I doubt whether 78 is being stored in one memory location.
I would really appreciate your help,Thankyou
C++:
std::vector<int> v;
std::string s;
int i;
std::getline( std::cin, s); // read full line with whitespaces
std::istringstream iss( s); // prepare to process the line
while( iss >> i) v.push_back( i); // read into i and push into vector if
// operator>> was successful
C:
int array[ 10];
int i = 0, retval;
while( i < 10 && ( retval = scanf( "%d", &array[ i++])) == 1) ;
if( i == 10) {
// array full
}
if( retval == 0) {
// read value not an integer. matching failure
}
if( retval == EOF) {
// end of file reached or a read error occurred
}
You are deciding character by character. Thus, you will only store single digits or ignore those digits.
You could store the whole numbers like this (extending your code):
bool currentNumberStarted = false;
int currentNumber = 0;
int idx = 0;
while ((in=getchar()) != '0')// you probably want '\0' instead of '0'
{
if (in == ' ')
{
if (currentNumberStarted)
{
input[idx]=currentNumber;
idx++;
currentNumberStarted = false;
}
printf("space\n ");
continue;
}
else
{
printf("assigning\n ");
currentNumberStarted = true;
currentNumber *= 10;
currentNumber += in;
}
}
printf("Out of Loop");
First of all I highly doubt that your while loop will ever end, even if you made that to '\0' ,Because you are using char variable to store input. Not strings, Only strings uses '\0' at the end,How can we enter '\0' from keyboard..???. even if you want to keep it as '0',you would alwasy have to enter 0 as last number to end the loop(which i think you dont want to.)
So the Solution is this:-
After Entering Numbers You will Hit ENTER key, which would generate a newline character '\n' so you have to check for new line character('\n'), And as you are using getchar() function, it will returns EOF (-1) at the end of input, so its important to check for it too.So you have to check for both '\n' and EOF at once in while loop.And at last you should also check for array index number(it should be less than 1) in which you are storing numbers.
I made some effort to make you understand the program in comments.
int main()
{
int i=0;
int input[10]={0}; //here only 10 integers can be entered(hence i should be i<10)
int in; //To store input character
int num=0; //To store number which is converted from character.
int new=1; //To check if new number is started 0=false 1=True.
int count=0;//This is just to know how many numbers entered,also used to print numbers at end.
while ((in=getchar()) != '\n' && (in!=EOF) && i<10)//should check for both '\n' and EOF and array index also
{
if (in == ' ')
{
printf("space\n ");
if(new==0) //if new Number is not started yet.
{
new=1; //Start of a New number.(a number entered after space)
i++; //As new number is started it should be stored in new array index.
}
continue; //if space is entered just go to begining
}
else
{
printf("assigning\n ");
num=in-48; //converts a character to number (ex:- converts '3' to 3)
input[i]=(input[i]*10)+num; //storing the number..This is important do a paper work to understand this step.
new=0; //still in same number(we are still processing same number)
}
}
printf("Out of Loop \n");
count=i+1; //This gives correct count of numbers entered
for(i=0;i<count;i++) //to print numbers.
printf("%d ",input[i]);
return 0;
}
OUTPUT:-
E:>example.exe
78 2 65 998 1
assigning
assigning
space
assigning
space
.
.
.
space
assigning
Out of Loop
78 2 65 998 1