I am trying to write a function that reverses a string. I've figured out most of the code, and when I print the string to std::cout, it's showing what I need. But, when I test the code, the result is that I got " from the function. Here's my code:
#include <iostream>
#include <string>
using namespace std;
string result;
string reverseString (string str)
{
for(int i = str.length(); i >= -1; i--) {
result+= str[i];
}
cout << result;
return result;
}
In this for loop, in the very first iteration:
for(int i = str.length(); i >= -1; i--) {
result+= str[i];
}
The terminating zero character '\0' is being written in the first position of the object result, because the expression str[i] is equivalent in this case to the expression str[str.length()].
So, the result string is outputted as an empty string.
Also, you are trying to access the source string using the negative index -1, which results in undefined behavior.
Instead of this for loop, you could just write:
result.assign( str.rbegin(), str.rend() );
If you want to do the task using the for loop, then the loop can look like the following:
result.clear();
result.reserve( str.length() );
for ( auto i = str.length(); i != 0; ) {
result += str[--i];
}
Pay attention to that, it is a bad idea to use the global variable result within the function. The function could look like:
std::string reverseString( const std::string &str )
{
return { str.rbegin(), str.rend() };
}
I was given a project in class and almost have it finished, I am required to take a string of numbers and letters and return that string with the numbers printed first followed by the letters in reverse order (ex. abc123 should return 123cba). As of now my code returns a string with the numbers first and the original order of the letters (ex. abc123 returns 123abc). I would be able to do this with two loops however the assignment asks that my code only iterates though the initial string one time. Here is the code I have so far...
#include <iostream>
#include <string>
#include "QueType.h"
#include "StackType.h"
using namespace std;
int main ()
{
QueType<char> myQueue;
StackType<char> myStack;
string myString="hello there123";
char curchar;
string numbers, letters;
for (int i = 0; i < myString.length(); i++) {
if (isdigit(myString.at(i))) {
myQueue.Enqueue(myString.at(i));
myQueue.Dequeue(curchar);
numbers += curchar;
//cout<<numbers<<endl;
}
else if (islower(myString.at(i))) {
myStack.Push(myString.at(i));
curchar = myStack.Peek();
myStack.Pop();
letters += curchar;
//cout<<curchar<<endl;
}
}
cout<<(myString = numbers + letters)<<endl;
}
In my code, I have two .h files that set up a stack and a queue. With the given string, the code loops through the string looking to see if it sees a letter or number. With a number the spot in the string is then saved to a queue, and with a letter it is saved to the stack.
The only other way i can think of reversing the order of the letters is in the if else statement instead of having char = myStack.Peek() every loop, change it to char += myStack.Peek() however I get weird lettering when that happens.
since you already got the string with letters you can basically reverse it and that's it.
//emplace version:
void reverse_str(std::string& in)
{
std::reverse(in.begin(), in.end());
}
//copy version
std::string reverse_str(std::string in)
{
std::reverse(in.begin(), in.end());
return in;
}
in your case the emplace version would be the best match.
in other cases (e.g. when you want to preserve the original string) the copy version is preferred.
adding an example to make it as clean as possible.
int main()
{
std::string inputstr = "123abc";
std::string numbers{};
std::string letters{};
for(auto c : inputstr)
{
if(isdigit(c))
numbers += c;
else
letters += c;
}
reverse_str(letters); //using the emplace version
std::cout << numbers + letters;
}
Here's my take. It only loops through the string once. I don't have your types, so I'm just using the std versions.
std::string output;
output.reserve( myString.size() );
std::stack<char> stack;
for ( char c : myString ) {
if ( std::isdigit( c ) ) // if it's a number, just add it to the output
output.push_back( c );
else // otherwise, add the character to the stack
stack.push( c );
}
// string is done being processed, so use the stack to get the
// other characters in reverse order
while ( !stack.empty() ) {
output.push_back( stack.top() );
stack.pop();
}
std::cout << output;
working example: https://godbolt.org/z/eMazcGsMf
Note: wasn't sure from your description how to handle characters other than letters and numbers, so treated them the same as letters.
One way to do this is as follows:
Version 1
#include <iostream>
#include <string>
int main() {
std::string s = "abc123";
std::string output;
output.resize(s.size());
int i = output.length() - 1;
int j = 0;
for(char &c: s)
{
if(!std::isdigit(c))
{
output.at(i) = c;
--i;
}
else
{
output.at(j) = c;
++j;
}
}
std::cout<<output<<std::endl;
}
You can also use iterators in the above program to obtain the desired result as shown in version 2.
Version 2
#include <iostream>
#include <string>
int main() {
std::string s = "abfsc13423";
std::string output;
output.resize(s.size());
std::string::reverse_iterator iter = output.rbegin();
std::string::iterator begin = output.begin();
for(char &c: s)
{
if(!std::isdigit(c))
{
*iter = c;
++iter;
}
else
{
*begin = c;
++begin;
}
}
std::cout<<output<<std::endl;
}
I am using following:
replace (str1.begin(), str1.end(), 'a' , '')
But this is giving compilation error.
Basically, replace replaces a character with another and '' is not a character. What you're looking for is erase.
See this question which answers the same problem. In your case:
#include <algorithm>
str.erase(std::remove(str.begin(), str.end(), 'a'), str.end());
Or use boost if that's an option for you, like:
#include <boost/algorithm/string.hpp>
boost::erase_all(str, "a");
All of this is well-documented on reference websites. But if you didn't know of these functions, you could easily do this kind of things by hand:
std::string output;
output.reserve(str.size()); // optional, avoids buffer reallocations in the loop
for(size_t i = 0; i < str.size(); ++i)
if(str[i] != 'a') output += str[i];
The algorithm std::replace works per element on a given sequence (so it replaces elements with different elements, and can not replace it with nothing). But there is no empty character. If you want to remove elements from a sequence, the following elements have to be moved, and std::replace doesn't work like this.
You can try to use std::remove() together with str.erase()1 to achieve this.
str.erase(std::remove(str.begin(), str.end(), 'a'), str.end());
Using copy_if:
#include <string>
#include <iostream>
#include <algorithm>
int main() {
std::string s1 = "a1a2b3c4a5";
std::string s2;
std::copy_if(s1.begin(), s1.end(), std::back_inserter(s2),
[](char c){
std::string exclude = "a";
return exclude.find(c) == std::string::npos;}
);
std::cout << s2 << '\n';
return 0;
}
Starting with C++20, std::erase() has been added to the standard library, which combines the call to str.erase() and std::remove() into just one function:
std::erase(str, 'a');
The std::erase() function overload acting on strings is defined directly in the <string> header file, so no separate includes are required. Similiar overloads are defined for all the other containers.
string RemoveChar(string str, char c)
{
string result;
for (size_t i = 0; i < str.size(); i++)
{
char currentChar = str[i];
if (currentChar != c)
result += currentChar;
}
return result;
}
This is how I did it.
Or you could do as Antoine mentioned:
See this
question
which answers the same problem. In your case:
#include <algorithm>
str.erase(std::remove(str.begin(), str.end(), 'a'), str.end());
In case you have a predicate and/or a non empty output to fill with the filtered string, I would consider:
output.reserve(str.size() + output.size());
std::copy_if(str.cbegin(),
str.cend(),
std::back_inserter(output),
predicate});
In the original question the predicate is [](char c){return c != 'a';}
This code removes repetition of characters i.e, if the input is aaabbcc then the output will be abc. (the array must be sorted for this code to work)
cin >> s;
ans = "";
ans += s[0];
for(int i = 1;i < s.length();++i)
if(s[i] != s[i-1])
ans += s[i];
cout << ans << endl;
Based on other answers, here goes one more example where I removed all special chars in a given string:
#include <iostream>
#include <string>
#include <algorithm>
std::string chars(".,?!.:;_,!'\"-");
int main(int argc, char const *argv){
std::string input("oi?");
std::string output = eraseSpecialChars(input);
return 0;
}
std::string eraseSpecialChars(std::string str){
std::string newStr;
newStr.assign(str);
for(int i = 0; i < str.length(); i++){
for(int j = 0; j < chars.length(); j++ ){
if(str.at(i) == chars.at(j)){
char c = str.at(i);
newStr.erase(std::remove(newStr.begin(), newStr.end(), c), newStr.end());
}
}
}
return newStr;
}
Input vs Output:
Input:ra,..pha
Output:rapha
Input:ovo,
Output:ovo
Input:a.vo
Output:avo
Input:oi?
Output:oi
I have a string being read:
"\"internet\""
and I want to remove the quotes. I used the std::erase solution suggested above:
str.erase(std::remove(str.begin(), str.end(), '\"'), str.end());
but when I then did a compare on the result it failed:
if (str == "internet") {}
What I actually got was:
"internet "
The std::erase / std::remove solution doesn't shorten the string when it removes the end. I added this (from https://stackoverflow.com/a/21815483/264822):
str.erase(std::find_if(str.rbegin(), str.rend(), std::bind1st(std::not_equal_to<char>(), ' ')).base(), str.end());
to remove the trailing space(s).
I guess the method std:remove works but it was giving some compatibility issue with the includes so I ended up writing this little function:
string removeCharsFromString(const string str, char* charsToRemove )
{
char c[str.length()+1]; // + terminating char
const char *p = str.c_str();
unsigned int z=0, size = str.length();
unsigned int x;
bool rem=false;
for(x=0; x<size; x++)
{
rem = false;
for (unsigned int i = 0; charsToRemove[i] != 0; i++)
{
if (charsToRemove[i] == p[x])
{
rem = true;
break;
}
}
if (rem == false) c[z++] = p[x];
}
c[z] = '\0';
return string(c);
}
Just use as
myString = removeCharsFromString(myString, "abc\r");
and it will remove all the occurrence of the given char list.
This might also be a bit more efficient as the loop returns after the first match, so we actually do less comparison.
This is how I do it:
std::string removeAll(std::string str, char c) {
size_t offset = 0;
size_t size = str.size();
size_t i = 0;
while (i < size - offset) {
if (str[i + offset] == c) {
offset++;
}
if (offset != 0) {
str[i] = str[i + offset];
}
i++;
}
str.resize(size - offset);
return str;
}
Basically whenever I find a given char, I advance the offset and relocate the char to the correct index. I don't know if this is correct or efficient, I'm starting (yet again) at C++ and i'd appreciate any input on that.
70% Faster Solution than the top answer
void removeCharsFromString(std::string& str, const char* charsToRemove)
{
size_t charsToRemoveLen = strlen(charsToRemove);
std::remove_if(str.begin(), str.end(), [charsToRemove, charsToRemoveLen](char ch) -> bool
{
for (int i = 0; i < charsToRemoveLen; ++i) {
if (ch == charsToRemove[i])
return true;
}
return false;
});
}
#include <string>
#include <algorithm>
std::string str = "YourString";
char chars[] = {'Y', 'S'};
str.erase (std::remove(str.begin(), str.end(), chars[i]), str.end());
Will remove capital Y and S from str, leaving "ourtring".
Note that remove is an algorithm and needs the header <algorithm> included.
I'm working with a string and trying to break it up whenever it is non-alphanumeric (not a-z, A-Z, and 0-9). I found isalnum to be a useful function to use.
For example, if I have the string "bob-michael !#mi%#pa hi3llary-tru1mp"
The vector should contain: bob, michael, mi, pa, hi3llary, and tru1mp.
My current code is:
vector<string> result;
string something = "bob-michael !#mi%#pa hi3llary-tru1mp";
stringstream pie(something);
//not sure what to do after this point(I know, not a lot. See below for my current thinking)
My idea was using a loop and while isalnum results in 1 continue forward, if isalnum results in 0 then push whatever I have so far into the vector of strings. Perhaps I could use isalnum as a delim? I'm having a hard time taking my idea and writing this. Could anyone point me in the right direction? Thanks!
Edit: Thanks everyone for the help.
Something along these lines, perhaps:
std::vector<std::string> result;
std::string something = "bob-michael !#mi%#pa hi3llary-tru1mp";
std::regex token("[A-Za-z0-9]+");
std::copy(
std::sregex_token_iterator(something.begin(), something.end(), token),
std::sregex_token_iterator(),
std::back_inserter(result));
Demo
The std::replace_if trick I commented on turned out to not be quite as trivial as I thought it was because std::isalnum doesn't return bool.
#include <iostream>
#include <vector>
#include <string>
#include <cctype>
#include <algorithm>
#include <sstream>
#include <iterator>
int main()
{
std::vector<std::string> result;
std::string something = "bob-michael !#mi%#pa hi3llary-tru1mp";
// I expected replace_if(something.begin(), something.end(), &isalnum, " ");
// would work, but then I did a bit of reading and found is alnum returned int,
// not bool. resolving this by wrapping isalnum in a lambda
std::replace_if(something.begin(),
something.end(),
[](char val)->bool {
return std::isalnum(val) == 0;
},
' ');
std::stringstream pie(something);
// read stream into vector
std::copy(std::istream_iterator<std::string>(pie),
std::istream_iterator<std::string>(),
std::back_inserter<std::vector<std::string>>(result));
// prove it works
for(const std::string & str: result)
{
std::cout << str << std::endl;
}
}
You can also iterate through the string and then check if the current index is a letter or not, then if not break it then store to vector
std::string something = "bob-michael !#mi%#pa hi3llary-tru1mp";
std::vector<std::string> result;
std::string newResult = "";
for ( int a = 0; a < something.size(); a++ )
{
if((something[a] >= 'a' && something[a] <= 'z')||(something[a] >= 'A' && something[a] <= 'Z')
|| (something[a] >= '0' && something[a] <= '9'))
{
newResult += something[a];
}
else
{
if(newResult.size() > 0)
{
result.push_back(newResult);
newResult = "";
}
}
}
result.push_back(newResult);
It's in the form of a word so let's say I'm given the string "foo", and inside my array there are words like "food", "fool", "foo". All three of them should be printed out.
I haven't made a solid attempt at it yet cause I don't know how to wrap my head around it. Any idea?
Assuming you're using std::string, you could use string::find to see if one string is contained in another.
If you have a vector of strings, you might use that along with (for example) std::remove_copy_if to print out all the words from the vector that contain the chosen word:
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>
#include <iostream>
int main() {
std::vector<std::string> words{"food", "fool", "foo", "tofoo", "lood", "flood"};
std::string word = "foo";
std::remove_copy_if(words.begin(), words.end(),
std::ostream_iterator<std::string>(std::cout, "\n"),
[&](std::string const &s) {
return s.find(word) == std::string::npos;
});
}
Result:
food
fool
foo
tofoo
You could do something simple, like iterating through each character in the string and checking it against the characters in the string you are trying to match using a separate function. If three characters in a row match the string you are searching for, add it to a vector or something and display them.
// Variables
bool charMatched = false;
vector<string> *stringVec = new vector<string>();
int index = 0;
int counter = 0;
string str = "Whatever you are trying to match";
for (char &c : strings[index]) // For each character in string
{
// Check for match
if (checkChar(c))
{
counter++;
charMatched = true;
if(counter == str.length())
stringVec->push_back(strings[index]);
}
else
{
index++;
counter = 0;
break;
}
}
bool checkChar(char c)
{
// Iterator to go through match string
static string::iterator it = str.begin();
if (c == *it)
{
if (it == str.end())
it = str.begin(); // Reset iterator
else
it++; // Increment iterator
return true;
}
else
{
if (it == str.end())
it = str.begin(); // Reset iterator
else
it++; // Increment iterator
return false;
}
}
You will have to tweak it a little to work with an array the way you want it to but something like this should do what you want. I did not run this through a compiler, I wrote it in Notepad so there may be small syntax errors. I hope this helps!