CFURLCreateStringByAddingPercentEscapes is deprecated in iOS 9, how do I use "stringByAddingPercentEncodingWithAllowedCharacters" - ios

I have the following code:
return (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)string, NULL, CFSTR(";:#&=+$,/?%#[]"), kCFStringEncodingUTF8);
Xcode says it is deprecated in iOS 9. So, how do I use stringByAddingPercentEncodingWithAllowedCharacters ?
Thanks!

try this
NSString *value = #"<url>";
value = [value stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];

The character set URLQueryAllowedCharacterSet contains all characters allowed in the query part of the URL (..?key1=value1&key2=value2) and is not limited to characters allowed in keys and values of such a query. E.g. URLQueryAllowedCharacterSet contains & and +, as these are of course allowed in query (& separates the key/value pairs and + means space), but they are not allowed in a key or a value of such a query.
Consider this code:
NSString * key = "my&name";
NSString * value = "test+test";
NSString * safeKey= [key
stringByAddingPercentEncodingWithAllowedCharacters:
[NSCharacterSet URLQueryAllowedCharacterSet]
];
NSString * safeValue= [value
stringByAddingPercentEncodingWithAllowedCharacters:
[NSCharacterSet URLQueryAllowedCharacterSet]
];
NSString * query = [NSString stringWithFormat:#"?%#=%#", safeKey, safeValue];
query will be ?my&name=test+test, which is totally wrong. It defines a key named my that has no value and a key named name whose value is test test (+ means space!).
The correct query would have been ?my%26name=test%2Btest.
As long as you only deal with ASCII strings or as long as the server can deal with UTF-8 characters in the URL (most web servers today do that), the number of chars you absolutely have to encode is actually rather small and very constant. Just try that code:
NSCharacterSet * queryKVSet = [NSCharacterSet
characterSetWithCharactersInString:#":/?&=;+!##$()',*% "
].invertedSet;
NSString * value = ...;
NSString * valueSafe = [value
stringByAddingPercentEncodingWithAllowedCharacters:queryKVSet
];

Another solution to encode those characters allowed in URLQueryAllowedCharacterSet but not allowed in a key or a value (e.g.: +):
- (NSString *)encodeByAddingPercentEscapes {
NSMutableCharacterSet *charset = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
[charset removeCharactersInString:#"!*'();:#&=+$,/?%#[]"];
NSString *encodedValue = [self stringByAddingPercentEncodingWithAllowedCharacters:charset];
return encodedValue;
}

Related

NSString stringWithCString not showing special characters?

I'm using
[NSString stringWithFormat:#"%C",(unichar)decimalValueX];
but I have to call it thousands of times and its simply too slow.
As an alternative I tried this:
sprintf (cString, "%C", (unichar)decimalValueX);
[NSString stringWithCString:cString encoding:NSUTF16StringEncoding];
but no characters are correctly transalted.
If I try UTF8 instead of 16:
sprintf (cString, "%C", (unichar)decimalValueX);
[NSString stringWithCString:cString encoding:NSUTF8StringEncoding];
I get alphanumeric, but I don't get foreign characters or other special characters.
Can anyone explain whats going on? Or how to make stringWithFormat faster?
Thanks!
It seems that the %C format does not work with sprintf and related functions and non-ASCII characters. But there is a simpler method:
stringWithCharacters:length:
creates an NSString directly from a unichar array (UTF-16 code points).
For a single unichar this would be just
NSString *string = [NSString stringWithCharacters:&decimalValueX length:1];
Example:
unichar decimalValueX = 8364; // The Euro character
NSString *string = [NSString stringWithCharacters:&decimalValueX length:1];
NSLog(#"%#", string); // €
Example for multiple UTF-16 code points:
unichar utf16[] = { 945, 946, 947 };
NSString *string3 = [NSString stringWithCharacters:utf16 length:3];
NSLog(#"%#", string3); // αβγ
For characters outside of the "basic multilingual plane" (i.e.
characters > U+FFFF) you would have to use 2 UTF-16 code points
per character (surrogate pair).
Or use a different API like
uint32_t utf32[] = { 128123, 128121 };
NSString *string4 = [[NSString alloc] initWithBytes:utf32 length:2*4 encoding:NSUTF32LittleEndianStringEncoding];
NSLog(#"%#", string4); // 👻👹

How to validate a password which must contain either number or alphabets(or both) as well as special characters?

hi am currently using the following to validate the password but i want to include special characters also. Currently it contains only numbers and alphabets. Please help.
- (BOOL)validatePassword:(NSString *) password{
NSString *ACCEPTABLE_CHARECTERS = #"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:ACCEPTABLE_CHARECTERS] invertedSet];
NSString *filtered = [[password componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:#""];
return [password isEqualToString:filtered];
}
You can try this
- (BOOL)validatePassword:(NSString *) password{
if(password.length == 0){
return NO;
}
NSString *regex = #"^(?=(.*\d){2})(?=.*[a-zA-Z])(?=.*[!##$%])[0-9a-zA-Z!##$%]{8,}";
NSPredicate *passwordPredicate = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", regex];
return [passwordPredicate evaluateWithObject:password];
}
EXPLANATION
(?=(.*\d){2}) - uses lookahead (?=) and says the password must contain at least 2 digits
(?=.*[a-zA-Z]) - uses lookahead and says the password must contain an alpha
(?=.*[!##$%]) - uses lookahead and says the password must contain 1 or more special characters which are defined
[0-9a-zA-Z!##$%] - dictates the allowed characters
{8,} - says the password must be at least 8 characters long
It might need a little tweaking e.g. specifying exactly which special characters you need but it should do the trick.
-(BOOL)validatePassword:(NSString *) password{
NSString *COMMON_CHARECTERS = #"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
NSString *SPECIAL_CHARECTERS = #"##$%^&*";
NSCharacterSet *cs_common = [NSCharacterSet characterSetWithCharactersInString:COMMON_CHARECTERS];
NSCharacterSet *cs_special = [NSCharacterSet characterSetWithCharactersInString:SPECIAL_CHARECTERS];
NSString *filtere_common = [[password componentsSeparatedByCharactersInSet:cs_common] componentsJoinedByString:#""];
NSString *filtere_special = [[password componentsSeparatedByCharactersInSet:cs_special] componentsJoinedByString:#""];
BOOL valid = (password.length == (filtere_common.length + filtere_special.length));
return valid;
}
You can use regex to identify use of special character. like
^([a-zA-Z+]+[0-9+]+[&#!#+]+)$
You can use character sets as well to validate password:- Check this link

How to remove first 5 and last 3 characters from a NSString

For example my string is NSString *str=#"appleIsTheBest". Remember that the code have to work with any strings, not just with this.
NSString *str = #"appleIsTheBest";
str = [str substringWithRange:NSMakeRange(5, str.length - 5 - 3)];
Of course, you'll need to check the string's length before sending the substringWithRange: message.

Get the unique characters in an NSString

How can I get the unique characters in an NSString?
What I'm trying to do is get all the illegal characters in an NSString so that I can prompt the user which ones were inputted and therefore need to be removed. I start off by defining an NSCharacterSet of legal characters, separate them with every occurrence of a legal character, and join what's left (only illegal ones) into a new NSString. I'm now planning to get the unique characters of the new NSString (as an array, hopefully), but I couldn't find a reference anywhere.
NSCharacterSet *legalCharacterSet = [NSCharacterSet
characterSetWithCharactersInString:#"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLKMNOPQRSTUVWXYZ0123456789-()&+:;,'.# "];
NSString *illegalCharactersInTitle = [[self.titleTextField.text.noWhitespace
componentsSeparatedByCharactersInSet:legalCharacterSet]
componentsJoinedByString:#""];
That should help you. I couldn't find any ready to use function for that.
NSMutableSet *uniqueCharacters = [NSMutableSet set];
NSMutableString *uniqueString = [NSMutableString string];
[illegalCharactersInTitle enumerateSubstringsInRange:NSMakeRange(0, illegalCharactersInTitle.length) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
if (![uniqueCharacters containsObject:substring]) {
[uniqueCharacters addObject:substring];
[uniqueString appendString:substring];
}
}];
Try with the following adaptation of your code:
// legal set
NSCharacterSet *legalCharacterSet = [NSCharacterSet
characterSetWithCharactersInString:#"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLKMNOPQRSTUVWXYZ0123456789-()&+:;,'.# "];
// test strings
NSString *myString = #"LegalStrin()";
//NSString *myString = #"francesco#gmail.com"; illegal string
NSMutableCharacterSet *stringSet = [NSCharacterSet characterSetWithCharactersInString:myString];
// inverts the set
NSCharacterSet *illegalCharacterSet = [legalCharacterSet invertedSet];
// intersection of the string set and the illegal set that modifies the mutable stringset itself
[stringSet formIntersectionWithCharacterSet:illegalCharacterSet];
// prints out the illegal characters with the convenience method
NSLog(#"IllegalStringSet: %#", [self stringForCharacterSet:stringSet]);
I adapted the method to print from another stackoverflow question:
- (NSString*)stringForCharacterSet:(NSCharacterSet*)characterSet
{
NSMutableString *toReturn = [#"" mutableCopy];
unichar unicharBuffer[20];
int index = 0;
for (unichar uc = 0; uc < (0xFFFF); uc ++)
{
if ([characterSet characterIsMember:uc])
{
unicharBuffer[index] = uc;
index ++;
if (index == 20)
{
NSString * characters = [NSString stringWithCharacters:unicharBuffer length:index];
[toReturn appendString:characters];
index = 0;
}
}
}
if (index != 0)
{
NSString * characters = [NSString stringWithCharacters:unicharBuffer length:index];
[toReturn appendString:characters];
}
return toReturn;
}
First of all, you have to be careful about what you consider characters. The API of NSString uses the word characters when talking about what Unicode refers to as UTF-16 code units, but dealing with code units in isolation will not give you what users think of as characters. For example, there are combining characters that compose with the previous character to produce a different glyph. Also, there are surrogate pairs, which only make sense when, um, paired.
As a result, you will actually need to collect substrings which contain what the user thinks of as characters.
I was about to write code very similar to Grzegorz Krukowski's answer. He beat me to it, so I won't but I will add that your code to filter out the legal characters is broken because of the reasons I cite above. For example, if the text contains "é" and it's decomposed as "e" plus a combining acute accent, your code will strip the "e", leaving a dangling combining acute accent. I believe your intent is to treat the "é" as illegal.

iOS: changing NSString value

Will this bit of code produce any memory leaks? Is it the correct way to change NSString values?
NSString * enemiesAndElementsTextureFileName = #"bla bla";
enemiesAndElementsTextureFileName = #"bl";
That way of doing it won't cause any memory leaks and it is indeed correct. In this case you wouldn't need an NSMutableString because you aren't altering the string literal itself, you are simply replacing the string value with a new one (replacing #"bla bla" with #"bl").
In this case, however, your string will now be 'bl', so you can delete that first line value and just have NSString * enemiesAndElementsTextureFileName = #"bl";
Yes NSString allocated once. This is one of the way
Yes, use NSMutableString with the following method as your needs:
// Allocate
NSMutableString *str = [[NSMutableString alloc] initWithCapacity:10];
// set string content
[str setString:#"1234"];
// Append
[str appendString:#"567"];
// Concat
[str appendFormat:#"age is %i and height is %.2f", 27, 1.55f];
// Replace
NSRange range = [str rangeOfString:#"height"];//查找字符串height的位置
[str replaceCharactersInRange:range withString:#"no"];
// Insert
[str insertString:#"abc" atIndex:2];
// Delete
range = [str rangeOfString:#"age"];
[str deleteCharactersInRange:range];
NSLog(#"%#", str);

Resources