I am writing a C++ function that takes in a string of the form "let_varname_=_20" and then it will isolate "varname" to make a new string with my name variable name. I am trying to tell the .at() function to stop iterating through a while loop when it hits a space (the underscores are spaces, I just wanted it to be abundantly clear there was a space). However, it isn't comparing them properly, as it goes to the end of the string completely without stopping (passing by 2 spaces).
void store(std::string exp) {
int finalcount = 4;
char placeholder = ' ';
while (exp.at(finalcount)!=placeholder) {
finalcount++;
}
for (int i = 0; i < exp.size(); i++) {
std::cout << exp.at(i) << std::endl;
}
std::string varname = exp.substr(4, finalcount+1);
std::cout << finalcount + 1 << std::endl;
std::cout << varname << std::endl;
}
I started at index 4 because I know that indexes 0-3 of teh string will be 'l' 'e' 't' and ' '. The print statements were just me checking to see what it was reading versus what I input (and it was reading everything fine, just not comparing properly). I also tried have my while loop condition say while the char was >65 && <90 to work with ASCII codes but that also didn't work.
Thanks in advance for the help.
You could use istringstream and treat the string as a stream:
const std::string test_data = "let varname = 20";
std::istringstream test_stream(test_data);
std::string let_text;
std::string var_name;
char equals_sign;
unsigned int value;
test_stream >> let_text >> var_name >> equals_sign >> value;
This may be a lot easier than your code.
Edit 1: Searching the string
You could also use the std::string methods, find_first_of and find_first_not_of.
std::string::size_type position = test_data.find_first_of(' ');
position = test_data.find_first_not_of(' ', position);
std::string::size_type end_position = test_data.find_first_of(' ');
let_text = test_data.substr(position, end_position - position);
The problem is that you aren't using substr() properly, as I mentioned in a comment. Also, as Pete Becker mentioned in a comment, you should also be checking for = and stopping when you reach the end of the string, so that you don't overrun your string if there aren't any more spaces in it. Additionally, you don't want to add 1 to finalcount when determining substring length, because then your substring will include the space or = that made the check fail.
Try this:
void store(std::string exp) {
const int start = 4; // <-- Enter starting position here.
const char placeholder_space = ' '; // Check for space.
const char placeholder_equal = '='; // Check for equals sign, as pointed out by Pete Becker.
int finalcount = start; // <-- Use starting position.
bool found = false;
while (finalcount < exp.size() && !found) {
if (!((exp.at(finalcount) == placeholder_space) ||
(exp.at(finalcount) == placeholder_equal))) {
finalcount++;
} else {
found = true;
}
}
if (!found) {
std::cout << "Input is invalid.\n"; // No ' ' or '=' found, put error message here.
return;
}
for (int i = 0; i < exp.size(); i++) {
std::cout << exp.at(i) << std::endl;
}
std::string varname = exp.substr(4, finalcount - start); // <-- Use starting position.
std::cout << finalcount - start << std::endl; // Length of varname.
std::cout << varname << std::endl;
}
Related
I want to print a subword, after inputting my symbol.
For example like this.
I want input abcdefghijk d
And get efghijk
This is my code body without condition.
#include <iostream>
int main(){
const int n = 21;
char word[n];
std::cin>>word;
char symbol;
std::cin>>symbol;
int i = 0;
char*p = word;
while(word[i]!='\0' && word[i]!=symbol){
// what condition I need to write here?
i++;
std::cout << p <<std::endl;
}
return 0;
}
Thanks for helping))
You need to move your pointer p to the right while the splitting character is not met.
char*p = word;
while(word[i]!='\0' && word[i]!=symbol){
p++;
i++;
}
p++;
std::cout << p << std::endl;
On the first line, your pointer p points to the begining of the word (i.e. on the first char).
Then the while loop tests every char until we find the splitting char. Everytime a character does not match you splitting character, you increase p and make it point to the next character.
However, you would need to increase it one final time after the loop to point after the splitting char.
Note that a shorter way to do is:
char*p = word;
while(word[i]!='\0' && word[i]!=symbol){
i++;
}
p = p + i + 1;
std::cout << p << std::endl;
You could try something like this:
int main()
{
std::string text;
std::cout << "Enter sentence: ";
std::getline(std::cin, text);
char split_char;
std::cout << "Enter subword / split character: ";
std::cin >> split_char;
std::string::size_type split_position = text.find(split_char);
std::string::size_type word_end_position = text.find_first_of(" \t", split_position);
if (word_end_position == std::string::npos)
{
word_end_position = text.length();
}
std::string split_text = text.substr(split_position, word_end_position, split_position);
std::cout << split_text << "\n";
return 0;
}
I want to remove 3 characters after a full stop (.) and would like to exclude the last full stop in my string as well as all full stops that end a sentence (defined as full stop + space (. )).
My code thus far removes all full stops + 3 chars:
string test = "I would .asdlike to.aed remove a.thell these inserts.";
string target = ".";
int found=-1;
do{
found = test.find(target,found+1);
if(found!=-1){
test=test.substr(0,found)+test.substr(found+4);
}
}
while(found != -1);
cout << test << endl;
Unfortunately, I keep on getting an error with the final full stop in a string and it removes 3 chars when a string includes more than one sentence separated by a full stop (identified as (. )).
Any Thoughts?
The string class has a useful erase function for you, which I demonstrate here:
std::string test = "I would .asdlike to.aed remove a.thell these inserts. And also keep.asd mult.weriple sentences.";
char target = '.';
std::string::iterator stringIter;
for(stringIter = test.begin(); stringIter != test.end(); stringIter++) {
if (*stringIter == target && stringIter < test.end() - 3 && *(stringIter+1) != ' ') {
test.erase(stringIter, stringIter+4);
}
}
std::cout << test << std::endl;
Really simple and put together relatively quickly.
And the output is:
I would like to remove all these inserts. And also keep multiple sentences.
I'd do like this:
#include <string>
#include <iostream>
void solve(std::string &str, char target) {
std::string s;
for (int i = 0; i < str.size();) {
if (str[i] == target) {
if (i + 4 >= str.size() and str[i] == target) s.push_back(str[i]);
i += 4;
} else {
s.push_back(str[i]);
i++;
}
}
str = s;
}
int main() {
std::string test = "I would .asdlike to.aed remove a.thell these inserts.";
solve(test, '.');
std::cout << test << std::endl;
return 0;
}
Outut:
I would like to remove all these inserts.
I'm extremely new to C++ and I have an assignment to first format a name provided via the user, and then ensure it has proper capitalization (First letter capital, rest lowercase).
I feel like I have the function correct, but the function involves an array and the code I have written does not seem to allow a string to be initialized to the array.
The output of the first stretch of code is then input into the capitalize function and that is where I am running into an error.
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
void capitalize(char str[]);
int main()
{
//inputs user name in the format first, middle and last name
string name;
cout << "Enter your name in the order of first middle last: ";
getline(cin, name, '\n');
//string variables to extract the first. middle and last names
//from the input
string first, last, middle, subOutput;
// finds the poisiton of first space
int firstblank = name.find(' ', 0);
// taken as first name until the first space
first = name.substr(0, firstblank);
// finds second space
int secondblank = name.find(' ', firstblank + 1);
// if second space is not found means no middle name in the input
if (secondblank == -1)
{
// taken the remaining string as last name
last = name.substr(firstblank + 1);
// prepares name as desired output
subOutput = last + ", " + first;
}
else
{
// gets middle name from firstspace to second space
middle = name.substr(firstblank + 1, secondblank - firstblank - 1);
// gets last name
last = name.substr(secondblank + 1);
//prepares output
subOutput = last + ", " + first + " " + middle.at(0) + ".";
}
char O[] = subOutput;
capitalize(O);
cout << O << endl;
//displays output
//cout << O << endl;
return 0;
}
void capitalize(char str[]) {
if (strlen(str) == 0) {
return;
}
str[0] = toupper(str[0]);
for (int i = 1; i < strlen(str); i++)
{
str[1] = tolower(str[i]);
}
}
Might be a very basic fix but like I said, I am very new to coding/C++ so any help is greatly appreciated!
EDIT:
I actually revised my code and I believe I have some of the solution, however
there is a bug that I am unsure about.
New Code:
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
const int CAPACITY = 1000;
void capitalize(string& str);
int main()
{
//inputs user name in the format first, middle and last name
//string variables to extract the first. middle and last names
string name, first, last, middle, subOutput, Output;
cout << "Enter your name in the order of first middle last: ";
getline(cin, name, '\n');
//from the input
// finds the poisiton of first space
int firstblank = name.find(' ', 0);
// taken as first name until the first space
first = name.substr(0, firstblank);
// finds second space
int secondblank = name.find(' ', firstblank + 1);
// if second space is not found means no middle name in the input
if (secondblank == -1)
{
// taken the remaining string as last name
last = name.substr(firstblank + 1);
// prepares name as desired output
subOutput = last + ", " + first;
}
else
{
// gets middle name from firstspace to second space
middle = name.substr(firstblank + 1, secondblank - firstblank - 1);
// gets last name
last = name.substr(secondblank + 1);
//prepares output
subOutput = last + ", " + first + " " + middle.at(0) + ".";
}
capitalize(subOutput);
Output = subOutput;
cout << Output << endl;
return 0;
}
void capitalize(string& str) {
if (str.length() == 0) {
return;
}
str[0] = toupper(str[0]);
for (int i = 1; i < str.length(); i++)
{
str[i] = tolower(str[i]);
}
}
The code compiles and formats properly, however when capitalizing, it only properly capitalizes the last name properly. I am not sure how I can get it to capitalize everything though. Like I said, any help is greatly appreciated!
Use to std::toupper(string[0]) to capitalise the first character. It's builtin function.
You are already using many of the std::basic_string functions, why not simply use the .begin() and .end() iterators and iterate over each character in the string keeping track of the last (previous) character seen and if the last character was whitespace (or a '.' indicating an initial), capitalize the current character, otherwise set to lowercase?
It is actually shorter and simpler. All of the std::basic_string functions are listed. All you need do is:
...
#include <cctype>
/* convert string to Titlecase */
void strtotitle (std::string& name)
{
char last = ' '; /* initialize last as whitespace */
for (std::string::iterator i = name.begin(); i != name.end(); i++) {
if (isspace(last) || last == '.')
*i = toupper(*i); /* convert 1st in word toupper */
else
*i = tolower(*i); /* convert remaining tolower */
last = *i; /* save current char as last */
}
}
Adding a short main() to take the users input you could do:
#include <iostream>
#include <string>
#include <cctype>
/* convert string to Titlecase */
void strtotitle (std::string& name)
{
char last = ' '; /* initialize last as whitespace */
for (std::string::iterator i = name.begin(); i != name.end(); i++) {
if (isspace(last) || last == '.')
*i = toupper(*i); /* convert 1st in word toupper */
else
*i = tolower(*i); /* convert remaining tolower */
last = *i; /* save current char as last */
}
}
int main (void) {
std::string name {};
std::cout << "enter name: ";
if (!getline (std::cin, name)) {
std::cerr << "(user canceled input)\n";
return 1;
}
strtotitle (name);
std::cout << "formatted : " << name << "\n";
}
It provides much more flexibility than searching manually for the first or second space, etc..
Example Use/Output
$ ./bin/name2title
enter name: alPHRED c. fudSTER
formatted : Alphred C. Fudster
or
$ ./bin/name2title
enter name: mICKEy mOUSe
formatted : Mickey Mouse
or
$ ./bin/name2title
enter name: m.m. disNey
formatted : M.M. Disney
You can also easily add an additional function to trim leading and trailing whitespace and compress multiple included whitespace to a single space allowing you to fully format even the strangest input.
Look things over and let me know if you have further questions.
When you are in c++. Why C-Styled char array. Library string has so m inbuilt function try them. Try this instead. C style arrays are often error-prone. Try to use C++ functions and libraries.
int main()
{
string s;
getline(cin,s);
decltype(s.size()) i = 0;
do{
if(i==0 || isspace(s[i-1]))
{
s[i] = toupper(s[i]);
}
else{
s[i] = tolower(s[i]);
}
++i;
}while(i!= s.size());
cout<<s;
return 0;}
comment if you found it hard to understand.
I'm creating a program that counts how many words there are in a input file. I can't seem to figure out how to make it define a word with either whitespace, a period, a comma, or the beginning or end of a line.
Contents of input file:
hello world ALL is great. HELLO WORLD ALL IS GREAT. hellO worlD alL iS great.
Output should be 15 words meanwhile my output is 14
I've tried adding or's that include periods, commas etc. but it just counts those on top of the spaces as well.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
//Function Declarations
void findFrequency(int A[], string &x);
void findWords(int A[], string &x);
//Function Definitions
void findFrequency(int A[], string &x)
{
//Counts the number of occurences in the string
for (int i = 0; x[i] != '\0'; i++)
{
if (x[i] >= 'A' && x[i] <= 'Z')
A[toascii(x[i]) - 64]++;
else if (x[i] >= 'a' && x[i] <= 'z')
A[toascii(x[i]) - 96]++;
}
//Displaying the results
char ch = 'a';
for (int count = 1; count < 27; count++)
{
if (A[count] > 0)
{
cout << A[count] << " : " << ch << endl;
}
ch++;
}
}
void findWords(int A[], string &x)
{
int wordcount = 0;
for (int count = 0; x[count] != '\0'; count++)
{
if (x[count] == ' ')
{
wordcount++;
A[0] = wordcount;
}
}
cout << A[0] << " Words " << endl;
}
int main()
{
string x;
int A[27] = { 0 }; //Array assigned all elements to zero
ifstream in; //declaring an input file stream
in.open("mytext.dat");
if (in.fail())
{
cout << "Input file did not open correctly" << endl;
}
getline(in,x);
findWords(A, x);
findFrequency(A, x);
in.close();
system("pause");
return 0;
}
The output should be 15 when the result I am getting is 14.
Perhaps this is what you need?
size_t count_words(std::istream& is) {
size_t co = 0;
std::string word;
while(is >> word) { // read a whitespace separated chunk
for(char ch : word) { // step through its characters
if(std::isalpha(ch)) {
// it contains at least one alphabetic character so
// count it as a word and move on
++co;
break;
}
}
}
return co;
}
Here is an approach with a few test cases as well.
The test cases are a series of char arrays with particular strings to test the findNextWord() method of the RetVal struct/class.
char line1[] = "this is1 a line. \t of text \n "; // multiple white spaces
char line2[] = "another line"; // string that ends with zero terminator, no newline
char line3[] = "\n"; // line with newline only
char line4[] = ""; // empty string with no text
And here is the actual source code.
#include <iostream>
#include <cstring>
#include <cstring>
struct RetVal {
RetVal(char *p1, char *p2) : pFirst(p1), pLast(p2) {}
RetVal(char *p2 = nullptr) : pFirst(nullptr), pLast(p2) {}
char *pFirst;
char *pLast;
bool findNextWord()
{
if (pLast && *pLast) {
pFirst = pLast;
// scan the input line looking for the first non-space character.
// the isspace() function indicates true for any of the following
// characters: space, newline, tab, carriage return, etc.
while (*pFirst && isspace(*pFirst)) pFirst++;
if (pFirst && *pFirst) {
// we have found a non-space character so now we look
// for a space character or the end of string.
pLast = pFirst;
while (*pLast && ! isspace(*pLast)) pLast++;
}
else {
// indicate we are done with this string.
pFirst = pLast = nullptr;
}
}
else {
pFirst = nullptr;
}
// return value indicates if we are still processing, true, or if we are done, false.
return pFirst != nullptr;
}
};
void printWords(RetVal &x)
{
int iCount = 0;
while (x.findNextWord()) {
char xWord[128] = { 0 };
strncpy(xWord, x.pFirst, x.pLast - x.pFirst);
iCount++;
std::cout << "word " << iCount << " is \"" << xWord << "\"" << std::endl;
}
std::cout << "total word count is " << iCount << std::endl;
}
int main()
{
char line1[] = "this is1 a line. \t of text \n ";
char line2[] = "another line";
char line3[] = "\n";
char line4[] = "";
std::cout << "Process line1[] \"" << line1 << "\"" << std::endl;
RetVal x (line1);
printWords(x);
std::cout << std::endl << "Process line2[] \"" << line2 << "\"" << std::endl;
RetVal x2 (line2);
printWords(x2);
std::cout << std::endl << "Process line3[] \"" << line3 << "\"" << std::endl;
RetVal x3 (line3);
printWords(x3);
std::cout << std::endl << "Process line4[] \"" << line4 << "\"" << std::endl;
RetVal x4(line4);
printWords(x4);
return 0;
}
And here is the output from this program. In some cases the line to be processed has a new line in it which affects the output by performing a new line when printed to the console.
Process line1[] "this is1 a line. of text
"
word 1 is "this"
word 2 is "is1"
word 3 is "a"
word 4 is "line."
word 5 is "of"
word 6 is "text"
total word count is 6
Process line2[] "another line"
word 1 is "another"
word 2 is "line"
total word count is 2
Process line3[] "
"
total word count is 0
Process line4[] ""
total word count is 0
If you need to treat punctuation similar to white space, as something to be ignored, then you can modify the findNextWord() method to include the ispunct() test of characters in the loops as in:
bool findNextWord()
{
if (pLast && *pLast) {
pFirst = pLast;
// scan the input line looking for the first non-space character.
// the isspace() function indicates true for any of the following
// characters: space, newline, tab, carriage return, etc.
while (*pFirst && (isspace(*pFirst) || ispunct(*pFirst))) pFirst++;
if (pFirst && *pFirst) {
// we have found a non-space character so now we look
// for a space character or the end of string.
pLast = pFirst;
while (*pLast && ! (isspace(*pLast) || ispunct (*pLast))) pLast++;
}
else {
// indicate we are done with this string.
pFirst = pLast = nullptr;
}
}
else {
pFirst = nullptr;
}
// return value indicates if we are still processing, true, or if we are done, false.
return pFirst != nullptr;
}
In general if you need to refine the filters for the beginning and ending of words, you can modify those two places with some other function that looks at a character and classifies it as either a valid character for a word or not.
#include <iostream>
#include <string>
#include <cctype>
size_t countwords(const char *);
using namespace std;
int main()
{
char a[] = "Four score and seven years ago";
float sum = 0.0;
char j[10];
string s;
int size = sizeof(a)/sizeof(char);
for(int i = 0; i < size; i++){
if(!isspace(a[i])){
s += a[i];
}
if(isspace(a[i]) and !isspace(a[i + 1])){
cout << s << " " << s.length() << endl;
sum += s.length();
s = "";
}
}
cout << countwords(a);
return 0;
}
size_t countwords( const char *s )
{
size_t count = 0;
while ( *s )
{
while ( isspace( *s )) ++s;
if ( *s ) ++count;
while ( isalnum( *s )) ++s;
}
return ( count );
}
In the main function, I am able to print each word and it's word length. such as four 4, score 5 etc. I am having trouble handling the last word "ago." I don't know how to account for that. Any help would be appreciated.
Output:
Four 4
score 5
and 3
seven 5
years 5
▼ 2
6
and yeah, don't know why that black triangle is in the output but this is the exact output.
The terminating NULL character is not considered whitespace, so your second if condition returns false when it encounters the end of the string.
Seems to me the statements within the for statement can be simplified to
if(!isspace(a[i]) && a[i]){
s += a[i];
} else {
cout << s << " " << s.length() << endl;
sum += s.length();
s = "";
}
Also, breaking the string apart at whitespace can be done easily using an istringstream
char a[] = "Four score and seven years ago";
std::istringstream ss(a);
std::string s;
while(ss >> s) {
std::cout << s << ' ' << s.length() << '\n';
}
The string you try to inspect is one character longer than you expect:
int size = sizeof(a)/sizeof(char);
This size includes the terminating null character. If I were to deal with the assignment I would either operator on char const* and use the C convention of checking against a terminating null character or I would convert the array into a std::string and deal with iterator and check against the end iterator. I also think that the logic you have to check against the end of a word assumes that words are separated by exactly one space.
Your countwords() function seems to deal with the C convention. Your main() function should check against a[i] being null before using !isspace(static_cast<unsigned char>(a[0])): the countwords() works because isspace(0) and isalnum(0) are false. However, just because 0 isn't a space it means it is part of a word. You should also consider the terminating null character a word separator, i.e., the condition to report the length of a word should be
if(!a[i] || isspace(static_cast<unsigned char>(a[i])))
std::string word;
std::istringstream str(a);
while (str >> word) {
sum += str.length();
std::cout << word << ' ' << word.length << '\n';
}