Losing the last token from every line of input read in - c++

I'm trying to write a program that reads lines of code from a file as strings then splits that string into tokens around each comma. (It is a comma seperated file).
It works for the most part but I'm losing the last token on every single line.
//This is function splits input strings into tokens. It takes in an input
string
//and a delimiter character as parameters.
vector<string> tokenize(string inputString, char delimiter) {
//the store the delimiter in local variable
char newDelimiter = delimiter;
//store the input string in local variable
string newString = inputString;
//vector of strings to store tokens.
vector<string> tokenVector;
//temp variable for making tokens
string temp;
//iterate through the string...
for (int i = 0; i < newString.size(); ++i) {
//...checking for specified delimiter.
//If not present, add current character to temp string.
if (newString.at(i) != newDelimiter) {
temp += newString.at(i);
}
//if present, add temp string to vector and reset temp variable
else
{
tokenVector.push_back(temp);
temp = "";
}
}
return tokenVector;
}
int main() {
//string variable input will store each line of input
string input;
//use getline initially to "skip" the header line
getline(cin, input);
//this vector will be used to store each input lines string tokens
vector<string> stringTokens;
//this while loop will execute as long as cin is reading lines from the
file
while (getline(cin, input)) {
//print out each original line for testing purposes
cout << input << endl;
//split the string into tokens around commas
stringTokens = tokenize(input, ',');
//TEST OUTPUT
for (int j = 0; j < stringTokens.size(); ++j) {
cout << stringTokens.at(j) << " ";
}
cout << endl;
}
return 0;
}
A sample line of output: THere is a zero missing from the second line. The first line is simply the original string, the second the output:
1,000010007,01,XX,0,0,0,0,0,0,0,01 - XXXXX,XXXXXXXXXX,0,0,0,0,0,0,0,0,0,0,0
1 000010007 01 XX 0 0 0 0 0 0 0 01 - XXXXX XXXXXXXXXX 0 0 0 0 0 0 0 0 0 0
How shall I fix this? Thanks.

After the loop add:
if (temp != "")
{
tokenVector.push_back(temp);
}
For the last element.
vector<string> tokenize(string inputString, char delimiter) {
...Code...
for (int i = 0; i < newString.size(); ++i) {
...Code...
}
if (temp != "") {
tokenVector.push_back(temp);
}
return tokenVector;
}

Related

while reversing string 'my.name.is' i'm getting output as 'is#.name.my'. I don't understand from where '#' came from

Given a String of length S, reverse the whole string without reversing the individual words in it. Words are separated by dots.
Input:
The first line contains T denoting the number of testcases. T testcases follow. Each case contains a string S containing characters.
Output:
For each test case, in a new line, output a single line containing the reversed String.
Constraints:
1 <= T <= 100
1 <= |S| <= 2000
Example:
Input:
i.like.this.program.very.much
Output:
much.very.program.this.like.i
#include <bits/stdc++.h>
using namespace std;
int main() {
//code
int t;cin>>t;
while(t--) {
string s;
cin>>s;
stack<string> st;
int siz = s.size();
char c[siz];
for(int i =0;i<siz;i++) {
c[i] = s[i];
}
char *token = strtok(c,".");
while (token != NULL)
{
st.push(token);
st.push(".");
token = strtok(NULL, ".");
}
st.pop();
while(!st.empty()) {
cout<<st.top();
st.pop();
}
cout<<"\n";
}
return 0;
}
When you do
char c[siz];
for(int i =0;i<siz;i++) {
c[i] = s[i];
}
you don't append a 0 to c[] to mark the end of the string.
If you used siz + 1 as an array size, and put a zero (null character) at the end, it would work.
But still, you should not use VLAs.
char c[siz];
c.push(0);
for(int i =0;i<siz+1;i++) {
c[i] = s[i];
}
You could add a null character to the end of the string and increase the string size by 1 to avoid size violation errors.

How to fill an array with a sentence?

For instance i have the sentence " I am Piet". I want to fill this sentence into an array in a way that I[0], am[1] Piet[2]. Below is the code i've made. The problem is that the sentence is filled in each element of the array.
#include <iostream>
#include <string>
using namespace std;
// function to populate my array
void populateMyArray(string*myArray, string sentence, int size)
{
for (int i = 0; i < size; i++)
{
*myArray = sentence;
myArray++;
}
}
// function to count works in the sentence
int countWords(string x)
{
int Num = 0;
char prev = ' ';
for (unsigned int i = 0; i < x.size(); i++) {
if (x[i] != ' ' && prev == ' ') Num++;
prev = x[i];
}
return Num;
}
int main()
{
string sentence1;
cout << "Please enter a line of text:\n";
getline(cin, sentence1);
int nWords1 = countWords(sentence1);
string *arr1 = new string[nWords1];
populateMyArray(arr1, sentence1, nWords1); //populate array1
for (int i = 0; i < nWords1; i++)
{
cout << "sentence one: " << arr1[i] << "\n";
}
system("PAUSE");
}
You can use vector in order to save data and each time you should use space between two words and you will store each string type into vector array
#include<bits/stdc++.h>
using namespace std;
main()
{
string s;
getline(cin,s);
vector<string> ss;
string temp = "";
s +=" ";
for(int i = 0 ; i < s.size();i ++){
if(s[i] != ' ')
temp += s[i];
else{
ss.push_back(temp);
temp = "";
}
}
for(int i = 0 ; i < ss.size();i ++)
cout << ss[i] <<" ";
}
Instead of using an array, use a std::vector instead. This way you don't have to worry about variable word sizes or overflowing anything in case a word or sentence is too long. Rather you can just do something like this:
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
int main() {
// Get all words on one line
std::cout << "Enter words: " << std::flush;
std::string sentence;
getline(std::cin, sentence);
// Parse words into a vector
std::vector<std::string> words;
std::string word;
std::istringstream iss(sentence);
while( iss >> word ) {
words.push_back(word);
}
// Test it out.
for(auto const& w : words) {
std::cout << w << std::endl;
}
}
For an example sentence of I like cats and dogs equally you will have: words[0] = I, words[1] = like and so on.
If I understood correctly you are trying to split the input sentence into words.
You could do it like this:
void populateMyArray(string *myArray, string sentence, int size)
{
int firstCharIndex = -1;
char prev = ' ';
for (unsigned int i = 0; i < sentence.size(); i++) {
// Find the first character index of current word
if (sentence[i] != ' ' && prev == ' ') {
firstCharIndex = i;
}
// Check if it's the end of current word
// and get substring from first to last index of current word
else if (sentence[i] == ' ' && prev != ' ') {
*myArray = sentence.substr(firstCharIndex, i - firstCharIndex);
myArray++;
}
prev = sentence[i];
}
// For the last word
if (firstCharIndex != -1 && sentence[sentence.size() - 1] != ' ') {
*myArray = sentence.substr(firstCharIndex, sentence.size() - firstCharIndex);
}
}
How to think like a programmer.
The first thing we need is definitions of the beginning or a word and the end of a word. You might think that the beginning of a word is a non-space preceded by a space and the end of a word is a non-space followed by a space. But those definitions are wrong because they ignore the possibility of words at the start or end of the string. The correct definition of the beginning of a word is a non-space at the start of the string or a non-space preceded by a space. Similarly the end of a word is a non-space at the end of the string or a non-space followed by a space.
Now we have the definitions we capture them in two functions. It's very important to break complex problems down into smallier pieces and the way to do that is by writing functions (or classes).
bool beginning_of_word(string str, int index)
{
return str[index] != ' ' && (index == 0 || str[index - 1] == ' ');
}
bool end_of_word(string str, int index)
{
return str[index] != ' ' && (index == str.size() - 1 || str[index + 1] == ' ');
}
Now we're getting closer, but we still need the idea of finding the next start of word, or the next end of word, so we can loop through the sentence finding each word one at a time. Here are two functions for finding the next start and next end of word. They start from a given index and find the next index that is the start or end of a word. If no such index is found they return -1.
int next_beginning_of_word(string str, int index)
{
++index;
while (index < str.size())
{
if (beginning_of_word(str, index))
return index; // index is a start of word so return it
++index;
}
return -1; // no next word found
}
int next_end_of_word(string str, int index)
{
++index;
while (index < str.size())
{
if (end_of_word(str, index))
return index; // index is an end of word so return it
++index;
}
return -1; // no next word found
}
Now we have a way of looping through the words in a sentence we're ready to write the main loop. We use substr to break the words out of the sentence, substr takes two parameters the index of the start of the word and the length of the word. We can get the length of the word by substracting the start from the end and adding one.
int populateMyArray(string* array, string sentence)
{
// find the first word
int start = next_beginning_of_word(sentence, -1);
int end = next_end_of_word(sentence, -1);
int count = 0;
while (start >= 0) // did we find it?
{
// add to array
array[count] = sentence.substr(start, end - start + 1);
++count;
// find the next word
start = next_beginning_of_word(sentence, start);
end = next_end_of_word(sentence, end);
}
return count;
}
Now for extra credit we can rewrite countWords using next_beginning_of_word
int countWords(string sentence)
{
int start = next_beginning_of_word(sentence, -1);
int count = 0;
while (start >= 0)
{
++count;
start = next_beginning_of_word(sentence, start);
}
return count;
}
Notice the similarity of the countWords and the populateMyArray functions, the loops are very similar. That should give you confidence.
This is the way programmers work, when you have a problem that is too complex for you to handle, break it down into smaller pieces.

Why am I getting this error breaking my program? C++

I have a program for my c++ class that for some reason keeps breaking when I get to a certain point in my program.
Here is the header file of my
// This class has overloaded constructors.
#ifndef INVENTORYITEM_H
#define INVENTORYITEM_H
#include <string>
using namespace std;
class InventoryItem
{
private:
string description; // The item description
double cost; // The item cost
int units; // Number of units on hand
int inventoryItemNumber; //Used to sort items from first entered to last
public:
// Constructor #1
InventoryItem()
{ // Initialize description, cost, and units.
description = "";
cost = 0.0;
units = 0; }
// Constructor #2
InventoryItem(string desc)
{ // Assign the value to description.
description = desc;
// Initialize cost and units.
cost = 0.0;
units = 0; }
// Constructor #3
InventoryItem(string desc, double c, int u)
{ // Assign values to description, cost, and units.
description = desc;
cost = c;
units = u; }
// Mutator functions
void setDescription(string d)
{ description = d; }
void setCost(double c)
{ cost = c; }
void setUnits(int u)
{ units = u; }
// Accessor functions
string getDescription() const
{ return description; }
double getCost() const
{ return cost; }
int getUnits() const
{ return units; }
};
#endif
And this is my cpp file containing my main:
#include "InventoryItem.h"
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
using namespace std;
int main(){
InventoryItem item[1000];
string parsingArray[1000];
char command;
ifstream inFile;
string inFileName;
//The typecasting variables from string to int,string,double,int
//other possible integers ROUND 2
int itemNumber;
string description;
double cost;
int units;
//possible variables:
int count = 0;
int jTracker = 0;
string parsingArray2[1000];
while(true){
cout << "Command: ";
cin >> command; cin.ignore(80, '\n');
if (command == 'a') {
//Add parts: increase the units value for an existing inventory item.
}
else if (command == 'h') {
//Prints Help Text
cout << "Supported commands: \n"
<< " a Add parts.\n"
<< " h print Help text.\n"
<< " i Input inventory data from a file.\n"
<< " p Print invetory list.\n"
<< " n New invetory Item.\n"
<< " o Output invetory data to a file.\n"
<< " q quit (end the program).\n"
<< " r Remove Parts.\n"
<< endl;
}
else if (command == 'i') {
//Input inventory data from a file.
do{
cout << "Enter name of input file: ";
getline(cin, inFileName);
inFile.open(inFileName);
if (inFile.fail())
{
cout << "Failed to open file: " << inFileName << "\n\n";
}
}while(inFile.fail());
//write each line to string
for (int i = 0; inFile; i++) {
getline(inFile, parsingArray[i], '\n');
count++;//count will be needed for counting iterations of for loop for InventoryItem object data field completion
}
for (int k = 0; k < count; k++)
{
int newLine = 0;
int num = 0;
int oldDelimiter = 0, newDelimiter = 0;
int variable = 0;
for (int j = jTracker; num < variable; j++) {//jTracker continues to grow through multiple outer "k" loops.
newDelimiter = parsingArray[k].find("|", oldDelimiter); //newDelimiter becomes the further pipe delimiter in the line.
parsingArray2[j] = parsingArray[k].substr(oldDelimiter, ((newDelimiter)-oldDelimiter));//the pipe delimited strings are isolated in input2[]
oldDelimiter = newDelimiter + 1;//oldDelimiter is set to the next pipe delimiter.
variable = parsingArray[k].length();
//The following alters variables as needed for the next loop
num = newDelimiter;
jTracker = (j + 1);
newLine = j;
}
}
for(int y = 0; y < count; y++)
{
int itemNumber = stoi(parsingArray2[0+(4*y)]);
string description = parsingArray2[1+(4*y)];
double costs = stof(parsingArray2[2+(4*y)]);
int unit = stoi(parsingArray2[3+(4*y)]);
item[itemNumber].setDescription(description);
item[itemNumber].setCost(costs);
item[itemNumber].setUnits(unit);
}
cout << count << " records loaded to array.\n";
}
else if (command == 'p') {
}
else if (command == 'j') {
}
else if (command == 'o') {
}
else if (command == 'q') {
// Quit.
cout << "Exit." << endl;
system("pause");
return 0;
}
else if (command == 'r') {
}
else {
// Invalid user input, re-prompted.
cout << "Invalid command.\n";
}
}
}
The assignment was to create a program that does all the actions described in the help menu. I started with "i" which is to input text files' information into an array of InventoryItem onjects, containing description of item, cost of item and total number of item units. Also, inventoryitem # should be included, but the array spot held by the object is the same as the item number, so a variable isn't needed.
I try running the program, it runs. I type in "i" as my command. It asks for a file to input, I use the file "plumbing.txt". Plumbing.txt contains the following pipe-delimited text:
0|Pump|39.00|20
1|Gasket|1.50|29
2|Water Level Gauge|12.99|30
3|Faucet Repair Kit|4.89|8
4|Teflon Thread Seal Tape (50 ft roll)|3.30|12
5|shutoff valve|6.50|10
Once i hit enter after typing in "plumbing.txt", the program programs.
It looks like this:
"command: i
Enter file name for input: plumbing.txt"
And then the program breaks.
I narrowed down the part of the code to what actually causes the program to break and its something in this part of the code:
for(int y = 0; y < count; y++)
{
int itemNumber = stoi(parsingArray2[0+(4*y)]);
string description = parsingArray2[1+(4*y)];
double costs = stof(parsingArray2[2+(4*y)]);
int unit = stoi(parsingArray2[3+(4*y)]);
item[itemNumber].setDescription(description);
item[itemNumber].setCost(costs);
item[itemNumber].setUnits(unit);
}
Please help me figure out why my program keeps breaking. I cannot figure it out. I'm trying to read the input as strings from the file, parse the strings into individual pieces of data. Convert from string to integer or double using stoi or stof and enter the info into the array of objects. Thank you for reading and any help you can offer.
There are two issues with your code involving the use of for loops when it is better to use while. The first issue involves the block of code:
for (int i = 0; inFile; i++) {
getline(inFile, parsingArray[i], '\n');
count++;//count will be needed for counting iterations of for loop for InventoryItem object data field completion
}
Here, count is incremented even after we have reached the end of the file. As a result, count will be one more than the number of lines in the file. We can use a while loop instead:
while (getline(inFile, parsingArray[count], '\n'))
++count;
Here, getline will set the end-of-file flag for the inFile ifstream when the last line is read so that the while loop exits. With count initialized to zero before this while loop, the resulting count will correctly reflect the number of lines in the file.
The second issue involves the block of code:
for (int j = jTracker; num < variable; j++) {//jTracker continues to grow through multiple outer "k" loops.
newDelimiter = parsingArray[k].find("|", oldDelimiter); //newDelimiter becomes the further pipe delimiter in the line.
parsingArray2[j] = parsingArray[k].substr(oldDelimiter, ((newDelimiter)-oldDelimiter));//the pipe delimited strings are isolated in input2[]
oldDelimiter = newDelimiter + 1;//oldDelimiter is set to the next pipe delimiter.
variable = parsingArray[k].length();
//The following alters variables as needed for the next loop
num = newDelimiter;
jTracker = (j + 1);
newLine = j;
}
As pointed out by others, num and variable are both set to zero before this for loop so that the condition num < variable is never met. Therefore, the code within the for loop is never executed. Again, a while loop here will do:
while ((newDelimiter = parsingArray[k].find("|", oldDelimiter)) != std::string::npos) {
parsingArray2[j] = parsingArray[k].substr(oldDelimiter, ((newDelimiter)-oldDelimiter)); //the pipe delimited strings are isolated in input2[]
oldDelimiter = newDelimiter + 1; //oldDelimiter is set to the next pipe delimiter.
++j; // increment j
}
// get the last token and increment j
parsingArray2[j] = parsingArray[k].substr(oldDelimiter, std::string::npos); //the pipe delimited strings are isolated in input2[]
++j;
Here, find will return std::string::npos if there are no more delimiters (i.e., "|") to find. With j initialized to zero before the outer k for loop, this while loop will parse all tokens delimited by "|" except for the last one. Therefore, after the while loop, we extract the last substring using std::string::npos to denote that we want all characters from oldDelimiter until the end of the string. Note that the variables newLine, num, variable, and jTracker are all not needed.
In fact, we can combine the two while loops to get:
std::string line; // don't need parsingArray any more
int j = 0; // initialize j before looping over file
while (std::getline(inFile, line, '\n')) {
int oldDelimiter = 0, newDelimiter = 0;
while ((newDelimiter = line.find("|", oldDelimiter)) != std::string::npos) {
parsingArray2[j] = line.substr(oldDelimiter, ((newDelimiter)-oldDelimiter)); //the pipe delimited strings are isolated in input2[]
oldDelimiter = newDelimiter + 1; //oldDelimiter is set to the next pipe delimiter.
++j; // increment j
}
// get the last token and increment j
parsingArray2[j] = line.substr(oldDelimiter, std::string::npos); //the pipe delimited strings are isolated in input2[]
++j;
// increment count
++count;
}
which eliminates the need for the outer k for loop. Note also that the array parsingArray is no longer needed as there is no longer a need to store intermediate results accumulated from one loop to be iterated over and used in a subsequent loop.
Additional notes to consider:
Use std::vector instead of fixed size arrays for std::string and InventoryItem.
Declare variables "locally" for reasons discussed in this link.
In the subsequent for loop that sets the items, there is an assumption that the file contains exactly four tokens for each line (and that the tokens are exactly the item number (integer number), description (character string), cost (real number), and unit (integer number) in that order). You should carefully consider what will happen if the file does not satisfy this requirement (i.e., input data error), and how your program should handle all error cases. Maybe the code within that loop can be incorporated within the nested while loops so that errors can be detected and properly handled as the file is being parsed?

Capitalizing individual characters in string array

I have to capitalize the first and last name in my string array, but I'm stuck on how to access the specific value after I input my string value into an array.
Here are my two functions, the first one reads the values into two separate arrays, and the second is supposed to capitalize the first and last names while changing all other characters to lower case.
void read(string names[],int DVDrent[],int& n)
{
n=0; // # of data calculated
cin >> names[n] >> DVDrent[n]
while(cin)
{
n++;
cin >> names[n] >> DVDrent[n];
}
}
void reformat(string& names)
{
int nlen;
nlen = names.length();
names[0] = toupper(names[0]);
for (int i=1; i<nlen; i++)
{
if (names[i] == ',')
names[i+1] = toupper(names[i+1]);
names[i+2] = tolower(names[i+2]);
}
}
My second function works if I do simply store my data as a string. I'm stuck right now because I'm not sure how to read the specific characters of my array.
For reference, the data that I enter is as follows.
./a.out < data > output
Data:
smith,EMILY 3
Johnson,Daniel 2
williAMS,HanNAH 0
joneS,Jacob 4
bROwn,MicHAEL 5
DAVIS,ETHAn 2
millER,soPhiA 0
TAYlor,matthew 1
andERSON,aNNa 7
Desired output:
Smith,Emily 3
Johnson,Daniel 2
William,Hannah 0
.
.
.
Anderson,Anna 7
etc.
Try this for your reformat() method:
void reformat(string& names) {
bool isUpper = true; // store if the next letter should be upper
for(size_t i = 0; i < names.length(); ++i) {
if (names[i] == ',') {
isUpper = true; // if it's a comma, make the next letter upper
}
else if (isUpper) {
names[i] = toupper(names[i]);
isUpper = false; // make the next letter lower
}
else {
names[i] = tolower(names[i]);
}
}
}

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