This question already has answers here:
C++ Remove punctuation from String
(12 answers)
Closed 9 years ago.
I got a code. It should give me an output that will erase the middle character between 'z' and 'p'. for example: zipZap("zipXzap"): expected [zpXzp] but found [z pXz p]
std::string zipZap(const std::string& str){
string a = str;
string b = "";
size_t len = str.length();
for (size_t i = 0; i < len; i++){
if (str[i] == 'z')
if (str[i+2] == 'p')
a[i+1] = ' ';
}
return a;
}
When i replaced a[i+1] = ''; it gave me an error.
You are not removing the chars, you are replacing them with ' '.
There are many ways to do this. One simple way is to build a new string, only adding chars when the proper conditions are met:
std::string zipZap(const std::string& str)
{
string a;
size_t len = str.length();
for (size_t i = 0; i < len; i++) {
// Always add first and last chars. As well as ones not between 'z' and 'p'
if (i == 0 || i == len-1 || (str[i-1] != 'z' && str[i+1] != 'p')) {
a += str[i];
}
}
return a;
}
Use string.erase() :
std::string zipZap(const std::string& str){
std::string a = str;
std::string b = "";
size_t len = str.length();
for (size_t i = 0; i < len; i++){
if (a[i] == 'z')
if (a[i+2] == 'p')
a.erase(i+1,1);
}
return a;
}
You're completely right that you cant replace an element of the string with ''.
A string is an array of chars, and '' is not a char at all. It is nothing.
If we look at the cplusplus page for a string
http://www.cplusplus.com/reference/string/string/
We see that we can use erase(iterator p) to "Erase characters from string (public member function)"
So if we change:
for (size_t i = 0; i < len; i++){
if (str[i] == 'z')
if (str[i+2] == 'p')
a.erase(a.begin() + i + 1);
We're closer now, but we can see that len is no longer the same as str.length(). the length of a is now actually 1 char shorter than len. To remedy this however we can simply add:
for (size_t i = 0; i < len; i++){
if (str[i] == 'z')
if (str[i+2] == 'p')
a.erase(a.begin() + i + 1);
len -= 1;
Hope that helps
If you #include <regex>, you can do a regular expression replacement.
std::string zipZap(const std::string& str){
regex exp("z.p");
string a = str;
a = regex_replace(a, exp "zp");
return a;
}
Related
I am trying to use C++ functions in Swift. To do that, I use an Objective-C wrapper. I am not familiar with Objective-C and C++ so much.
My wrapper function takes Swift String as a parameter from textField. And inside of C++ I encrypt the passed string and return it.
Here is my C++ function:
string StringModifier::encryptString(string str) {
int i;
for(i=0; (i<100 && str[i] != '\n'); i++) {
str[i] = str[i] + 2;
}
return str;
}
And inside of the wrapper:
StringModifier stringModifier;
-(NSString*)encryptString:(NSString*)str; {
string strng = [str UTF8String];
string finalString = stringModifier.encryptString(strng);
NSString *result = [NSString stringWithCString: finalString.c_str() encoding:[NSString defaultCStringEncoding]];
return result;
}
The output of encryptString("Helloworld") is "Jgnnqyqtnf¬√√0*?"
and after a couple of times calling this method, it throws an EXC_BAD_ACCESS error.
How can I solve this problem?
You need to check for the null character (\0) in C++.
Change your for-loop to this:
for(i=0; (i<100 && str[i] != '\n' && str[i] != '\0'); i++) {
str[i] = str[i] + 2;
}
Even better, loop depending on how big the string is:
string StringModifier::encryptString(string str) {
for (int i = 0; i < str.size() && str[i] != '\n'; i++) {
str[i] = str[i] + 2;
}
return str;
}
I have the debug assertion error in the if statement when i = 7:
Expression: c>= -1 && c <= 255
This is my code:
#include <iostream>
#include <string>
const char* clearString(std::string str)
{
for (int i = str.length() - 1; i >= 0; i--)
{
if ( !isdigit(str[i])
&& str[i] != ',')
{
str.erase(i, 1);
}
}
return str.c_str();
}
int main()
{
std::string str = "688,13 €";
std::cout << clearString(str);
}
I try to delete all characters in the string that are not numbers and ','.
For std::isdigit, see the Notes section as to why you are getting the assertion.
The fix is to cast to an unsigned char:
if (!isdigit(static_cast<unsigned char>(str[i]))
Second, your function returns the address of a local temporary, thus exhibits undefined behavior. Return a std::string instead.
std::string clearString(std::string str)
{
//…
return str;
}
Third, you could rewrite your function using std::remove_if and std::string::erase, instead of writing a loop that removes a character at a time.
#include <algorithm>
//...
std::string clearString(std::string str)
{
auto iter = std::remove_if(str.begin(), str.end(),
[&](char ch)
{ return !isdigit(static_cast<unsigned char>(ch)) && ch != ',';});
str.erase(iter, str.end());
return str;
}
The function isdigit() works only with chars that their decimal value is between -1 and 255.
The decimal value of the character € is -128 which the function doesn't support.
I would suggest to change the comparison instead of using isdigit(), compare the decimal values of the chars.
Change your function to this:
const char* clearString(std::string& str)
{
for (int i = str.length() - 1; i >= 0; i--)
{
if ((str[i] < '0' || str[i] > '9') && str[i] != ',')
{
str.erase(i, 1);
}
}
return str.c_str();
}
A little out of topic, about your algorithm.
It would be better if you don't erase every non-digit character, but shift your characters left, skipping all non-digits (except ',') and resize string.
About isdigit I would do how 0xBlackMirror suggested, compare to '0' and '9'.
Here is the code:
const char* clearString(std::string str)
{
int j = 0;
for (uint i = 0; i < str.size(); i++)
{
if ((str[i] >= '0' && str[i] <= '9') || str[i] == ',')
{
str[j++] = str[i];
}
}
str.resize(j);
return str.c_str();
}
The function I am using is
vector<string> tokenise(string s){
}
Firstly, I intend to split the string into substrings, in which case the string is always arithmetic expression (e.g. "100+5") and there could be some whitespaces.
"100+5" is needed to convert to "100", "+", "5"
After conversion, the substrings will be stored in a vector and return it. I am struggling with the fist step and using the subscript to loop over a string. The type of the value returned is char, so there is no way to put it in the vector.
You could just call the string's substring method, after figuring out the range of characters that are either digits, arithmetic characters, or unwanted.
You mentioned - The type of the value returned is char, so there is no way to put it in the vector.
You have some function that returns a character. You want to then insert the equivalent string into the vector.
Assuming your vector is defined as
std::vector<std::string> broken_strings;
So you can do it as follows.
char ch = ...; // Here comes the character that you get from the function.
std::string str(1, ch);
broken_strings.push_back(str);
Then you can return broken_strings.
Edit:
OP mentions that he wants to tokenize algebraic expressions.
So it will have to be done it a different way.
Following is a simple approach.
std::vector<std::string> broken;
std::string temp;
for ( int i = 0; i<s.length() ;i++){
char ch = s[i];
if (ch == ' ')
continue;
else if (ch >= '0' && ch <='9')
temp += ch;
else{
if (temp.length() != 0)
broken.push_back(temp);
temp = "";
temp += ch;
broken.push_back(temp);
temp = "";
}
}
if (temp.length() != 0)
broken.push_back(token);
return broken;
You can see the demo of the same here
Ideone
vector<string> tokenise(string s)
{
vector<string> v;
string number;
for(int i = 0; i < s.length(); ++i)
{
if((s[i] >= '0') && (s[i] <= '9'))
{
number += string(1, s[i]);
}
else if(s[i] == '.')
{
number += string(1, s[i]);
}
else if((s[i] == '+') || (s[i] == '-') || (s[i] == '*') || (s[i] == '/'))
{
if(number.size())
{
v.push_back(number);
number.clear();
}
v.push_back(string(1, c));
}
}
if(number.size())
{
v.push_back(number);
number.clear();
}
return v;
}
This question already has answers here:
Remove spaces from std::string in C++
(19 answers)
Closed 8 years ago.
so I am making a palindrome checker that ignores any white space or special characters. Below is part of my function. What it does is it takes a c string as an argument, then I create another c string in order to remove the whitespaces and special character from the orignal. When I output the second c string, it still will have the whitespaces or special characters. Could some explain why it is doing that? Thanks
bool isPalindrome(char *line)
{
//variables
bool palindrome = true;
int length = strlen(line);
int count = 0;
//copy line to line2 with no spaces and no punctuation
char *line2 = new char[length + 1];
int count2 = 0;
for(int i = 0; i < length; i++)
{
if(line[i] != ' ' && ispunct(line[i]) == false)
{
line2[count2] = line[i];
count2 ++;
}
}
for(int i = 0; i < count2; i++)
cout << line[i];
line2[length] = '\0';
You are null-terminating your second string at the original length:
line2[length] = '\0';
should be
line2[count2] = '\0';
As far as your original assignment goes, it is not necessary to create a copy of the string to check if it is a palindrome: all you need is a function that finds the next non-empty, non-punctuation character in a specific direction:
int nextValidChar(const char *str, int &pos, const int step) {
pos += step;
while (pos >= 0 && str[pos] != '\0') {
char c = str[i];
if (c != ' ' && !ispunct(c)) {
return c;
}
pos += step;
}
return -1;
}
With this function in hand, set up two indexes, at zero and at length-1, and call nextValidChar repeatedly to find valid characters at both ends.
The reason it is still outputting with spaces and special chars is because this
for(int i = 0; i < count2; i++)
cout << line[i];
should be
for(int i = 0; i < count2; i++)
cout << line2[i];
My input string is
\\?\bac#dos&ven_bb&prod_open-v&rev_5001#1&7f6ac24&0&353020304346333030363338#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}
Required output is
bac\dos&ven_bb&prod_open-v&rev_5001\1&7f6ac24&0&353020304346333030363338_0
I have written a following code but is not working...need help is figuring out the problem.
Forgive my ignorance :) Also let me know if there is any better and efficient way to do it.
The rule for the output string is
In the second string i am removing all the "\" and "?" .And where is see the "#" i replace it with "\". and the second string is only till you see the charater "{" but does not include "#" at the end of it.
THanks
int main()
{
char s[] = "\\?\bac#dos&ven_bb&prod_open-v&rev_5001#1&7f6ac24&0&353020304346333030363338#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}";
char s1[] = {0};
printf("OUtput string is : ");
for(int i = 0; s[i] != '{'; i++)
{
if(s[i] != '\\' && s[i] != '?')
{
int j = 0;
if(s[i] == '#')
{
s1[j] = '\\';
continue;
}
s1[j] = s[i];
j++;
}
}
for(int i = 0; s1[i] != '\0'; i++)
{
cout<<s1[i];
}
getch();
}
I would suggest looking into using the std::string::replace() function. There is plenty of online documentation on this. Take a look at some of the other functions that std::string has to offer as they might be of use too. If you are using c++, the use of std::string is usually preferable to tinkering with char arrays and indices.
Note the fixed scope of j. In your version you were always assigning to s1[0].
for(int i = 0, j = 0; s[i] != '{'; i++)
{
if(s[i] != '\\' && s[i] != '?')
{
// int j = 0;
if(s[i] == '#')
{
s1[j] = '\\';
}
else
{
s1[j] = s[i];
}
j++;
}
}
The other thing is to allocate enough space for the new string. Since you haven't specified the size char s1[] = {0}; declares an array of size 1. You need to do something like:
char s1[sizeof(s)] = { 0 }; // the size of the old array, since we don't know how long the new one will be
But since you tagged the Q C++, take advantage of of dynamically resizable std::string.
std::string s = ".......";
std::string s1;
for(int i = 0; s[i] != '{'; i++)
{
if(s[i] != '\\' && s[i] != '?')
{
if(s[i] == '#')
s1 += '\\';
else
s1 += s[i];
}
}
Your s1 buffer needs to be increased, as it stands now there is no room for the new string.
E.g.
char* s1 = calloc(strlen(s)+1,sizeof(char)); // same size should be enough, free(s1) later
the calloc ensures that it is \0 terminated, in your code you forgotten to add the \0 so the printout act erratically.