Extracting numbers from string into an array - c++

I'm having a problem with an assignment. I have to open a text file that looks more or less like this:
-------------------------------------------------------------
|ammount | time |delay |
-------------------------------------------------------------
|100 | 342 | 4324 |
with a few more rows. All I have to do is get the numbers into an array, which, for the example above, would look like this: ar[0]=100, ar[1]=342, ar[2]=4324. I imagine that I need to read the file line by line into strings with getline, but what next? If I use stringstream, I would get |100 instead of just 100. I'm really out of ideas now.

To read one line of input like you described (file may be an ifstream or a istringstream here):
for (int i = 0; i < 3; ++i)
{
file.ignore(numeric_limits<streamsize>::max(), '|'); // Ignores all characters until it finds a '|' character
file >> ar[i]; // Reads the number following the '|' to ar[i]
}
file.ignore(numeric_limits<streamsize>::max(), '\n'); // Finally, ignores all characters until newline
You can even make a small shortcut macro if you want:
#define ignore_until(c) ignore(numeric_limits<streamsize>::max(), c)
and use it like this:
file.ignore_until('|');

Related

Separately reading a word like "a-b-" from a text file and deleting

The first question is I have code like this for reading from the text file:
File >> product.projectNo >> product.date
>> product.productNo >> product.productQ
>> product.productTotalPrice;
And I write productNo, productQ and productTotalPrice to the file, separated by - because there can be more than one. Here is an example of the text file:
17 5 17-7051-10- 9-8-11- 720-616-55-
The last one 720-616-55- (productTotalPrice) is a list of prices. I need to read them separately and add them. So: 720+616+55. How can I do that?
The second question is I need to delete any of them, meaning productNo 17-7051-10-, needs to delete 17-. How can I do this?
The first part of your problem is reading each word from your file. This can be done using:
std::string word0, word1;
std::getline(file, word0, ' ');
std::getline(file, word1, ' ');
...
Of course, the above code assumes that there is exactly one ' ' is being used as a separator between words.
The next problem is parsing your prices. This can be done using std::stoi:
size_t index;
int price0 = `std::stoi(word, &index);
word = word.substr(index + 1);
int price1 = `std::stoi(word, &index);
word = word.substr(index + 1);
int price2 = `std::stoi(word);
int totalPrice = price0 + price1 + price2;
This works because std::stoi returns the index of the first character which is not part of the integer. So this would be the - separator between your numbers.
As for the second part of your question: You wouldn't delete 17- as a string. Instead you should simply ignore the 17 before adding it onto the sum or you should remove it from the list of numbers after parsing.

Separate a line to columns using several spaces (>1) as a delimiter using C++ or linux

I have several lines looking like this:
4539(random number of spaces)07235001(random number of spaces)Aach(random number of spaces)Trier Saarburg
I want to separate it to 4 columns using C++ or linux. The output I want will look like this:
4539|07235001|Aach|Trier Saasburg
So I want to treat several spaces as the delimiter but not the single one.
(random number of spaces thankfully is always > 1)
Lines do not always consist of 4 columns and the space problem is not always at the last column.
Thanks in advance
You should read each field individually. The last field can be read until a newline
character is received:
std::string column1;
std::string column2;
std::string column3;
std::string column4;
while (input_file >> column1)
{
input_file >> column2;
input_file >> column3;
getline(input_file, column4);
}
Another method is to read the entire line using getline and then fetch out the substring fields using std::string::find and std::string::substr.
You can use awk with regular expressions for this:
echo "4539 07235001 Aach Trier Saarburg" | awk 'BEGIN { FS = "[ ]{2,}" } { OFS = "|" }; {$1=$1; print $0 }'
FS variable is used to set the field separator for each record and may contain any regular expression. OFS is the output equivalent of the FS variable.

C++ Reading a text file backwards from the end of each line up until a space

Is it possible to read a text file backwards from the end of each line up until a space? I need to be able to output the numbers at the end of each line. My text file is formatted as follows:
1 | First Person | 123.45
2 | Second Person | 123.45
3 | Third Person | 123.45
So my output would be, 370.35.
Yes. But in your case, it's most likely more efficient to simply read the whole file and parse out the numbers.
You could do something like this (and I'm writing this in pseudocode so you have to acutally write real code, since that's how you learn):
seek to end of file.
pos = current position
while(pos >= 0)
{
read a char from file.
if (char == space)
{
flag = false;
process string to fetch out number and add to sum.
}
else
{
add char to string
}
if (char == newline)
{
flag = true;
}
pos--
seek to pos-2
}

Parsing of file with Key value in C/C++

Need some help in parsing the file
Device# Device Name Serial No. Active Policy Disk# P.B.T.L ALB
Paths
--------------------------------------------------------------------------------------- -------------------------------------
1 AB OPEN-V-CM 50 0BC1F1621 1 SQST Disk 2 3.1.4.0 N/A
2 AB OPEN-V-CM 50 0BC1F1605 1 SQST Disk 3 3.1.4.1 N/A
3 AB OPEN-V*2 50 0BC1F11D4 1 SQST Disk 4 3.1.4.2 N/A
4 AB OPEN-V-CM 50 0BC1F005A 1 SQST Disk 5 3.1.4.3 N/A
The above information is in devices.txt file and and i want to extract the device number corresponding to the disk no i input.
The disk number i input is just an integer (and not "Disk 2" as shown in the file).
Open the file and skip first 3 lines.
Start reading line by line from 4th line onward. You can get the device number easily as it is the first column.
To get the disk no, search through each line using the space character. When you encounter one space character it means you've gone past one column. Ignore the repeated spaces and continue this until you reach the disk no. You must handle the spaces in the column data separately if it exist.
Load the disk no and device no in to say a map and later you can use your input to query the device info from this map.
#include <sstream>
#include <fstream>
#include <iostream>
#include <cctype>
using namespace std;
int main(int argc, char* argv[])
{
int wantedDisknum = 4;
int finalDeviceNum = -1;
ifstream fin("test.txt");
if(!fin.is_open())
return -1;
while(!fin.eof())
{
string line;
getline(fin, line);
stringstream ss(line);
int deviceNum;
ss >> deviceNum;
if(ss.fail())
{
ss.clear();
continue;
}
string unused;
int diskNum;
ss >> unused >> unused >> unused >> unused >> unused >> unused >> unused >> diskNum;
if(diskNum == wantedDisknum)
{
finalDeviceNum = deviceNum;
break;
}
}
fin.close();
cout << finalDeviceNum << endl;
system("pause");
return 0;
}
In UNIX, you can easily achieve this using awk or other script lang.
cat Device.txt | awk '{if ( $1 == 2 ) print}'
In C++, you have to extract specific column using strtok and compare it with 'val' if it matches print that line.'
Assuming there is no "Disk" in any of the following columns:
1) Skip lines until you encounter '-' as the first character of a line, then skip that line too.
2) read a line
2.a) skip characters of the current line until isdigit(line[i]) function returns true, then read current character and characters following it into a temporary buffer until isdigit(line[i]) returns false. This is the device id.
2.b) Skip characters of the current line until you find a 'D'
2.b.i) match 'i', 's', 'k' characters, if any of them fails, go to 2.b
2.c) skip characters of the current line until isdigit(line[i]) function returns true, then read current character and characters following it into another buffer until isdigit(line[i]) returns false. This is the disk id.
3) print out both buffers
I don't have my Regular Expression cheat sheet handy, but I'm pretty sure it would be straightforward to run each line in the file through a regex that:
1) looks for a integer in the line
2) skips whitespace followed by text three times
3) matches characters one space and characters
Boost, Qt, and most other common C++ class libraries have a Regex parser for just this kind of thing.

Counting columns of a space separated file

My question concerns the use of std::count (or another appropriate function) to count the columns of a space separated file.
I currently use something like this:
std::ifstream inFile("file");
int lines = std::count(std::istreambuf_iterator<char>(inFile),
std::istreambuf_iterator<char>(), '\n');
to count the lines.
Since all the lines are equal (same amount of data), would something like
std::ifstream inFile("file");
int columns = std::count(std::istreambuf_iterator<char>(inFile),
std::istreambuf_iterator<char>('\n'), ' ') + 1;
do what I need?
Thanks
EDIT:
I mean, if in "file" there is data like 1 2 or 1 [many spaces here] 2, would the value of columns anyway be 2 or not?
No, you'll count spaces, not columns. You need to tokenize your line, e.g. by boost::tokenizer