Capitalizing letters in C++ - c++

I have an assignment where the user enters a student name in the format ( last name, first name). Can you help me figure out how to capitalize the first letter for both the first name and the last name?
I was using this to turn the user input into an array, so I could have the first letter capitalized, but when I did this, I had trouble getting it to work outside of the for loop.
for (int x = 0; x < fName.length(); x++)
{
fName[x] = tolower(fName[x]);
}
fName[0] = toupper(fName[0]);

I used your code and just added some parsing around it. You really are very close.
I can't help myself. For user input, I always use getline() followed by a stringstream to parse the words from the line. I find it avoids a lot of edge cases that get me into quicksand.
When getline() gets an input, it returns true unless it has problems. If the user inputs Ctrl-d, it will return false. Ctrl-D is basically an EOF (end of file) code, which works well in this case (as long as you are not trying to input the Ctrl-d from inside your debugger. Mine does not like that.
Note that I am using std::string in place of an array. std::string can be treated like an array for subscripting, but it prints nicely and has other functions that make it better for processing character strings.
#include <iostream>
#include <string> // Allow you to use strings
#include <sstream>
int main(){
std::string input_line;
std::string fName;
std::string lName;
std::cout << "Please enter students as <lastname>, <firstname>\n"
"Press ctrl-D to exit\n";
while(std::getline(std::cin, input_line)){
std::istringstream ss(input_line);
ss >> lName;
// remove trailing comma. We could leave it in and all would work, but
// it just feels better to remove the comma and then add it back in
// on the output.
if(lName[lName.size() - 1] == ',')
lName = lName.substr(0, lName.size() - 1); // Substring without the comma
ss >> fName;
for (int x = 0; x < fName.length(); x++) // could start at x=1, but this works.
{
fName[x] = tolower(fName[x]); // make all chars lower case
}
fName[0] = toupper(fName[0]);
for (int x = 0; x < lName.length(); x++)
{
lName[x] = tolower(lName[x]);
}
lName[0] = toupper(lName[0]);
std::cout << "Student: " << lName << ", " << fName << std::endl;
}
}

Related

Cannot push back a string into a vector of strings c++

I'm trying to create a program to separate a single line into a vector of strings separated by the blank spaces in said line, so turn:
foo bar
into
["foo", "bar"]
This is what I have so far:
string command;
string command_temp;
vector<string> command_seperated;
std::cin >> command;
for (int i = 0; i < command.length(); i++){
if (isspace(command[i])){
cout << "blankspace" << endl; command_seperated.push_back(command_temp);
command_temp.clear();
}
command_temp.push_back(command[i]);
for (int i = 0; i < command_temp.size(); i++){
cout << command_temp[i];
}
cout << endl;
}
for (int i = 0; i < command_seperated.size(); i++){
cout << command_seperated[i] << endl;
}
But, if I input "foo bar" when prompted, this just returns:
foo bar
f
fo
foo
Process returned 0 (0x0) execution time : 2.596 s
Press any key to continue
I assume the reason the last for loop isn't printing anything is that there's nothing in it and the push_back to command_seperated isn't working. I have no idea why.
I also don't know why the entire program seems to just stop working after the first blank space.
Using this to refresh my rudimentary C++ skills, so I would appreciate an explanation of why I'm wrong, rather than a more elegant alternative solution.
What you are seeing is normal behavior of operator>>, which is used for reading formatted input. It skips leading whitespace (if the skipws flag is enabled on the stream, which it normally is), then reads until EOF or whitespace is encountered. So, in your example, std::cin >> command receives only foo even though you entered foo bar. If you invoked std::cin >> command a 2nd time, you would receive bar.
To read a string that contains whitespace in it, use std::getline() instead:
std::getline(std::cin, command);
It does not skip leading whitespace, and reads until EOF or a linebreak (ie, from typing Enter) is encountered.
That being said, the parsing code you have shown can be greatly simplified if you use a std::istringstream with operator>> to parse the command, eg:
std::string command, token;
std::vector<std::string> command_seperated;
std::getline(std::cin, command);
std::istringstream iss(command);
while (iss >> token) {
command_seperated.push_back(token);
}
for (const auto &str : command_seperated){
cout << str << endl;
}

Convert Text with spaces to Camel Case

i want to take a film name from user and change that to camel case , my code work if there is no numbers or spaces between letters
#include <iostream>
#include <string>
using namespace std;
int main()
{
int Count,Length=0;
string Films;
cout<<"Enter Film Count: ";
cin>>Count;
for(int i=0;i<Count;i++)
{
cout<<"Enter Film Names: ";
cin>>Films;
Length=0;
while(Length<1000)
{
switch(Length)
{
case 0: Films[Length]=toupper(Films[Length]); break;
default: Films[Length]=tolower(Films[Length]); break;
}
Length++;
}
cout<<"Results: "<<Films<<endl;
}
return 0;
}
i tried other topic solutions but i cant do it correctly.
Problem:
You've chosen the wrong approach to solve the problem. Your current code only changes the first character to uppercase and the rest to lowercase.
Solution:
Instead of using a while and a switch, use a for loop and an if statement that checks for spaces, delete them and change the following characters to uppercase.
Additional information:
using namespace std; is considered a bad practice (More info here).
The while loop can be replaced for a for loop to limit the Length scope and improve readability.
It's a good practice to check whether the std::cin inputs are valid or not to prevent Undefined Behavior.
Full code:
#include <iostream>
#include <string>
int main()
{
int count;
std::cout << "Enter film count: ";
std::cin >> count;
if(std::cin.fail())
{
std::cout << "Invalid input." << std::endl;
exit(0);
}
std::cin.ignore(10000,'\n');
for(int i = 0; i < count; i++)
{
std::string film;
std::cout << "Enter film name: ";
std::getline(std::cin, film);
if(std::cin.fail())
{
std::cout << "Invalid input." << std::endl;
exit(0);
}
if(film.size() == 0)
break;
film[0] = tolower(film[0]);
for(unsigned int i = 1; i < film.size() - 1; i++)
{
if(film[i] == ' ')
{
film.erase(i,1);
film[i] = toupper(film[i]);
i--;
}
}
std::cout << "Result: " << film << std::endl;
}
return 0;
}
Example:
Enter film count: 1
Enter file name: Love live! the school idol movie
Result: loveLive!TheSchoolIdolMovie
I could see really a lot of code to solve a simple problem. I will later show a one-liner that converts a string with words to camel case.
As a side note, code should always contain tons of comments. Otherwise, nobody will understand it, and later, even you will not understand your own code.
Anyway. Let us look at the requirements. What shall we do?
User shal input the number of film titles to convert
Title for title shall be read from the user
Titles have to converted to camel case style and shown to the user
Now, we think an how we want to solve the problem:
We will always instruct the user what to do next
We will make sanity checks for the users input
We will get the number of titles from the user
Then, we create a loop and read title for title
The current read title will be converted to camel case
The result will be shown to the user
Ok, we need to go into details for "The current read title will be converted to camel case"
Let us think again. We get a string, that consists of words. So, we need to extract words from the string. We consider that everything is a word, that is separated by white space.
Then, depending on the camle case style, please see here, we convert all first letters of a word to uppercase and discard all white spaces. The first word will have a starting lower case letter (selectable).
But how to extract words from a string? We remember the extractor operator >> will discard all white spaces and only read the text. That is what we need. So, we will pack the string into an std::istringstream and then extract word for word.
And with a simple boolean condition, we decide, if the first letter of the first word shall be in upper- or lower case.
So, let us implement or thoughts into code:
#include <iostream>
#include <sstream>
#include <string>
#include <cctype>
int main() {
// Instruct user, what to do
std::cout << "\nPlease end number of film titles to convert: ";
// Read input from the user and check, if that was valid
if (size_t numberOfFilms{}; std::cin >> numberOfFilms && numberOfFilms > 0) {
// Now, in a loop, read all the film titles that the user wants to be processed
for (size_t index{}; index < numberOfFilms; ++index) {
// Instruct user, what to do
std::cout << "\n\nPlease end film title " << index + 1 << ": \t";
// Read a complete line and check, if that worked
if (std::string line{}; std::getline(std::cin >> std::ws, line)) {
// Put the complete string into an istringstream, so that we can extract the words
std::istringstream lineStream{line};
// Here we can select the style of our camel case
bool wordShallHaveFirstLetterInUpperCase{ false };
// Extract all words from the line stream and convert first letter
for (std::string word{}; lineStream >> word; std::cout << word) {
// Depending on the camel case style
if (wordShallHaveFirstLetterInUpperCase)
word[0] = std::toupper(word[0]);
else
word[0] = std::tolower(word[0]);
// From now on all words shall start with an uppercase character
wordShallHaveFirstLetterInUpperCase = true;
}
}
else std::cerr << "\n\n*** Error: Problem while a title\n\n";
}
}
else std::cerr << "\n\n*** Error: Problem while reading the number of ilm titles\n\n";
return 0;
}
This is a rather straight forward implementation of our detailed design. And after running some tests, we see that it will work.
Now, for the more advanced users.
In professional software development, people try to avoid loops and branch statements. Because this will increase the code complexity (usually measured via the cyclomatic complexity). And complex code needs more tests cases for C0, C1 or even MCDC code coverage.
Therefore, often algorithms from the standard library are used. And they hide the loops somehow inside. But that is OK, because the standard library is thoroughly tested and sometimes even qualified with a certification.
So, as one example, you can do the whole camel case conversion with one statement. With std::transform and by using std::regex and iterators and a stateful Lambda.
The downside is, that it is not so easy to understand for the reader . . .
Please see yourself:
#include <iostream>
#include <iterator>
#include <algorithm>
#include <regex>
#include <string>
#include <cctype>
// The separator will be white space
const std::regex re{ R"(\s+)" };
int main() {
// Instruct user, what to do
std::cout << "\nPlease end number of film titles to convert: ";
// Read input from the user and check, if that was valid
if (size_t numberOfFilms{}; std::cin >> numberOfFilms && numberOfFilms > 0) {
// Now, in a loop, read all the film titles that the user wants to be processed
for (size_t index{}; index < numberOfFilms; ++index) {
// Instruct user, what to do
std::cout << "\n\nPlease end film title " << index+1 << ": \t";
// Read a complete line and check, if that worked
if (std::string line{}; std::getline(std::cin >> std::ws, line)) {
// Convert to camel case and show output
std::transform(std::sregex_token_iterator(line.begin(), line.end(), re, -1), {}, std::ostream_iterator<std::string>(std::cout),
[firstIsUpper = 0U](std::string s) mutable {if (firstIsUpper++) s[0] = std::toupper(s[0]); else s[0] = std::tolower(s[0]); return s; });
}
else std::cerr << "\n\n*** Error: Problem while a title\n\n";
}
}
else std::cerr << "\n\n*** Error: Problem while reading the number of ilm titles\n\n";
return 0;
}
Ultra compact, but difficult to read . . .
In case of questions, please ask.

First letters being erased when reading from data file c++

Can someone please explain why only the first letters are being deleted when reading in from a data file but only on the 1/2/3 parts of the array and not the 0 part? (sorry really don't know how to explain it)(I'll only include part of what I am getting as well as data file)
What i get
GoogleyleSmith01#gmail.comyleman27ecurity question:White rabbit with a watch
Deviantartragonmaster27andalfthegreyNULL
What it's supposed to be
GoogleKyleSmith01#gmail.comKyleman27securityquestion:Whiterabbitwithawatch
DeviantartDragonmaster27GandalfthegreyNULL
And the original data file
Google;KyleSmith01#gmail.com;Kyleman27;security question:White rabbit with a watch;
Deviantart;Dragonmaster27;Gandalfthegrey; NULL;
I won't include all of the code as it shouldn't be relevant to this issue
#include<iostream>
#include <fstream>
#include <string>
#include <vector>
#include<sstream>
using namespace std;
const int NCOLS = 4;
const int NROWS = 10;
void description_and_options(string data[][NCOLS], int count[NCOLS]);
void available_options();
void view_line_data(int choice,string data[][NCOLS]);
int main()
{
ifstream file_name;//create the new file
string user_input_file;//the files name inputed by the user
int stringlength;
string read_in_array[NROWS][NCOLS];
string line;
int counter[10] = { 1,2,3,4,5,6,7,8,9,10 };
string user_option_choice;
string small_exit = "x";
string large_exit = "X";
int view_choice;
cout << "Enter the name of the input file: ";
cin >> user_input_file;
if (user_input_file.length() > 4)// check to see if its more than 4 in length
{
stringlength = user_input_file.length(); //saves length
if (user_input_file.substr(stringlength - 4, 4) == ".txt")//checks to see if its .dat
{
file_name.open(user_input_file.c_str());
if (file_name.fail())
{
cerr << "The file " << user_input_file << " failed to open.\n";//tells user if it fails
exit(1);
}
}
}
else
{
user_input_file += ".txt";//adds .dat to non .dat
file_name.open(user_input_file.c_str());
}
if (file_name.fail())
{
cout << "File failed to open" << endl;
system("PAUSE");
exit(1);
}
for (int row = 0; row <= 9; row++)
{
for (int col = 0; col < 4; col++)
{
if (getline(file_name, line, ';'))
{
file_name.ignore(1, '\n');
read_in_array[row][col] = line;
cout << read_in_array[row][col];
}
}
cout << endl;
}
//[updown][leftright]
file_name.close();
is there anyway to fix this without completely changing the code?
It is ignoring the first character because you tell it to
file_name.ignore(1, '\n');
Is going to ignore the first character in the stream after each call to getline. It looks like you are doing this because you think the ; in the file it still there. What you need to remember about getline is that it discards the delimiter you use. That means it will read until it finds a ; and then it tosses that ; out. This means you do not need to ignore it since it is no longer there.
Just removing the call to ignore is not enough to fix the issue though. Since you are trying to parse an entire line what we need to do is read the line into a stringstream and then call getline on the stream to get the individual parts. This is because just reading to ; is going to capture the newline.
A quick refactor of your code gives you something that should look like
for (int row = 0; row <= 9; row++)
{
std::string temp;
std::getline(file_name, temp)
std::stringstream ss(temp)
for (int col = 0; col < 4; col++)
{
if (getline(ss, line, ';'))
{
read_in_array[row][col] = line;
cout << read_in_array[row][col];
}
}
cout << endl;
}
You are using wrongly ifstream::ignore().
Extracts characters from the input sequence and discards them, until
either n characters have been extracted, or one compares equal to
delim.
file_name.ignore(1, '\n'); always dismiss the first letter. In your case, the first letter after ";" in line.
file_name.ignore(1, '\n'); will make the stream ignore one character from the input.
From reading your code:
For what you call "the 0 part", ignore is not called yet before the first getline in the loop.
For "parts 1/2/3", the ignore statement makes the stream skip the next character
For the remaining parts, there is either a space or a '\n' that was skipped so that the readable letter was not skipped.

Splitting sentences and placing in vector

I was given a code from my professor that takes multiple lines of input. I am currently changing the code for our current assignment and I came across an issue. The code is meant to take strings of input and separate them into sentences from periods and put those strings into a vector.
vector<string> words;
string getInput() {
string s = ""; // string to return
bool cont = true; // loop control.. continue is true
while (cont){ // while continue
string l; // string to hold a line
cin >> l; // get line
char lastChar = l.at(l.size()-1);
if(lastChar=='.') {
l = l.substr(0, l.size()-1);
if(l.size()>0){
words.push_back(s);
s = "";
}
}
if (lastChar==';') { // use ';' to stop input
l = l.substr(0, l.size()-1);
if (l.size()>0)
s = s + " " + l;
cont = false; // set loop control to stop
}
else
s = s + " " + l; // add line to string to return
// add a blank space to prevent
// making a new word from last
// word in string and first word
// in line
}
return s;
}
int main()
{
cout << "Input something: ";
string s = getInput();
cout << "Your input: " << s << "\n" << endl;
for(int i=0; i<words.size(); i++){
cout << words[i] << "\n";
}
}
The code puts strings into a vector but takes the last word of the sentence and attaches it to the next string and I cannot seem to understand why.
This line
s = s + " " + l;
will always execute, except for the end of input, even if the last character is '.'. You are most likely missing an else between the two if-s.
You have:
string l; // string to hold a line
cin >> l; // get line
The last line does not read a line unless the entire line has non-white space characters. To read a line of text, use:
std::getline(std::cin, l);
It's hard telling whether that is tripping your code up since you haven't posted any sample input.
I would at least consider doing this job somewhat differently. Right now, you're reading a word at a time, then putting the words back together until you get to a period.
One possible alternative would be to use std::getline to read input until you get to a period, and put the whole string into the vector at once. Code to do the job this way could look something like this:
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <iterator>
int main() {
std::vector<std::string> s;
std::string temp;
while (std::getline(std::cin, temp, '.'))
s.push_back(temp);
std::transform(s.begin(), s.end(),
std::ostream_iterator<std::string>(std::cout, ".\n"),
[](std::string const &s) { return s.substr(s.find_first_not_of(" \t\n")); });
}
This does behave differently in one circumstance--if you have a period somewhere other than at the end of a word, the original code will ignore that period (won't treat it as the end of a sentence) but this will. The obvious place this would make a difference would be if the input contained a number with a decimal point (e.g., 1.234), which this would break at the decimal point, so it would treat the 1 as the end of one sentence, and the 234 as the beginning of another. If, however, you don't need to deal with that type of input, this can simplify the code considerably.
If the sentences might contain decimal points, then I'd probably write the code more like this:
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <iterator>
class sentence {
std::string data;
public:
friend std::istream &operator>>(std::istream &is, sentence &s) {
std::string temp, word;
while (is >> word) {
temp += word + ' ';
if (word.back() == '.')
break;
}
s.data = temp;
return is;
}
operator std::string() const { return data; }
};
int main() {
std::copy(std::istream_iterator<sentence>(std::cin),
std::istream_iterator<sentence>(),
std::ostream_iterator<std::string>(std::cout, "\n"));
}
Although somewhat longer and more complex, at least to me it still seems (considerably) simpler than the code in the question. I guess it's different in one way--it detects the end of the input by...detecting the end of the input, rather than depending on the input to contain a special delimiter to mark the end of the input. If you're running it interactively, you'll typically need to use a special key combination to signal the end of input (e.g., Ctrl+D on Linux/Unix, or F6 on Windows).
In any case, it's probably worth considering a fundamental difference between this code and the code in the question: this defines a sentence as a type, where the original code just leaves everything as strings, and manipulates strings. This defines an operator>> for a sentence, that reads a sentence from a stream as we want it read. This gives us a type we can manipulate as an object. Since it's like a string in other ways, we provide a conversion to string so once you're done reading one from a stream, you can just treat it as a string. Having done that, we can (for example) use a standard algorithm to read sentences from standard input, and write them to standard output, with a new-line after each to separate them.

HW Help: get char instead of get line C++

I wrote the code below that successfully gets a random line from a file; however, I need to be able to modify one of the lines, so I need to be able to get the line character by character.
How can I change my code to do this?
Use std::istream::get instead of std::getline. Just read your string character by character until you reach \n, EOF or other errors. I also recommend you read the full std::istream reference.
Good luck with your homework!
UPDATE:
OK, I don't think an example will hurt. Here is how I'd do it if I were you:
#include <string>
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
static std::string
answer (const string & question)
{
std::string answer;
const string filename = "answerfile.txt";
ifstream file (filename.c_str ());
if (!file)
{
cerr << "Can't open '" << filename << "' file.\n";
exit (1);
}
for (int i = 0, r = rand () % 5; i <= r; ++i)
{
answer.clear ();
char c;
while (file.get (c).good () && c != '\n')
{
if (c == 'i') c = 'I'; // Replace character? :)
answer.append (1, c);
}
}
return answer;
}
int
main ()
{
srand (time (NULL));
string question;
cout << "Please enter a question: " << flush;
cin >> question;
cout << answer (question) << endl;
}
... the only thing is that I have no idea why do you need to read string char by char in order to modify it. You can modify std::string object, which is even easier. Let's say you want to replace "I think" with "what if"? You might be better off reading more about
std::string and using find, erase, replace etc.
UPDATE 2:
What happens with your latest code is simply this - you open a file, then you get its content character by character until you reach newline (\n). So in either case you will end up reading the first line and then your do-while loop will terminate. If you look into my example, I did while loop that reads line until \n inside a for loop. So that is basically what you should do - repeat your do-while loop for as many times as many lines you want/can get from that file. For example, something like this will read you two lines:
for (int i = 1; i <= 2; ++i)
{
do
{
answerfile.get (answer);
cout << answer << " (from line " << i << ")\n";
}
while (answer != '\n');
}