stringByAddingPercentEscapesUsingEncoding does not escape "&" - objective-c

I am using stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding to pass data to a php script. The problem is if the field has the char '&' in the text lets say: 'someone & cars', only the text "someone" is saved, everything after the '&' doesn't.
To create the string I use [NSString stringWithFormat:], so I have like 5 field in the form and if I use stringbyReplacingOcorrencesOfstring:#"&", what it does is replace the whole string not only the char '&' from the text field, so I get error.
Any ideas?

Unfortunately, stringByAddingPercentEscapesUsingEncoding: doesn't actually escape all necessary URL characters.
Instead, you can use the lower-level CoreFoundation function:
(NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)myString, NULL, (CFStringRef)#"!*'\"();:#&=+$,/?%#[]% ", CFStringConvertNSStringEncodingToEncoding(encoding));
or, when using ARC:
CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL, (__bridge CFStringRef)myString, NULL, (__bridge CFStringRef)#"!*'\"();:#&=+$,/?%#[]% ", CFStringConvertNSStringEncodingToEncoding(encoding)));
See this post for an example of a category on NSString that uses this function.

Following works using stringByAddingPercentEncodingWithAllowedCharacters if you want to specifically allow what would be encoded yourself. I'm using after base64 so this works fine.
NSString *charactersToEscape = #"!*'();:#&=+$,/?%#[]\" ";
NSCharacterSet *customEncodingSet = [[NSCharacterSet characterSetWithCharactersInString:charactersToEscape] invertedSet];
NSString *url = [NSString stringWithFormat:#"%#", #"http://www.test.com/more/test.html?name=john&age=28"];
NSString *encodedUrl = [url stringByAddingPercentEncodingWithAllowedCharacters:customEncodingSet];

Related

in objective-c is there any easy way to add backslash in front of special characters?

Note: Not sure why this is marked as duplicate as I clearly stated that I don't want to use stringByReplacingOccurrencesOfString over and over again.
I have a question regarding the special character filename.
I have implemented a program, so that when you open a file or multiple files, the program will read all these filenames and local path and store them into the NSMutableArray. This part works perfectly without a problem.
My program also need to use NSTask to manipulate these files. However, the problem is, sometimes filename will contain special characters, for example, /Users/josh/Desktop/Screen Shot 2013-03-19 at 2.05.06 PM.png.
I have to replace space with backslash and space
NSString *urlPath = [[self url] path];
urlPath = [urlPath stringByReplacingOccurrencesOfString:#"(" withString:#"\\("];
urlPath = [urlPath stringByReplacingOccurrencesOfString:#")" withString:#"\\)"];
urlPath = [urlPath stringByReplacingOccurrencesOfString:#" " withString:#"\\ "];
to: /Users/josh/Desktop/Screen\ Shot\ 2013-03-19\ at\ 2.05.06\ PM.png
so that I can manipulate the file properly.
Same for the ( and ). I also need to add backslash before that.
but there are too many special characters. ie.
/Users/josh/Desktop/~!##$?:<,.>%^&*()_+`-={}[]\|'';.txt
I need to change to:
/Users/josh/Desktop/\~\!#\#\$\?\:\<\,.\>\%^\&\*\(\)_+\`-\=\{\}\[\]\\\|\'\'\;.txt
and not to mention other special characters (ie. accent)
Is there any easy way to put a backslash in front of each special character, as I don't want to keep calling stringByReplacingOccurrencesOfString over and over again.
As described in NSTask's documentation for the setArguments: method, there should be no need to do special quoting:
Discussion
The NSTask object converts both path and the strings in
arguments to appropriate C-style strings (using
fileSystemRepresentation) before passing them to the task via argv[].
The strings in arguments do not undergo shell expansion, so you do not
need to do special quoting, and shell variables, such as $PWD, are not
resolved.
If you feel it is necessary, can you please provide some examples of the commands you want to run in the NSTask?
[UPDATE]: I see in the comments that you indeed are using the NSTask to execute a bash shell with -c, which I had wondered about. I've generally used NSTask to execute the command directly rather than going through the shell, like this:
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:#"/bin/ls"];
[task setArguments:[NSArray arrayWithObjects:#"-l", self.url.path, nil]];
Can you give a more accurate example of the actual command you want to run? For example, are you piping a series of commands together? Perhaps there might be an alternate way to achieve the same results without the need for using the bash shell...
I think you may be able to use an NSRegularExpressionSearch search.
It would look something like this
+ (NSString *) addBackslashes: (NSString *) string
{
// First convert the name string to a pure ASCII string
NSData *asciiData = [string dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *asciiString = [[[NSString alloc] initWithData:asciiData encoding:NSASCIIStringEncoding] lowercaseString];
// Define the characters that we will replace
NSString *searchCharacters = #"PUT IN ALL OF YOUR SPECIAL CHARACTERS HERE";
// example NSString *searchCharacters = #"!##$%&*()";
// replace them
NSString *regExPattern = [NSString stringWithFormat:#"[%#]", searchCharacters];
string = [asciiString stringByReplacingOccurrencesOfString:regExPattern withString: [NSString stringWithFormat:#"\\%#", regExPattern] options:NSRegularExpressionSearch range:NSMakeRange(0, asciiString.length)];
return string;
}
you could maintain a set of strings that need to be escaped and use NSScanner to build the new string by iterating the the source string and each time a problematic character is found u first add \\ to a destination string and continue coping the next chars.
NSString *sourceString = #"/Users/josh/Desktop/\"Screen Shot\" 2013-03-19 at 2\\05\\06 PM.png";
NSMutableString *destString = [#"" mutableCopy];
NSCharacterSet *escapeCharsSet = [NSCharacterSet characterSetWithCharactersInString:#" ()\\"];
NSScanner *scanner = [NSScanner scannerWithString:sourceString];
while (![scanner isAtEnd]) {
NSString *tempString;
[scanner scanUpToCharactersFromSet:escapeCharsSet intoString:&tempString];
if([scanner isAtEnd]){
[destString appendString:tempString];
}
else {
[destString appendFormat:#"%#\\%#", tempString, [sourceString substringWithRange:NSMakeRange([scanner scanLocation], 1)]];
[scanner setScanLocation:[scanner scanLocation]+1];
}
}
NSLog(#"\n%#\n%#", sourceString, destString);
result:
/Users/josh/Desktop/Screen Shot 2013-03-19 at 2.05.06 PM.png
/Users/josh/Desktop/Screen\ Shot\ 2013-03-19\ at\ 2.05.06\ PM.png

how to replace one substring with another in Objective C?

I want to replace an NSString substring with another substring in Objective C.
I know how to locate the substring I want to replace:
NSRange range = [string rangeOfString:substringIWantToReplace];
NSString *substring = [string substringFromIndex:NSMaxRange(range)];
But when it comes to actually removing/replacing it, I'm a little confused. Do I follow the C++ method at Replace substring with another substring C++? Or the C method at how to replace substring in c?? There's a related question at Objective-C: Substring and replace, but the string in question is a URL, so I don't think I can use the answers.
I think your answer is here Replace occurrences of NSString - iPhone:
[response stringByReplacingOccurrencesOfString:#"aaa" withString:#"bbb"]; defenetly works on any string and URL also.
If your concern about percent-notation of url and you want to be sure it will be replaced properly, you can firstly decode string, replace, and then encode:
// decode
NSString *path = [[#"path+with+spaces"
stringByReplacingOccurrencesOfString:#"+" withString:#" "]
stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
// replace
path = [path stringByReplacingOccurrencesOfString:#"aaa" withString:#"bbb"]
// encode
path = CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)path,
NULL,
(CFStringRef)#"!*'\"();:#&=+$,/?%#[]% ",
kCFStringEncodingUTF8 );
This is how I check for a substring and replace/remove substrings from NSString:
if([titleName rangeOfString:#"""].location != NSNotFound) {
titleName = [titleName stringByReplacingOccurrencesOfString:#""" withString:#"\""];
}

Encoding a comma with stringByAddingPercentEscapesUsingEncoding

Why doesn't the comma get encoded? I was expecting it to be %2C.
(lldb) po [#"," stringByAddingPercentEscapesUsingEncoding:4]
(id) $24 = 0x0a8fbfd0 ,
As noted by #DayS, because comma is a legal URL character. However, if you would like to have control over which characters are escaped, look at CFURLCreateStringByAddingPercentEscapes().
NSString *toencode = #",";
NSString *result =
CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL,
(__bridge CFTypeRef)toencode,
NULL,
CFSTR(","),
kCFStringEncodingUTF8));
NSLog(#"%#", result);
This method will only replace special characters which aren't valid in a URL. As the comma is a valid one, he'll stay like this.
Try with this string to check :
[#",éà /" stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
To replace other characters like comma, you have to do it yourself...

Padding NSString not working

I have read that to left-pad an NSString all you need to do is this:
NSString *paddedStr = [NSString stringWithFormat:#"%-20.20# %-20.20#",
aString, anotherSting];
But, that does not work !! I don´t know why. I have tried a lot of combinations without success. Examples:
NSString *paddedStr = [NSString stringWithFormat:#"%-20s#", " ", myString];
but that way is ugly and ... ugly. It just append 20 times the char (" ") before the string (myString) and that is not what we need right?
The goal is to have an NSString formatted to present two or more columns of 20 chars each one no matter the length of the string within a row.
Example Goal Output:
Day Hour Name Age
Does anybody know how to do this right?
I'm using ARC and iOS 5.
And actually, the formatted string is going to be written to file using NSFileHandle.
Thanks to all of you folks !!
Edit:
I have noticed that this works:
NSString *str = [NSString stringWithFormat:#"%-10.10s %-10.10s",
[strOne UTF8String], [strTwo UTF8String]];
But... We don't want C-style strings either.
Here is a way to do that :
NSString *paddedStr = [NSString stringWithFormat:#"%#%#",
[#"day" stringByPaddingToLength:20
withString:#" "
startingAtIndex:0],
[#"Hour" stringByPaddingToLength:20
withString:#" "
startingAtIndex:0]];

simple question concerning NSString adding multiple strings

I have a fairly simple question concerning NSString however it doesn't seem to do what I want.
this is what i have
NSString *title = [NSString stringWithformat: character.name, #"is the character"];
This is a line in my parser takes the charactername and inserts in into a plist , however it doesn't insert the #"is the character" is there something I'm doing wrong?
Your code is wrong. It should be :
NSString *title
= [NSString stringWithformat:#"%# is the character", character.name];
assuming that character.name is another NSString.
Read the Formatting String Objects paragraph of the String Programming Guide for Cocoa to learn everything about formatting strings.
stringWithFormat takes a format string as the first argument so, assuming character.name is the name of your character, you need:
NSString *title = [NSString stringWithformat: #"%s is the character",
character.name];
What you have is the character name as the format string so, if it's #"Bob" then Bob is what you'll get. If it was "#Bob %s", that would work but would probably stuff up somewhere else that you display just the character name :-)
Note that you should use "%s" for a C string, I think "%#" is the correct format specifier if character.name is an NSString itself.