To keep it short, I'm quite a beginner at c++ and I'm learning character sequences.
Here's my problem: I'm trying to change every word with an even number of letters to a symbol ( # ), but I think that I'm approaching the problem in a bad way. I get nothing when running it.
#include<iostream>
#include<string.h>
using namespace std;
int main()
{
char s[101];
cin.getline(s,101);
int i;
for(int i=0; i<strlen(s); i++)
{
if(strchr(s,' ')) // searching for a space
{}
else
if((strlen(s)%2==0)) //trying to find if the word has an even number
{
strcat(s,"#"); // I'm sticking the # character to the word and then deleting everything after #.
strcpy(s+i,s+i+1);
cout<<s;
}
else
cout<<"Doens't exist";
}
return 0;
}
the only flow of code which doesnot contain cout is
if(strchr(s,' ')) // searching for a space
{}
so debug this.
Look what will happen if you input a single word with an even number of letters with space at end like abcd . Your program will search for space five times and every time do nothing.
Here is the algorithm I came up with:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
// declare input string and read it
string s;
getline(cin, s);
// declare vector of strings to store words,
// and string tmp to temporarily save word
vector <string> vec;
string tmp = "";
// iterate through each character of input string
for(auto c : s)
{
// if there is space push the word to vector,
// clear tmp string
if (c == ' ')
{
vec.push_back(tmp);
tmp = "";
continue;
}
// add character to temporary string
tmp += c;
}
// push last word to vector
vec.push_back(tmp);
// clear the input string
s = "";
// iterate through each word
for(auto w : vec)
{
// if number of word's characters are odd
// just add the word itself
// otherwise add '#' symbol
(w.size() % 2) ? s += w : s += '#';
s += ' ';
}
// remove last space
s.erase(s.begin() + s.size() - 1, s.begin() + s.size());
cout << s;
}
Your solution (algorithm) is completely wrong! First you should separate each word by space,
if(strchr(s,' '))
then you should find length of separated word and then replace it to #.
Related
Basically I need to check if the characters found in second string can make the first string. The program works, however I have this problem that it doesn't take the character order in mind.
For example if I input:
UMC UniverseCeeMake ==> Yes
but it should input No because UMC != UCM, how can I make it check the character order aswell? can someone assist?
#include <iostream>
#include <string>
using namespace std;
const int MAX = 256;
bool canMakeStr2(string str1, string str2)
{
int count[MAX] = {0};
for (int i = 0; i < str1.length(); i++)
count[str1[i]]++;
for (int i = 0; i < str2.length(); i++)
{
if (count[str2[i]] == 0)
return false;
count[str2[i]]--;
}
return true;
}
int main()
{
int n;
string str1;
string str2;
cin>>n;
for(int i =0;i<n;i++){
cin >> str1 >> str2;
if(str1.length()<=10000 && str2.length()<=10000)
if (canMakeStr2(str2, str1))
cout << "Yes";
else
cout << "No";
}
return 0;
}
As Fabian has alread stated. You approach with counting letters will not work. You will never cover the sequence.
You need to select a different approach. The most easy one is to use the std::strings existing find function.
So, you will go over all characters in the given character set in the correct sequence with a simple range based for loop. Then you can use the find function to check, if the character is existing in the other string.
To ensure the sequence, you must not search always from the beginning, but from the last poasition (+1) where a character was found. This will keep the ensure the sequence.
Example:
UMC UniverseCeeMake
Search for the 'U' starting from the beginning
'U' Found at position 0. Increment start position to 1
Search for 'M' staring from position 1
'M' found at position 11 (already behind the 'C'). Increment start position to 12
Search for a 'C' starting at position 12
Cannot be found --> Result will be "No"
This can be implemented very easyly:
#include <iostream>
#include <string>
bool canMakeStr(std::string toBeChecked, std::string characterSet) {
// Result of function. We assume that it will work
bool result{ true };
// position, where we find a charcted in the string to be checked
size_t position{};
// Go through all characters from the given character set
for (const char c : characterSet) {
// Look, where this character has been found
position = toBeChecked.find(c, position);
// If we could not find the character in the string to be checked
if (position == std::string::npos) {
// Then the result is false
result = false;
break;
}
else {
// Character was found. Now, we implement the solution to check for the sequence
// We will not start to search again at the beginning, but after the just found character
// This will ensure that we keep the sequence
++position;
}
}
return result;
}
int main()
{
// Read the number of test cases
unsigned int numberOfTestCases; std::cin >> numberOfTestCases;
// Work on all test cases
while (numberOfTestCases--) {
// Read the 2 strings
std::string characterSet, toBeChecked; std::cin >> characterSet >> toBeChecked;
// And check for the result
if (canMakeStr(toBeChecked, characterSet))
std::cout << "Yes\n";
else
std::cout << "No\n";
}
return 0;
}
Hey I'm quite new to programming and I'm having trouble using the isalpha function in my programme. This a part of the code for a palindrome class. What I'm trying to do is remove all the non alphabetic characters from the input. So if the user inputs "Hi, How are you" I need to first count the size of the array of just the letters then in my removeNonLetters subclass, I need to get rid of the non alphabetical characters. Can someone please help me with this. Thank you so much!
#include <iostream>
#include <string>
#include <stdio.h>
#include <algorithm>
#include <cctype>
#include <cstring>
#include <ctype.h>
using namespace std;
class palindrome
{
private:
int only_letters_size;
string input_phrase;
string* only_letters;
public:
string inputPhrase();
string removeNonLetters();
string* new_Array;
int size_new_Array;
};
string palindrome::inputPhrase()
{
cout << "Input phrase: "; //asks the user for the input
getline(cin,input_phrase);
size_new_Array = input_phrase.length(); //creating a dynamic array to store
the input phrase
new_Array = new string[size_new_Array];
int i;
for (i=0; i<size_new_Array; i++)
{
new_Array[i]=input_phrase[i];
}
only_letters_size = 0;
while(new_Array[i])
{
if (isalpha(new_Array[i])) //PROBLEM OCCURS HERE
{
only_letters_size=only_letters_size+1;
}
}
cout << only_letters_size << endl;
return new_Array;
}
string palindrome::removeNonLetters()
{
int j=0;
int str_length = new_Array.length(); //string length
only_letters = new string[only_letters_size];
for (int i=0;i<size_new_Array;i++) //PROBLEM OCCURS HERE AS WELL
{
if (isalpha(new_Array[i]))//a command that checks for characters
{
only_letters[j] = new_Array[i];//word without non alphabetical c
characters is stored to new variable
j++;
}
}
cout << only_letters << endl;
return only_letters;
}
I've found the best way to determine if a string is a palindrome is to walk toward the center from both sides. In your case I would just opt to skip non-alpha characters like so.
bool is_palindrome(string mystring)
{
int start = 0, end = mystring.length() - 1;
while (start < end)
{
// Skip over non-alpha characters
while (!isalpha(mystring[start]))
{
start++;
}
while (!isalpha(mystring[end]))
{
end--;
}
if (tolower(mystring[start]) != tolower(mystring[end]))
{
return false;
}
else
{
start++;
end--;
}
}
return true;
}
If you must save the input first and remove nonalpha characters, I would do it like this.
string remove_non_alpha(string mystring)
{
string ret_string = "";
for (int i = 0; i < mystring.length(); i++)
{
if (isalpha(mystring[i]))
{
ret_string += tolower(mystring[i]);
}
}
return ret_string;
}
And then feed the result into the above function.
Sorry for being hard, but your trying far too much copying around. You can achieve all this with one single loop after retrieving your data and all on one single string object (unless you want to keep the original input for some other purposes):
getline(cin,input_phrase);
std::string::iterator pos = input_phrase.begin();
for(char c : input_phrase)
{
if(isalpha(c))
{
*pos++ = tolower(c);
}
}
input_phrase.erase(pos, input_phrase.end());
After that, your string is ready to use...
Explanation:
std::string::iterator pos = input_phrase.begin();
An iterator something similar than a pointer to the internal data of the string. We keep the position to move the alpha only characters to, skipping the non-alpha ones.
for(char c : input_phrase)
Simply iterating over all characters...
if(isalpha(c))
The essential check, is the current character an alpha one?
*pos++ = tolower(c);
If so, convert it to lower case immediately. Assign it to the current string position, and advance the "pointer" (iterator!).
input_phrase.erase(pos, input_phrase.end());
And at very last, drop the remaining part of the string occupied with surplus characters. You might note that there might be some characters you wanted to keep within, but you copied these to a position more to the left already...
I'm trying to build a function that goes through a while or for-loop and finds where the space is, outputs everything before the space, and then erases everything before the space including the space, and then repeats this again.
Any help is much appreciated.
int sentence()
{
string enteredSentence="";
getline(cin,enteredSentence);
string sentenceString(enteredSentence);
int sentenceLength=enteredSentence.size();
cout<<"size of sentence"<<sentenceLength<<endl;
int stringSize=sentenceString.size();
while(stringSize>0)
{
int spaceLoc = enteredSentence.find(" ");
cout<<spaceLoc;
cout<<sentenceString.substr(0,spaceLoc)<<endl;
sentenceString.substr(0,spaceLoc);
cout<<"string before string eraced"<<sentenceString<<endl;
sentenceString.erase (0,spaceLoc);
cout<<"string after string eraced"<<sentenceString<<endl;
stringSize=sentenceString.size();
cout<<"string size is"<<stringSize<<endl;
}
This is how I fixed your code:
#include <iostream>
using namespace std;
int main()
{
string enteredSentence="";
getline(cin,enteredSentence);
string sentenceString(enteredSentence);
int sentenceLength = enteredSentence.size();
cout<<"size of sentence:"<<sentenceLength<<endl;
string::size_type stringSize = sentenceString.size();
while(stringSize > 0)
{
int spaceLoc = sentenceString.find(" "); //there was incorrect var
cout<<spaceLoc<<endl;
if(spaceLoc == string::npos){
cout<<"last part:"<<sentenceString<<endl;
break;
}//check if there are no spaces left
cout<<sentenceString.substr(0,spaceLoc)<<endl;
//the substr line here was redundant
cout<<"string before string erased:"<<sentenceString<<endl;
sentenceString.erase(0, spaceLoc + 1);//also delete the space
cout<<"string after string erased:"<<sentenceString<<endl;
stringSize=sentenceString.size();
cout<<"string size:"<<stringSize<<endl<<endl;
}
return 0;
}
You could use a stringstream.
#include <sstream>
#include <iostream>
using namespace std;
int main(int argc, char* argv[]) {
string enteredSentence; // It's initialized to "" by default, by the way
getline(cin,enteredSentence);
cout<<"size of sentence: "<<enteredSentence.length()<<endl;
istringstream str_in(enteredSentence);
string word;
while(str_in >> word) {
// Do stuff with word
// I believe str_in.str() will also give you the portion that hasn't yet been processed.
}
return 0;
}
I'm not 100% sure that I understand what you want to achieve. But I can help you with find:
It has a second parameter that specifies from where on in the string the search will start:
size_t pos = 0;
while ((pos = str.find(' ', pos)) != std::string::npos) {
std::cout << "Found a space at " << pos << std::endl;
++pos;
}
Reference
With more information on what you actually want your code to do (show example input plus wanted output) I can help you clear the rest of your code.
Currently your description suggests that you want to output the entire string, but in pieces (separated by spaces).
Your code makes a (needless?) copy of your input, generates substrings only to throw them away and doesn't return an int as said in the function declaration.
If you want to tokenize your input then this question has some answers for you.
This question already has answers here:
Reversing order of words in a sentence
(8 answers)
Closed 9 years ago.
How would I go about reversing the order of words in a string? I tried this but it doesn't work:
string sen = "Go over there";
reverse(sen.begin(), sen.end());
But this reverses the entire string but doesn't keep the words in the right order. How do I only reverse the order of words in the string?
I have written many string functions like this before:
// Make copy of this original if you don't wish to destroy in the process
string sen = "Go over there";
// string that will become your reversed string
string newStr = new string();
// A temp variable that will hold the current position of the last separator character
int aChar = -1;
////////////////////////////////////////////////////////////////////////////////////////
// You may want to delete pre and post spaces here
////////////////////////////////////////////////////////////////////////////////////////
// Loop through the entire string until the original is empty
while(sen.length > 0){
// Find the last separator character (in your case a space) within the string
aChar = sen.find_last_of(" ");
// Append the word created from one char forward of the last found separator char
// to the end of the CURRENT version of the original string
newStr += sen.substr(aChar + 1, sen.length - aChar - 1);
// Store a new version of the original string that is the SUBSTRING from beginning (char 0)
// to one char before the last found separator character
sen = sen.substr(0, aChar - 1);
// Need to add the space between the words, but only if the new substring is not empty
if(sen.length > 0) newStr += " ";
}
I have not tested this code, but if the APIs work the way they are intended, algorithmically this should work.
As an API this might look like follows
string reverse(string inStr){
// Make copy of the original so we don't destroy it in the process
string sen = inStr.copy();
// string that will become your reversed string
string newStr();
// A temp variable that will hold the current position of the last separator character
int aChar = -1;
////////////////////////////////////////////////////////////////////////////////////////
// You may want to delete pre and post spaces here
////////////////////////////////////////////////////////////////////////////////////////
// Loop through the entire string until the original is empty
while(sen.length > 0){
// Find the last separator character (in your case a space) within the string
aChar = sen.find_last_of(" ");
// Append the word created from one char forward of the last found separator char
// to the end of the CURRENT version of the original string
newStr += sen.substr(aChar + 1, sen.length - aChar - 1);
// Store a new version of the original string that is the SUBSTRING from beginning
// (char 0) to one char before the last found separator character
sen = sen.substr(0, aChar - 1);
// Need to add the space between the words, but only if the new substring is not empty
if(sen.length > 0) newStr += " ";
}
return newStr;
}
int main(int argc, char *argv[]){
string sen = "Go over there";
string rev = reverse(sen);
}
If the words inside the string are separated by spaces, you can use string.find() inside a while loop to locate the breaks, and then use string.substr() to output the words to a vector. Then you can simply read the vector backwards.
Live Example
If you use C++11, sen.pop_back() gets rid of the last space, otherwise you can check out Remove last character from C++ string for other examples. Secondly, instead of doing std::reverse(output.begin(), output.end()), we just use the reverse iterators rbegin() and rend(). The for loop could be improved definitely, but it does the job.
#include <sstream>
#include <iterator>
#include <algorithm>
#include <iostream>
using namespace std;
int main(int argc, char *argv[]) {
std::vector<std::string> output;
std::string sen = "Go over there";
std::string word = "";
unsigned int len = 0;
for (const auto& c : sen) {
++len;
if (c == ' ' || len == sen.size()) {
if (len == sen.size())
word += c;
output.push_back(word);
word = "";
}
if (c != ' ')
word += c;
}
std::ostringstream oss;
std::copy(output.rbegin(), output.rend(), std::ostream_iterator<std::string>(oss, " "));
sen = oss.str();
sen.pop_back(); // Get rid of last space, C++11 only
std::cout << sen;
}
I am trying to reverse the order of words in a sentence by maintaining the spaces as below.
[this is my test string] ==> [string test my is this]
I did in a step by step manner as,
[this is my test string] - input string
[gnirts tset ym si siht] - reverse the whole string - in-place
[string test my is this] - reverse the words of the string - in-place
[string test my is this] - string-2 with spaces rearranged
Is there any other method to do this ? Is it also possible to do the last step in-place ?
Your approach is fine. But alternatively you can also do:
Keep scanning the input for words and
spaces
If you find a word push it onto stack
S
If you find space(s) enqueue the
number of spaces into a queue Q
After this is done there will be N words on the stack and N-1 numbers in the queue.
While stack not empty do
print S.pop
if stack is empty break
print Q.deque number of spaces
end-while
Here's an approach.
In short, build two lists of tokens you find: one for words, and another for spaces. Then piece together a new string, with the words in reverse order and the spaces in forward order.
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <sstream>
using namespace std;
string test_string = "this is my test string";
int main()
{
// Create 2 vectors of strings. One for words, another for spaces.
typedef vector<string> strings;
strings words, spaces;
// Walk through the input string, and find individual tokens.
// A token is either a word or a contigious string of spaces.
for( string::size_type pos = 0; pos != string::npos; )
{
// is this a word token or a space token?
bool is_char = test_string[pos] != ' ';
string::size_type pos_end_token = string::npos;
// find the one-past-the-end index for the end of this token
if( is_char )
pos_end_token = test_string.find(' ', pos);
else
pos_end_token = test_string.find_first_not_of(' ', pos);
// pull out this token
string token = test_string.substr(pos, pos_end_token == string::npos ? string::npos : pos_end_token-pos);
// if the token is a word, save it to the list of words.
// if it's a space, save it to the list of spaces
if( is_char )
words.push_back(token);
else
spaces.push_back(token);
// move on to the next token
pos = pos_end_token;
}
// construct the new string using stringstream
stringstream ss;
// walk through both the list of spaces and the list of words,
// keeping in mind that there may be more words than spaces, or vice versa
// construct the new string by first copying the word, then the spaces
strings::const_reverse_iterator it_w = words.rbegin();
strings::const_iterator it_s = spaces.begin();
while( it_w != words.rend() || it_s != spaces.end() )
{
if( it_w != words.rend() )
ss << *it_w++;
if( it_s != spaces.end() )
ss << *it_s++;
}
// pull a `string` out of the results & dump it
string reversed = ss.str();
cout << "Input: '" << test_string << "'" << endl << "Output: '" << reversed << "'" << endl;
}
I would rephrase the problem this way:
Non-space tokens are reversed, but preserves their original order
The 5 non-space tokens ‘this’, ‘is’, ‘my’, ‘test’, ‘string’ gets reversed to ‘string’, ‘test’, ‘my’, ‘is’, ‘this’.
Space tokens remain in the original order
The space tokens ‘ ‘, ‘ ‘, ‘ ‘, ‘ ‘ remains in original order between the new order of non-space tokens.
Following is a O(N) solution [N being the length of char array]. Unfortunately, it is not in place as OP wanted, but it does not use additional stack or queue either -- it uses a separate character array as a working space.
Here is a C-ish pseudo code.
work_array = char array with size of input_array
dst = &work_array[ 0 ]
for( i = 1; ; i++) {
detect i’th non-space token in input_array starting from the back side
if no such token {
break;
}
copy the token starting at dst
advance dst by token_size
detect i’th space-token in input_array starting from the front side
copy the token starting at dst
advance dst by token_size
}
// at this point work_array contains the desired output,
// it can be copied back to input_array and destroyed
For words from first to central words switch word n with word length - n
First use a split function and then do the switching
This pseudocode assumes you don't end the initial string with a blank space, though can be suitably modified for that too.
1. Get string length; allocate equivalent space for final string; set getText=1
2. While pointer doesn't reach position 0 of string,
i.start from end of string, read character by character...
a.if getText=1
...until blank space encountered
b.if getText=0
...until not blank space encountered
ii.back up pointer to previously pointed character
iii.output to final string in reverse
iv.toggle getText
3. Stop
All strtok-solutions work not for your example, see above.
Try this:
char *wordrev(char *s)
{
char *y=calloc(1,strlen(s)+1);
char *p=s+strlen(s);
while( p--!=s )
if( *p==32 )
strcat(y,p+1),strcat(y," "),*p=0;
strcpy(s,y);
free(y);
return s;
}
Too bad stl string doesn't implement push_front. Then you could do this with transform().
#include <string>
#include <iostream>
#include <algorithm>
class push_front
{
public:
push_front( std::string& s ) : _s(s) {};
bool operator()(char c) { _s.insert( _s.begin(), c ); return true; };
std::string& _s;
};
int main( int argc, char** argv )
{
std::string s1;
std::string s( "Now is the time for all good men");
for_each( s.begin(), s.end(), push_front(s1) );
std::cout << s << "\n";
std::cout << s1 << "\n";
}
Now is the time for all good men
nem doog lla rof emit eht si woN
Copy each string in the array and print it in reverse order(i--)
int main()
{
int j=0;
string str;
string copy[80];
int start=0;
int end=0;
cout<<"Enter the String :: ";
getline(cin,str);
cout<<"Entered String is : "<<str<<endl;
for(int i=0;str[i]!='\0';i++)
{
end=s.find(" ",start);
if(end==-1)
{
copy[j]=str.substr(start,(str.length()-start));
break;
}
else
{
copy[j]=str.substr(start,(end-start));
start=end+1;
j++;
i=end;
}
}
for(int s1=j;s1>=0;s1--)
cout<<" "<<copy[s1];
}
I think I'd just tokenize (strtok or CString::Tokanize) the string using the space character. Shove the strings into a vector, than pull them back out in reverse order and concatenate them with a space in between.