I'll say first that sending my code a hardcoded, perfectly formatted string works fine. But when letting user input string, the code parses areaCode but fails during exchange parsing. Here is my .h
// PhoneNumber.h
#ifndef PHONENUMBER_H
#define PHONENUMBER_H
#include <string>
class PhoneNumber {
private:
short areaCode;
short exchange;
short line;
public:
PhoneNumber(std::string number);
void setPhoneNumber(std::string number);
std::string getPhoneNumber() const;
void printPhoneNumber() const;
};
#endif
Here is my .cpp implementation
// PhoneNumber.cpp
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <cctype>
#include <stdexcept>
#include "PhoneNumber.h"
PhoneNumber::PhoneNumber(std::string number) {
setPhoneNumber(number);
}
void PhoneNumber::setPhoneNumber(std::string number) {
int length = number.length();
std::istringstream iss(number);
int count = 0;
while (!isdigit(number[count])) {
count += 1;
iss.ignore(1);
}
iss >> std::setw(3) >> areaCode;
count += 3;
while (!isdigit(number[count])) {
count += 1;
iss.ignore(1);
}
iss >> std::setw(3) >> exchange;
count += 3;
while (!isdigit(number[count])) {
count += 1;
iss.ignore(1);
}
if (length - count < 4) {
throw std::invalid_argument("Something wrong with your phone number input");
}
else {
iss >> std::setw(4) >> line;
}
}
void PhoneNumber::printPhoneNumber() const {
std::cout << "(" << areaCode << ") " << exchange << "-" << line;
}
And now my short test code.
// PhoneNumber testing
#include <iostream>
#include <string>
#include "PhoneNumber.h"
int main() {
std::string p1;
std::cout << "Enter phone number in format of (800) 555-1212: ";
std::cin >> p1;
PhoneNumber phone1(p1);
phone1.printPhoneNumber();
std::cout << std::endl;
}
I have tried to write my setPhoneNumber code so that it is user error tolerant. So first question is how do I make this work with user input? Secondary (need not be answered) why does it work with hardcoded telephone number string and not user input?
std::cin >> p1;
will only read to the first space or carriage return. So, if the user inputs (800) 555-0123, you'll only read "(800)".
You need
std::getline(std::cin, p1);
to read the input.
The reason it works with a hardcoded string is that the string assignment operator is not affected by this. When you code p1 = "(800) 555-0123";, p1 gets set to "(800) 555-0123"
Related
I am trying to this function to return without numbers, spaces, or other characters and I am supposed to use the .erase function. I understand that my loop keeps going out of range, but I have no clue how to fix it and I've been stuck on this for a while. If the user types "dogs are a lot of fun" and I need the function to return and output "dogsarealotoffun" Thanks for the help.
#include <iostream>
#include <cctype>
#include <cstring>
using namespace std;
//function to output string without spaces, numbers, or punctuations
string alphabetOnly (string input){
int size;
int i= 0;
size = (int)input.size();
while (input[i] < size){
if (isalpha(input[i])){
i++;
}
else
input.erase(input[i]);
}
return input;
}
int main() {
string input;
cout << "Enter a string to test: ";
getline(cin, input);
cout << "alphabetOnly: " << alphabetOnly(input) << endl;
}
EDITED: I was too hasty in my previous answer (as I am learning I need to speak from tested code rather than off the top of my head) and needed to debug. The problem is in the else case you need to erase the char, NOT increment i because the length of the string just changed, and also since the length of the string changed you need to reset size to be the new length. Sorry for the hasty answer earlier, I was speaking without actually using the compiled code.
#include <iostream>
#include <cctype>
#include <string>
//function to output string without spaces, numbers, or punctuations
std::string alphabetOnly (std::string input){
int size;
int i= 0;
size = (int)input.size();
while (i < size){
if (isalpha(input[i])){
i++;
}
else{
input.erase(i,1);
//do not increment i here since the index changed becauase of erase
size = (int)input.size();
}
}
return input;
}
int main() {
std::string input;
std::cout << "Enter a string to test: ";
std::getline(std::cin, input);
std::cout << input;
std::cout << "alphabetOnly: " << alphabetOnly(input) << std::endl;
return 0;
}
something like this:
#include <iostream>
#include <string>
#include <algorithm>
//function to output string without spaces, numbers, or punctuations
std::string alphabetOnly (std::string input)
{
auto not_alpha = [](char c) { return !std::isalpha(c); };
input.erase(std::remove_if(begin(input),
end(input),
not_alpha),
std::end(input));
return input;
}
int main() {
std::string input;
std::cout << "Enter a string to test: ";
getline(std::cin, input);
std::cout << "alphabetOnly: " << alphabetOnly(input) << std::endl;
}
http://coliru.stacked-crooked.com/a/340465d41ecd8c8e
There's quite a few things wrong with your code, but to start with here's your main error corrected.
#include <iostream>
#include <cctype>
#include <cstring>
using namespace std;
//function to output string without spaces, numbers, or punctuations
string alphabetOnly (string input){
int size;
int i= 0;
size = (int)input.size();
while (i < size){
if(isalpha(input[i]))
{
i++;
}
else
input.erase(input.begin( ) + i );
}
return input;
}
int main() {
string input;
cout << "Enter a string to test: ";
getline(cin, input);
cout << "alphabetOnly: " << alphabetOnly(input) << endl;
}
But this is awfully inefficient because you swhift all the remaining unchecked characters each time you delete.
You should use something like
input.erase( remove_if( input.begin(), input.end(), not( isalpha ) ), input.end( ));
This is known as the remove-erase idiom, whihc you can lookup anywhere.
I'm new to C++.
In a part of a simple project, I have to enter a number and verify that it is positive and not an alphanumeric sequence. With the following code I perform the "check for alphanumeric sequence" but in which way I can add the "positive check"?
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
string getline()
{
string str;
getline(cin, str);
return str;
}
int main()
{
int choice;
istringstream iss(getline());
iss >> choice >> ws;
if(iss.fail() || !iss.eof())
{
cout << "Error" << endl;
}
}
Thank you in advance!!
I'm working on a problem where I need to have user input a message then replace the work "see" with "c". I wanted to read in the array message[200] and then break it down into individule words. I tried a for loop but when I concatinate it just adds the privous words. I am only to use array of characters, no strings.
const int MAX_SIZE = 200;
int main(){
char message[MAX_SIZE]; //message array the user will enter
int length; // count of message lenght
int counter, i, j; //counters for loops
char updateMessage[MAX_SIZE]; //message after txt update
//prompt user to
cout << "Please type a sentence" << endl;
cin.get(message, MAX_SIZE, '\n');
cin.ignore(100, '\n');
length = strlen(message);
//Lower all characters
for( i = 0; i < length; ++i)
{
message[i] = tolower(message[i]);
//echo back sentence
cout << "You typed: " << message << endl;
cout << "Your message length is " << length << endl;
for( counter = 0; counter <= length; ++counter)
{
updateMessage[counter] = message[counter];
if(isspace(message[counter]) || message[counter] == '\0')
{
cout << "Space Found" << endl;
cout << updateMessage << endl;
cout << updateMessage << " ** " << endl;
}
}
return 0;
}
After each space is found I would like to output one work each only.
You should really try to learn some modern C++ and standard library features, so you don't end up writing C code in C++. As an example, this is how a C++14 program makes use of standard algorithms from the library to do the job in 10-15 lines of code:
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
int main()
{
using namespace std::string_literals;
std::istringstream input("Hello I see you, now you see me");
std::string str;
// get the input from the stream (use std::cin if you read from console)
std::getline(input, str);
// tokenize
std::vector<std::string> words;
std::istringstream ss(str);
for(std::string word ; ss >> word; words.push_back(word));
// replace
std::replace(words.begin(), words.end(), "see"s, "c"s);
// flatten back to a string from the tokens
str.clear();
for(auto& elem: words)
{
str += elem + ' ';
}
// display the final string
std::cout << str;
}
Live on Coliru
This is not the most efficient way of doing it, as you can perform replacement in place, but the code is clear and if you don't need to save every bit of CPU cycles it performs decently.
Below is a solution that avoids the std::vector and performs the replacement in place:
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
int main()
{
std::istringstream input("Hello I see you, now you see me");
std::string str;
// get the input from the stream (use std::cin if you read from console)
std::getline(input, str);
// tokenize and replace in place
std::istringstream ss(str);
std::string word;
str.clear();
while (ss >> word)
{
if (word == "see")
str += std::string("c") + ' ';
else
str += word + ' ';
}
// display the final string
std::cout << str;
}
Live on Coliru
I'm not able to figure out why the loop in following program is not running exactly testCount times. Please help to make it correct.
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main() {
size_t testCount;
cin >> testCount;
if(testCount < 0 || testCount > 100) return 0;
int input;
while(testCount--) {
string instr;
getline(cin,instr);
istringstream iss(instr);
while(iss >> input) {
cout << input << endl;
}
}
return 0;
}
Thanks. I got it. The problem is with getline(). First loop cycle is getting wasted as getline() is taking first line containing just new line character when I pressed enter key after typing testCount value.
std::ws is an input stream manipulator which ignores all whitespaces to the point where the first non-whitespace character is encountered.
Also, getline leaves whitespaces where they are if they don't fit in the line. cin >> ws will discard those.
Here's the bullet proof code:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main() {
size_t testCount;
cin >> testCount >> ws;
if(testCount < 0 || testCount > 100) return 0;
int input;
while(testCount--) {
cout << "testCount " << testCount << endl;
string instr;
cin >> ws;
getline(cin,instr);
istringstream iss(instr);
while(iss >> input) {
cout << input << endl;
}
}
return 0;
}
I want to read from a file two things, the full name (first name and last name)
and age. After that I want to store them in an array then print the data.
However, when I try to reading the first record is read find, but the other two are not.
Please tell me what am I missing.
Thank you.
The content of the file is:
sampleFirst1 sampleLast1
30
sampleFirst2 sampleLast2
25
sampleFirst3 sampleLast3
40
The Output is:
Name: sampleFirst1 Age: 30
Name: Age: 30
Name: Age: 30
Here's my Code:
#include "Person.h"
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream inputFile("data.txt", ios::in);
string full_name;
int age = 0;
int i = 0;
Person personArray[3];
while (i < 3)
{
getline(inputFile, full_name);
personArray[i].set_name(full_name);
inputFile >> age;
personArray[i].set_age(age);
++i;
}
inputFile.close();
printData(personArray, 3);
cout << endl;
return 0;
}
You should not mix getline and the >> operator in that way. Prefer a simpler code like this one :
#include <iostream>
#include <fstream>
#include <array>
#include <string>
using namespace std;
struct Person {
std::string name;
int age;
void set_name(std::string const& i_name) { name = i_name; }
void set_age(int i_age) { age = i_age; }
};
int main()
{
ifstream inputFile("data.txt", ios::in);
std::string first;
std::string last;
int age = 0;
int i = 0;
std::array<Person,3> personArray;
while (i < personArray.size()) {
inputFile >> first >> last >> age;
personArray[i].set_name(first + " " + last);
personArray[i].set_age(age);
++i;
}
inputFile.close();
for(Person const& person : personArray) {
std::cout << "Name: " << person.name << " Age: " << person.age << "\n";
}
std::cout << std::flush;
return 0;
}
Or use only getline and a istringstream to pase the age if you dont want to pay the string concatenation extra cost for the full name.
A lot could be said of the parsing method but that is not the point here.