Strings; substrings. Not understanding a block of codes - c++

This is a program that creates a username for a user who enters their first name and last name.
Username = user's first initial + up to 7 letters of user's last name.
Ex: John Smith becomes 'jsmith'
John Smoother becomes 'jsmoothe'
#include <iostream>
#include <string>
using namespace std;
int main()
{
string fullname, fname, lname, uname, u2;
int l, len;
cout<<"FULLNAME: ";
getline(cin, fullname);
l=fullname.length();
cout<<"Fullname length: "<<l<<endl;
/*
len=0;
while (len!=(l-1))
{
if (fullname[len]!=' ')
len++;
else
break;
}
fname=fullname.substr(0,len);
lname=fullname.substr(len+1, (l-len));
*/
cout<<"FName: "<<fname<<endl;
cout<<"LName: "<<lname<<endl;
if(isupper(fname[0]))
{
fname[0]=fname[0] + 32;
}
if(isupper(lname[0]))
{
lname[0]=lname[0] + 32;
}
cout<<"FName: "<<fname<<endl;
cout<<"LName: "<<lname<<endl;
uname=fname.substr(0,1);
u2=lname.substr(0,7);
uname+=u2;
cout<<"USERNAME: "<<uname;
return 0;
}
I am having difficulties understand the block of codes i put between comments (/.../).

It is a silly code so do not try to understand it. It would have been much better if you had wrote the code by yourself. In this case, you would not ask such a question.
The author of the code tries to count first non-space characters and then to extract them using method substr and to place them in fname. Remaining characters are placed in lname.
Take into account that the code is invalid. For example the entered string can start with blanks. Also between the two names there can be more than one blank.
Also, it would have been much better if it was written for example
fname[0] = tolower( fname[0] );
instead of
fname[0]=fname[0] + 32;
And I think you need to convert all the characters of names to lower case.

It is simple ,if your string is "John Hoffman",len will equal to 4

Related

How to find the position of the first blank in a string

So I have an array of names and I need to find the position of the blank and put anything that comes before it into fname and put everything that comes after the blank into lname. I have absolutely no idea what I'm doing and I got help from my teacher and she gave me the 3 lines of code that come after posit_of_blank, fname and lname and said that all I had to do was figure out what goes in place of the ... and I haven't got a clue.
using namespace std;
#include "PersonNameFileCreator.h"
#include "PersonName.h"
int main()
{
string arr_names[] = {"Adam Burke", "Madeline Kramer", "Scott Gardner",
"Tonya Lopez", "Christoper Hamilton",
"Andrew Mitchell", "Lori Smith" };
PersonNameFileCreator fil_names("names.txt);
for (auto one_name : arr_names)
{
int posit_of_blank = ?
string fname = ?
string lname = ?
PersonName onePerson(fname, lname);
fil_names.write_to_file(onePerson);
}
return 0;
}
If you refer to the std::string documentation, it will have what you need.
Given a string std::string name = "Justin Jones" you can find the space using the std::string::find() or the std::string::find_first_of() function. From the example above, you can find the space with unsigned int spacePosition = name.find(" ");. This will return the position of the space and then you can use the std::string::substr function to split it where you need it.
Here is a link to the find function: https://cplusplus.com/reference/string/string/find/
Here is a link to the substr function: https://cplusplus.com/reference/string/string/substr/

how do i detect a spacebar in a getline/cin and not ignore it or split it into two inputs?

lets say im making a getline. like I want to getline (cin, employeecode), and when the user
enters the employee code and they typed something like, A 05, I want to detect the spacebar in the center and then give an appropriate error message, how would I tackle something like that, I do not want to just just normal cin as that makes it into two input ( A as 1st input, 05 as 2nd input )and if I use cin.ignore() I cant detect the space bar as it ignores the space bar. I tried something with the ASCII value of spacebar, which is 32, so when it detects the the value of 32 it will do something but I dont know how to implement that either.
If you just want to read upto spacebar(that is a space) then you can use:
std::getline(std::cin, line, ' ');
The above will stop when a space is read. You can try out the program here.
So lets say you have the program:
#include<iostream>
int main(){
std::string line;
std::getline(std::cin, line, ' ');
std::cout<<line<<std::endl;
}
Then if the user enters the string Anoop Rana then only the first name Anoop is read into the variable line and everything after the space is not read into the variable line.
Edit
If you want to check whether the input given by the user has a space and then print out some message like invalid input if it has a space, you can use:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name;
getline(cin, name);
if(name.find(' ')!= string::npos)//check whether the input has a space or not
{
cout<<"Invalid input"<<endl;
}
else
{
cout<<"Input Is Correct"<<endl;
}
return 0;
}

I have made a program in C++ to separate words from a line by spacebar and display those words as an array. What's wrong in my code?

Please help me to find a bug in this program.It separates a line into words by spacebar. And display as a list.
If the first char of a word is in lower case, it is converted to uppercase.
#include <iostream>
#include <string>
using namespace std;
int main()
{
char line[30]="Hi there buddy",List[10][20];
unsigned int i=0,List_pos=0,no;
int first=0,last;
while(i!=sizeof(line)+1)
{
if(line[i]==' ' or i==sizeof(line))
{
last=i;
no=0;
for(int j=first;j<last;++j)
{
if(no==0)
List[List_pos][no]=toupper(line[j]);
else
List[List_pos][no]=line[j];
++no;
}
++List_pos;
first=last+1;
}
++i;
}
for(unsigned int a=0;a<List_pos;++a)
cout<<"\nList["<<a+1<<"]="<<List[a];
return 0;
}
Expected Output:
List[1]=Hi
List[2]=There
List[3]=Buddy
Actual Output:
List[1]=Hi
List[2]=ThereiXŚm
List[3]=Buddy
I suggest you use a string, as you already included it. And 'List is not really necessary in this situation. Try making a single for loop where you separate your line into words, in my opinion when you work with arrays you should use for loops. In your for loop, as you go through the line, you could just add a if statement which determines whether you're at the end of a word or not. I think the problem in your code is the multiple loops but I am not sure of it.
I provide you a code which works. Just adapt it to your display requirements and you will be fine
#include <iostream>
#include <string>
using namespace std;
int main()
{
string line = "Hi there buddy";
for (int i = 0; i < line.size(); i++) {
if (line[i] == ' ') {
line[i + 1] = toupper(line[i+1]);
cout<<'\n';
} else {
cout<<line[i];
}
}
return 0;
} ```
Challenged by the comment from PaulMcKenzie, I implemented a C++ solution with 3 statements:
Define a std::string, with the words to work on
Define a std::regex that finds words only. Whitespaces and other delimiters are ignored
Use the std::transform to transform the input string into output lines
std::transform has 4 parameters.
With what the transformation should begin. In this case, we use the std::sregex_token_iterator. This will look for the regex (so, for the word) and return the first word. That's the begin.
With what the transformation should end. We use the empty std::sregex_token_iterator. That means: Do until all matches (all words) have been read.
The destination. For this we will use the std::ostream_iterator. This will send all transformed results (what the lambda returns) to the given output stream (in our case std::cout). And it will add a delimiter, here a newline ("\n").
The transormation function. Implemented as lambda. Here we get the word from the std::sregex_token_iterator and transform it into a new word according to what we want. So, a word with a capitalized first letter. We add a little bit text for the output line as wished by the OP.
Please check:
#include <string>
#include <iostream>
#include <regex>
#include <iterator>
int main()
{
// 1. This is the string to convert
std::string line("Hi there buddy");
// 2. We want to search for complete words
std::regex word("(\\w+)");
// 3. Transform the input string to output lines
std::transform(
std::sregex_token_iterator(line.begin(), line.end(), word, 1),
std::sregex_token_iterator(),
std::ostream_iterator<std::string>(std::cout, "\n"),
[i = 1](std::string w) mutable {
return std::string("List[") + std::to_string(i++) + "]=" + static_cast<char>(::toupper(w[0])) + &w[1];
}
);
return 0;
}
This will give us the following output:
List[1]=Hi
List[2]=There
List[3]=Buddy
Please get a feeling for the capabilities of C++
Found a solution for your next problem (when the user inputs a sentence only the first word it displayed). When you input a "space", the cin just thinks you are done. You need to use the getLine() to get the whole sentence.
getline(cin, line);
Instead of
cin>>line;

getline to split string manipulation error

Hey guys so I have an assignment for class where I have to split a string and manipulate it. However, when I try to split the string and assign it to an array only the first element comes and the other two don't. Please help.
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
int main()
{
string str;
cout<<"Enter a first name, middle initial, last name: ";
cin>> str;
string word;
string array[3];
stringstream stream(str);
int counter = 0;
while( getline(stream, word, ' ') )
{
cout<<word;
array[counter] = word;
counter++;
}
cout<<"The "<<array[0].length()<<" characters of the first name are: "<<array[0]<<endl;
cout<<"The "<<array[2].length()<<" characters of the last name are: "<<array[2]<<endl;
string newstring = array[2]+", "+array[0]+" "+array[1];
cout<<"In the phone book, the name would be: "<<newstring<<endl;
cout<<"The length of the name is: "<<newstring.length()<<endl;
cout<<"The comma is at position: "<<newstring.find(",")<<endl;
array[0].swap(array[2]);
cout<<"After the swap, the last name is "<<array[2]<<" and the first name is "<<array[0];
system("pause");
return 0;
}
There are a few blatant errors in your code:
You need to always check your input after trying to read! You do that using the while-loop but you also need to verify that you actually successfully read the string first.
It seems you are mixing the what the input operator for std::string and std::getline() are doing: the input operator reads the first word after skipping leading spaces while std::getline() read, well, a line (whether the line terminator can be specified as third argument).
When reading fixed sized array you always need to make sure you do not read more than fits into this array! You may have heart about hackers exploiting software by using buffer overruns: assuming you'd actually indeed read a line first followed by splitting it into words you'd have created one of those exploitable programs! If you don't want to check before each word if there is enough space in the array, you'd use, e.g., a std::vector<std::string> (doing so also has a problem with hackers, namely that it opens up the program for a Denial of Service attack but although this is still a problem it is a somewhat lesser problem).
There are also a few smaller issues with your program, too:
If you are only reading from a string stream, you should use std::istringstream as there is no need to also set up the writing part of the std::stringstream.
The programs asks for "first name, middle name, and last name". I would read that specification to use, e.g., "John, F., Kennedy" but it seems you'd expect "John F. Kennedy". One reason I would expect that commas are to be used is that I don't have a middle name, i.e., I would enter "Dietmar, , Kühl".

Input from text file, not displaying correctly, why?

Here is some part of my main:
int main() {
Inventory Master;
bool flag;
Customer Bob("Bob", "CreditCard.txt");
Customer Chris("Chris", "CreditCard.txt" );
}
Here is my method:
Customer::Customer( string n, string fileName ) {
name = n;
ifstream Credit;
Credit.open(fileName.c_str(), ios::in);
while( Credit.good() && !Credit.eof() ) {
Credit >> card >> balance >> ws;
cout << card <<"\t" << balance << endl;
}
CreditCard _CC( int card, double balance);
}
Here is my "CreditCard.txt file:
12345 15.00
32564 20.00
The way I wanted the info to display is have line 1 "12345 15.00" assigned to Bob and line 2 assigned to Chris and do that so on and so forth if i make new instances or objects of a customer. However the way I currently implemented it is it keeps assigning "12345 15.00 and 32564 20.00" to both Bob and Chris. I could appreciate the help if someone could SHOW me how to somehow point to certain lines of the text file so Bob is assigned to line 1, Chris to line 2, and more customers to other lines when i add them in the text file.
Everything you're doing to Bob and Chris happens inside the constructor. So, as written, your code says: while the stream is in good condition and it's not the end of the file(key point), write to here.
Well, if you think about it, this will read until the end of the file is reached for each instance of Customer. That's not what you want. I might suggest adding the name as the first field in the data file for each record. You could then search the file for the correct record, assuming you ensure the names are all uniquely defined, then pull the data out string by string. That way it's not reading from the beginning to the end each time. I added "Bob" as the first field on line 1, and "Chris" to line 2 and made string name = "Chris";. So...
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
string tempStr;
string name = "Chris";
ifstream Credit;
Credit.open("Info.txt", ios::in);
while( Credit.good() && !Credit.eof() )
{
getline(Credit, tempStr, ' ');//Reads the first records name field
cout << tempStr << endl;
if(name.compare(tempStr) == 0)//Compares the "name" to the field.
{ //If true they are the same
//Proceed to do reading and assignments with additional getline statements
cout << "Chris was matched the second time around!";
Credit.setstate(ios::eofbit, true);//***Sets eof to true
}
else
{
Credit.ignore(50, '\n');
//That should put Credit in the proper position to read the next name
}
}
}
The way you're doing it will cause problems. The only way that it would work for sure is if you knew where the record was at in the file. What if you had five records? By the time you got to the third one you would have to ignore, or similar, all the fields prior to the one you're working on. Also, it could be handy for a human to read a print out of the data file. Another reason to provide a label(name) to each record. Also, you're apparently using namespace std;, so I did too, but it's frowned upon.
istream.getline() http://www.cplusplus.com/reference/iostream/istream/getline/ could be your answer. Just read one line at a time.
A little example here:
http://www.cplusplus.com/forum/beginner/27799/
Little Example from one of my old homerworks:
ifstream fin(fileName);
char buffer[256];
int count = 0;
if (fin.is_open())
{
while (!fin.eof())
{
fin.getline(buffer, 256);
}
}