Adding Space to String at certain places in C++ - c++

I am having trouble figuring out the process to add a space in a string at capital letters in C++. If I have a string "HelloWorld", how do I convert that to "Hello World"?
I've tried using substrings and the isupper function but I can't get anything to work.
Edit: this is the code I have. I don't understand why in = newname is not valid code.
string breakStringAtCaps(string in) {
string newname[10];
int j = 0;
for (int i = 0; i < in.size(); i++) {
if (isupper(in[i]) && i != 0) {
newname[j] = " ";
j++;
}
newname[j] = in[i];
j++;
}
in = newname;
return in;
}

You can do it like this:
string breakStringAtCaps(const string& in)
{
string newname;
for(int i = 0; i < in.size(); i++)
{
if(isupper(in[i]) && i != 0)
newname += " ";
newname += in[i];
}
return newname;
}

You are thinking right in thinking substr, but you implementation is a bit off. If creating an new string containing the contents of the original and inserting a ' ' (space) before each upper-case letter (not including the first), you can seed the new string with the first character of the original using substr(0,1) and then use an auto ranged for loop and substr(1) to evaluate each character after the first.
The loop along with a check of isupper() is basically all you need, e.g.
#include <iostream>
#include <string>
#include <cctype>
int main (int argc, char **argv) {
std::string s = argc > 1 ? argv[1] : "HelloWorld",
snew = s.substr (0,1);
if (s.size() > 0)
for (auto& c : s.substr(1)) {
if (std::isupper (c))
snew += " ";
snew += c;
}
std::cout << snew << '\n';
}
(the program will use "HelloWorld" by default if no string is given as an argument on the command line, otherwise the string given on the command line is used)
Example Use/Output
$ ./bin/spacebeforeupper
Hello World
Or with a string given as an argument:
$ ./bin/spacebeforeupper MyDogHasFleas
My Dog Has Fleas

You can iterate through the strin characters, check if it is a cap and insert a ' ' before if it is one:
It should look like:
for(int i=0; i < str.length(); i++)
{
if (str[i]>='A' && str[i]<='Z')
{
if (i != 0)
cout << " ";
cout << str[i];
}
else
{
cout << str[i];
}
}

I just give a implementation, maybe not the best solution:
#include <string>
#include <ctype.h>
void breakStringAtCaps(std::string& in) {
std::string::const_iterator it = in.begin();
while(it != in.end()) {
if(it != in.begin() && isupper(*it)) {
in.insert(it, ' ');
it += 2;
}
else
++it;
}
}
//
#include <iostream>
int main(int argc, char** argv) {
std::string str("HelloWorld;");
breakStringAtCaps(str);
std::cout << str.c_str() << std::endl;
return 0;
}
and in your code,
string newname[10];
here 'newname' is a string array's name. you should not assign the name of array to a string instance.
and newname[i] means the i-th string of the array, not the i-th char of a string named 'newname' as you desired.

Related

Why is this program returning the last word and not the longest word?

Why is this program returning garbage values? I expect the output to be the word 'large', but the value is actually 'rat' - the last word.
#include <iostream>
#include <string>
using namespace std;
std::string LongestWord(std::string sen)
{
std::string s2, lW;
for (int i = 0; i < sen.size(); ++i) {
while (sen[i] != ' ') {
s2 += sen[i];
++i;
}
if (s2.size() > lW.size()) {
lW = ""; lW = s2;
}
s2 = "";
}
return lW;
}
int main(void)
{
cout << LongestWord("a cat ate the large rat") << endl;
return 0;
}
Your internal while loop will almost certainly run beyond the end of the given string argument (unless it has a space at the end). Change this internal loop to check for the size of that string, as follows:
while (i < sen.size() && sen[i] != ' ') {
s2 += sen[i];
++i;
}

changing case for first and last letter C++

i need ThE FirsT AnD LasT letter of every word to be uppercase and the rest lowercase but function convertFirstAndLastLetter only does the first and last of the sentence.
void convertFirstAndLastLetter(char wrd[])
{
size_t last = strlen(wrd) - 1;
size_t first = 0;
wrd[first] = toupper(wrd[first]);
wrd[last] = toupper(wrd[last]);
for(int i = first + 1 ; i < last - 1; i++)
{
wrd[i] = tolower(wrd[i]);
}
}
int main ()
{
float val;
cout << "ent ";
cin >> val;
if (val == 4)
{
char wrd[256];
cin.ignore();
cin.getline(wrd,256);
convertFirstAndLastLetter(wrd);
cout << wrd;
return 0;
}
}
Right now you're passing a whole line to your function, so the first and last characters are all that is being changed.
To fix that you need to split the line up into words which could be done by reading a word at a time using std::cin >> word, or reading the whole line and then using a std::stringstream to split it up. Both are about the same, but I used a stringstream.
Next, if I'm reading your statement correctly, you want to have the first and last "letter" of each word uppercase and the rest lowercase. That means we need to find the first and last letter in case there is punctuation before or after the word.
Once the first and last are determined it's easy to uppercase them and lowercase the rest.
#include <iostream>
#include <string>
#include <sstream>
#include <cctype>
void convertFirstAndLastLetter(std::string& word)
{
if(!word.empty())
{
size_t first = 0;
size_t last = word.size() - 1;
//Find first alpha character
while(first < word.size() && !std::isalpha(word[first]))
{
++first;
}
//If the position is valid, uppercase it
if(first < word.size())
{
word[first] = static_cast<char>(std::toupper(word[first]));
}
//Find last alpha character
while(last > first && !std::isalpha(word[last]))
{
--last;
}
//If the position is valid, uppercase it
if(last > first)
{
word[last] = static_cast<char>(std::toupper(word[last]));
}
for(size_t i = first + 1; i < word.size() && i < last; ++i)
{
if(std::isalpha(word[i]))
{
word[i] = static_cast<char>(std::tolower(word[i]));
}
}
}
}
int main()
{
float val;
std::cout << "ent ";
std::cin >> val;
std::cin.ignore();
if(val == 4)
{
std::string line;
if(std::getline(std::cin, line))
{
std::string word;
std::stringstream ss(line);
while(ss >> word)
{
convertFirstAndLastLetter(word);
std::cout << word << " ";
}
std::cout << "\n";
}
}
return 0;
}
Keep in mind this will discard any extra spaces at the beginning and end of each line as well as any extra spaces between words. The way I am printing them out will also add an extra space at the end of each line. You didn't mention any concern about those things in your question, so I didn't worry about them. They are all solvable with a little extra effort.
Now with less duplicated code:
#include <algorithm>
#include <iostream>
#include <string>
template<typename It>
void upperFirstAlpha(It begin, It end)
{
auto first = std::find_if(begin, end, isalpha);
if (first != end)
*first = toupper(*first);
}
int main()
{
for (std::string s; std::cin >> s;) {
std::transform(s.begin(), s.end(), s.begin(), tolower);
upperFirstAlpha(s.begin(), s.end());
upperFirstAlpha(s.rbegin(), s.rend());
std::cout << s << ' ';
}
}
As #Retired Ninja pointed out the first version wouldn't work for punctuation, whether this version is what you are looking for depends on what your input looks like.
This function
void convertFirstAndLastLetter(char wrd[])
{
size_t last = strlen(wrd) - 1;
size_t first = 0;
wrd[first] = toupper(wrd[first]);
wrd[last] = toupper(wrd[last]);
for(int i = first + 1 ; i < last - 1; i++)
{
wrd[i] = tolower(wrd[i]);
}
}
is wrong. For example if character array is empty that is it has only the terminating zero then expression strlen(wrd) - 1 will give you the maximum value for an object of type size_t and in the next statement
wrd[last] = toupper(wrd[last]);
you will try to change memory beyond the array.
Also if you use standard function strlen then you have to include header <cstring>.
In fact there is no any need to use function strlen. The code can be written simpler
#include <cctype>
//...
void convertFirstAndLastLetter( char wrd[] )
{
if ( *wrd )
{
*wrd = std::toupper( *wrd );
if ( *++wrd )
{
while ( *( wrd + 1 ) )
{
*wrd = std::tolower( *wrd );
++wrd;
}
*wrd = std::toupper( *wrd );
}
}
}
#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;
void convertFirstAndLastLetter(char wrd[])
{
size_t last = strlen(wrd) - 1;
size_t first = 0;
wrd[first] = toupper(wrd[first]);
wrd[last] = toupper(wrd[last]);
for(int i = first + 1 ; i < last; i++)
{
wrd[i] = tolower(wrd[i]);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
float val;
cout << "ent ";
cin >> val;
if (val == 4)
{
char wrd[256];
cin.ignore();
cin.getline(wrd,256);
convertFirstAndLastLetter(wrd);
cout << wrd;
return 0;
}
}

Returning string from a function causing formatting issues

It's supposed to look like this: http://i.imgur.com/gko501E.png
Instead it looks like this: http://i.imgur.com/ISwqyD8.png
When I take the code out of the function and use it in the main class it works properly. However once I put it in this function the formatting problems occur, it also isn't filtering like it's supposed to. This program is supposed to take user input, store it in a string, remove all non-alphabetical characters, capitalize the vowels, and then space it out based on user defined variables given in the command line. It's also supposed to accept files as input in the command line, such as: 'program 5 8 < file'.
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <cstdlib>
#include <fstream>
#include <sstream>
using namespace std;
//make vowels uppercase
string filter(string input)
{
size_t found = input.find_first_of("aeiou");
while (found != string::npos)
{
if (islower(input[found]))
{
input[found] = toupper(input[found]);
found = input.find_first_of("aeiou", found + 1);
}
}
//Make consonants lowercase
size_t foundLower = input.find_first_of("BCDFGHJKLMNPQRSTVWXYZ");
while (foundLower != string::npos)
{
if (isupper(input[foundLower]))
{
input[foundLower] = tolower(input[foundLower]);
foundLower = input.find_first_of("BCDFGHJKLMNPQRSTVWXYZ", foundLower + 1);
}
}
//remove punctuation
for (int i = 0, len = input.size(); i < len; i++)
{
if (!isalnum(input[i]))
{
input.erase(i--, 1);
len = input.size();
}
}
return input;
}
int main(int argc, char* argv[])
{
int wordSize;
int wordSizeCounter;
int wordCounter = 0;
int rowSize;
//char letter;
wordSize = atoi(argv[1]);
rowSize = atoi(argv[2]);
ifstream inFile;
inFile.open(argv[3]);//open the input file
stringstream strStream;
strStream << inFile.rdbuf();//read the file
string test = strStream.str();//str holds the content of the file
if (!inFile) test = cin.get() ; // Read first character
//Begin filter for files
while (!test.empty())
{
filter(test);
if (test.length() < wordSize) //make sure we don't go out-of-bounds
{
wordSize = test.length();
}
cout << test.substr(0, wordSize);
cout << " ";
if (test.length() >= wordSize) //again, make sure we don't go out-of-bounds
{
test = test.substr(wordSize);
}
else
{
test = " ";
}
wordCounter++;
if (wordCounter == rowSize)
{
cout << std::endl;
wordCounter = 0;
}
if(test.empty())
{
test = cin.get();
}
}
cout << endl;
return 0;
}

Printing input string words in reverse order

Using if and while/do-while, my job is to print following user's inputs (string value) in reverse order.
For example:
input string value : "You are American"
output in reverse order : "American are You"
Is there any way to do this?
I have tried
string a;
cout << "enter a string: ";
getline(cin, a);
a = string ( a.rbegin(), a.rend() );
cout << a << endl;
return 0;
...but this would reverse the order of the words and spelling while spelling is not what I'm going for.
I also should be adding in if and while statements but do not have a clue how.
The algorithm is:
Reverse the whole string
Reverse the individual words
#include<iostream>
#include<algorithm>
using namespace std;
string reverseWords(string a)
{
reverse(a.begin(), a.end());
int s = 0;
int i = 0;
while(i < a.length())
{
if(a[i] == ' ')
{
reverse(a.begin() + s, a.begin() + i);
s = i + 1;
}
i++;
}
if(a[a.length() - 1] != ' ')
{
reverse(a.begin() + s, a.end());
}
return a;
}
Here is a C-based approach that will compile with a C++ compiler, which uses the stack to minimize creation of char * strings. With minimal work, this can be adapted to use C++ classes, as well as trivially replacing the various for loops with a do-while or while block.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE_LENGTH 1000
#define MAX_WORD_LENGTH 80
void rev(char *str)
{
size_t str_length = strlen(str);
int str_idx;
char word_buffer[MAX_WORD_LENGTH] = {0};
int word_buffer_idx = 0;
for (str_idx = str_length - 1; str_idx >= 0; str_idx--)
word_buffer[word_buffer_idx++] = str[str_idx];
memcpy(str, word_buffer, word_buffer_idx);
str[word_buffer_idx] = '\0';
}
int main(int argc, char **argv)
{
char *line = NULL;
size_t line_length;
int line_idx;
char word_buffer[MAX_WORD_LENGTH] = {0};
int word_buffer_idx;
/* set up line buffer - we cast the result of malloc() because we're using C++ */
line = (char *) malloc (MAX_LINE_LENGTH + 1);
if (!line) {
fprintf(stderr, "ERROR: Could not allocate space for line buffer!\n");
return EXIT_FAILURE;
}
/* read in a line of characters from standard input */
getline(&line, &line_length, stdin);
/* replace newline with NUL character to correctly terminate 'line' */
for (line_idx = 0; line_idx < (int) line_length; line_idx++) {
if (line[line_idx] == '\n') {
line[line_idx] = '\0';
line_length = line_idx;
break;
}
}
/* put the reverse of a word into a buffer, else print the reverse of the word buffer if we encounter a space */
for (line_idx = line_length - 1, word_buffer_idx = 0; line_idx >= -1; line_idx--) {
if (line_idx == -1)
word_buffer[word_buffer_idx] = '\0', rev(word_buffer), fprintf(stdout, "%s\n", word_buffer);
else if (line[line_idx] == ' ')
word_buffer[word_buffer_idx] = '\0', rev(word_buffer), fprintf(stdout, "%s ", word_buffer), word_buffer_idx = 0;
else
word_buffer[word_buffer_idx++] = line[line_idx];
}
/* cleanup memory, to avoid leaks */
free(line);
return EXIT_SUCCESS;
}
To compile with a C++ compiler, and then use:
$ g++ -Wall test.c -o test
$ ./test
foo bar baz
baz bar foo
This example unpacks the input string one word at a time,
and builds an output string by concatenating in reverse order.
`
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
string inp_str("I am British");
string out_str("");
string word_str;
istringstream iss( inp_str );
while (iss >> word_str) {
out_str = word_str + " " + out_str;
} // while (my_iss >> my_word)
cout << out_str << endl;
return 0;
} // main
`
This uses exactly one each of if and while.
#include <string>
#include <iostream>
#include <sstream>
void backwards(std::istream& in, std::ostream& out)
{
std::string word;
if (in >> word) // Read the frontmost word
{
backwards(in, out); // Output the rest of the input backwards...
out << word << " "; // ... and output the frontmost word at the back
}
}
int main()
{
std::string line;
while (getline(std::cin, line))
{
std::istringstream input(line);
backwards(input, std::cout);
std::cout << std::endl;
}
}
You might try this solution in getting a vector of string's using the ' ' (single space) character as a delimiter.
The next step would be to iterate over this vector backwards to generate the reverse string.
Here's what it might look like (split is the string splitting function from that post):
Edit 2: If you don't like vectors for whatever reason, you can use arrays (note that pointers can act as arrays). This example allocates a fixed size array on the heap, you may want to change this to say, double the size when the current word amount has reached a certain value.
Solution using an array instead of a vector:
#include <iostream>
#include <string>
using namespace std;
int getWords(string input, string ** output)
{
*output = new string[256]; // Assumes there will be a max of 256 words (can make this more dynamic if you want)
string currentWord;
int currentWordIndex = 0;
for(int i = 0; i <= input.length(); i++)
{
if(i == input.length() || input[i] == ' ') // We've found a space, so we've reached a new word
{
if(currentWord.length() > 0)
{
(*output)[currentWordIndex] = currentWord;
currentWordIndex++;
}
currentWord.clear();
}
else
{
currentWord.push_back(input[i]); // Add this character to the current word
}
}
return currentWordIndex; // returns the number of words
}
int main ()
{
std::string original, reverse;
std::getline(std::cin, original); // Get the input string
string * arrWords;
int size = getWords(original, &arrWords); // pass in the address of the arrWords array
int index = size - 1;
while(index >= 0)
{
reverse.append(arrWords[index]);
reverse.append(" ");
index--;
}
std::cout << reverse << std::endl;
return 0;
}
Edit: Added includes, main function, while loop format
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
// From the post
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems)
{
std::stringstream ss(s);
std::string item;
while(std::getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
return split(s, delim, elems);
}
int main ()
{
std::string original, reverse;
std::cout << "Input a string: " << std::endl;
std::getline(std::cin, original); // Get the input string
std::vector<std::string> words = split(original, ' ');
std::vector<std::string>::reverse_iterator rit = words.rbegin();
while(rit != words.rend())
{
reverse.append(*rit);
reverse.append(" "); // add a space
rit++;
}
std::cout << reverse << std::endl;
return 0;
}
This code here uses string libraries to detect the blanks in the input stream and rewrite the output sentence accordingly
The algorithm is
1. Get the input stream using getline function to capture the spacecs. Initialize pos1 to zero.
2. Look for the first space in the input stream
3. If no space is found, the input stream is the output
4. Else, get the position of the first blank after pos1, i.e. pos2.
5. Save the sub-string bewteen pos1 and pos2 at the beginning of the output sentence; newSentence.
6. Pos1 is now at the first char after the blank.
7. Repeat 4, 5 and 6 untill no spaces left.
8. Add the last sub-string to at the beginning of the newSentence. –
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string sentence;
string newSentence;
string::size_type pos1;
string::size_type pos2;
string::size_type len;
cout << "This sentence rewrites a sentence backward word by word\n"
"Hello world => world Hello"<<endl;
getline(cin, sentence);
pos1 = 0;
len = sentence.length();
pos2 = sentence.find(' ',pos1);
while (pos2 != string::npos)
{
newSentence = sentence.substr(pos1, pos2-pos1+1) + newSentence;
pos1 = pos2 + 1;
pos2 = sentence.find(' ',pos1);
}
newSentence = sentence.substr(pos1, len-pos1+1) + " " + newSentence;
cout << endl << newSentence <<endl;
return 0;
}

Strings with whitespace in a list?

I have this function sentanceParse with a string input which returns a list. The input might be something like "Hello my name is Anton. What's your name?" and then the return value would be a list containing "Hello my name is Anton" and "What's your name?". However, this is not what happens. It seems as if the whitespaces in the sentences are treated like a separator and therefore the return is rather "Hello", "my", "name" etc instead of what I expected.
How would you propose I solve this?
As I am not a 100% sure the problem does not lie within my code, I will add that to the post as well:
Main:
list<string> mylist = sentanceParse(textCipher);
list<string>::iterator it;
for(it = mylist.begin(); it != mylist.end(); it++){
textCipher = *it;
cout << textCipher << endl; //This prints out the words separately instead of the entire sentances.
sentanceParse:
list<string> sentanceParse(string strParse){
list<string> strList;
int len = strParse.length();
int pos = 0;
int count = 0;
for(int i = 0; i < len; i++){
if(strParse.at(i) == '.' || strParse.at(i) == '!' || strParse.at(i) == '?'){
if(i < strParse.length() - 1){
while(i < strParse.length() - 1 && (strParse.at(i+1) == '.' || strParse.at(i+1) == '!' || strParse.at(i+1) == '?')){
if(strParse.at(i+1) == '?'){
strParse.replace(i, 1, "?");
}
strParse.erase(i+1, 1);
len -= 1;
}
}
char strTemp[2000];
int lenTemp = strParse.copy(strTemp, i - pos + 1, pos);
strTemp[lenTemp] = '\0';
std::string strAdd(strTemp);
strList.push_back(strAdd);
pos = i + 1;
count ++;
}
}
if(count == 0){
strList.push_back(strParse);
}
return strList;
}
Your implementation of sentence parse is wrong, here is a simpler correct solution.
std::list<std::string> sentence_parse(const std::string &str){
std::string temp;
std::list<std::string> t;
for(int x=0; x<str.size();++x){
if(str[x]=='.'||str[x]=='!'||str[x]=='?'){
if(temp!="")t.push_back(temp);//Handle special case of input with
//multiple punctuation Ex. Hi!!!!
temp="";
}else temp+=str[x];
}
return t;
}
EDIT:
Here is a full example program using this function. Type some sentences in your console, press enter and it will spit the sentences out with a newline separating them instead of punctuation.
#include <iostream>
#include <string>
#include <list>
std::list<std::string> sentence_parse(const std::string &str){
std::string temp;
std::list<std::string> t;
for(int x=0; x<str.size();++x){
if(str[x]=='.'||str[x]=='!'||str[x]=='?'){
if(temp!="")t.push_back(temp);//Handle special case of input with
//multiple punctuation Ex. Hi!!!!
temp="";
}else temp+=str[x];
}
return t;
}
int main (int argc, const char * argv[])
{
std::string s;
while (std::getline(std::cin,s)) {
std::list<std::string> t= sentence_parse(s);
std::list<std::string>::iterator x=t.begin();
while (x!=t.end()) {
std::cout<<*x<<"\n";
++x;
}
}
return 0;
}
// This function should be easy to adapt to any basic libary
// this is in Windows MFC
// pass in a string, a char and a stringarray
// returns an array of strings using char as the separator
void tokenizeString(CString theString, TCHAR theToken, CStringArray *theParameters)
{
CString temp = "";
int i = 0;
for(i = 0; i < theString.GetLength(); i++ )
{
if (theString.GetAt(i) != theToken)
{
temp += theString.GetAt(i);
}
else
{
theParameters->Add(temp);
temp = "";
}
if(i == theString.GetLength()-1)
theParameters->Add(temp);
}
}