Converting string from C++ to Swift - c++

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;
}

Related

Debug Assertion Failed error while comparing unicode using isdigit

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();
}

How to captalize and title a string

If I was given a string, I need to either capitalize or title the string. For example:
There are some problems with your code. Here is the modified version of your code that works fine. Here:
std::string Capitalize(const std::string &str) {
std::string Ret;
for (int i = 0; i < str.length(); i++){
char c = str[i];
if (i == 0){
Ret += toupper(c);
}
else if (i != 0){
Ret += (tolower(c));
}
}
return Ret;}
Condition in for loop needs to be str.length() not Ret.length() and here :
std::string Title(const std::string &str) {
std::string Ret;
int i=0;
for (int i=0;i<str.size();i++) {
if(!(i==0 && str[i]==' '))
Ret += tolower(str[i]);
}
int size = Ret.length();
for (int i = 0; i < size; i++) {
if (i==0 || Ret[i - 1] == ' ')
{
Ret[i] = toupper(Ret[i]);
}
}
return Ret;}
Check if i is 0 to prevent out of range access to string.
Use a stringstream to first split all words, so that you can do this easily with a vector. This is an implementation of the Title function:
std::string Title(const std::string &str) {
std::vector<string>words;
words.clear();
std::string res = str, std::ans = "";
// It's better to pass the string AFTER you convert it all lowercase. Or you can only work with the capitalized characters:
for(int i = 0; i < res.size(); ++i){
if(res[i] >= 'A' && res[i] <= 'Z'){
res[i] = tolower(res[i]);
}
}
istringstream ss(res); // We push the modified string into a stringstream.
do{
res = "";
ss >> res;
words.push_back(res); // We split the string at " " and push each word in the vector.
} while(ss)
for(int i = 0; i < words.size(); ++i){
res = words[i];
res[0] = toUpper(res[0]); // For each word, we capitalize it
ans += res; // We add the word to our return string.
if(i < words.size() - 1){
ans += " "; // If this is not the last word, add a space
}
}
return ans;
}
As for the capitalization, you can do something like this:
std::string Capitalize(const std::string &&str){
std::string res = str;
res[0] = toupper(res[0]);
for(int i = 1; i < res.size(); ++i){
if(res[i] >= 'A' && res[i] <= 'Z'){
res[i] = tolower(res[i]); // converting if only an uppercase character.
}
}
return res; // If you pass a reference, the original will be modified so no return required.
}

Strings Code not Working

Using the C++ language, the function LetterChanges(str) takes the str parameter being passed and modifies it using the following algorithm.
Replace every letter in the string with the letter following it in the
alphabet (ie. c becomes d, z becomes a). Then capitalize every vowel
in this new string (a, e, i, o, u) and finally return this modified
string.
#include <iostream>
using namespace std;
string LetterChanges(string str) {
// code goes here
string str2 = "abcdefghijklmnopqrstuvwxyz";
int j;
for (int i = 0; str[i] != '\0'; i++) {
for (j = 0; str2[j] != '\0'; j++) {
if (str[i] == str2[j]) {
str[i] = str2[j + 1];
}
}
}
for (int i = 0; str[i] != '\0'; i++) {
if (str[i] == 'a') {
str[i] = 'A';
}
else if (str[i] == 'e') {
str[i] = 'E';
}
else if (str[i] == 'i') {
str[i] = 'I';
}
else if (str[i] == 'o') {
str[i] = 'O';
}
else if (str[i] == 'u') {
str[i] = 'U';
}
}
return str;
}
int main() {
// keep this function call here
cout << LetterChanges(gets(stdin));
return 0;
}
I am trying to run this code but it is not giving the desire output please help..
The Function
Let's start with your first loop:
for (int i = 0; str[i] != '\0'; i++) {
for (j = 0; str2[j] != '\0'; j++) {
if (str[i] == str2[j]) {
str[i] = str2[j + 1];
}
}
}
There are a couple things here. Firstly, we don't even need to deal with str2. Characters in C++ use ASCII encoding, meaning we can actually do something like str[i]++ to change an 'a' to a 'b' or an 'e' to an 'f', etc...
Also, I'd advise against using str[i] != '\0'. We're using the standard library strings instead of c-strings for a reason, so we might as well make our lives easier and use str.size(). Along these same lines, I'd suggest str.at(i) as opposed to str[i] as the former will do bounds checking for us.
Lastly, if you include cctype, then we can use the isalpha function to make sure we're only modifying alphabetic characters (no numbers or spaces, etc..).
Thus your first loop can become:
for (int i = 0; i < str.size(); i++) {
if(isalpha(str.at(i)){
if(str.at(i) == 'z') str.at(i) = 'a'; //special case
else str.at(i)++;
}
}
As far as your second loop, you don't even need it! We can actually incorporate everything straight into the first one. As long as we make sure to do the vowel modification after we've changed the individual letters.
A conversion from lowercase to uppercase can be done with some ASCII math as well. The difference between the lowercase and uppercase letters is 'A'-'a', so if we add that to any lowercase letter, it'll give us its uppercase version!
With all of this, we can modify your code to:
for (int i = 0; i < str.size(); i++) {
if(isalpha(str.at(i)){ //Make sure it's a letter!
if(str.at(i) == 'z') str.at(i) = 'a'; //special case
else str.at(i)++;
if(str.at(i) == 'a' | str.at(i) == 'e' | str.at(i) == 'i'
| str.at(i) == 'o' | str.at(i) == 'u') {
str.at(i) += 'A' - 'a';
}
}
Your Main
There's only one thing to fix here. Don't use gets for input. If you're looking for a single word, use the extraction operator, >>, or if you want a whole line, use getline.
string word, line;
getline(cin, line);
cin >> word;
cout << LetterChanges(line) << endl;
cout << LetterChanges(word) << endl;

String error output [duplicate]

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;
}

Copying selected character from string

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.