How to URL Decode in iOS - Objective C - objective-c

The stringByReplacingPercentEscapesUsingEncoding method is not working properly as it's not decoding special symbols that dont start with a % character, i.e., the + character. Does anyone know of a better method to do this in iOS?
Here's what I'm currently using:
NSString *path = [#"path+with+spaces"
stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
And here's an example of the output:
path+with+spaces

NSString *path = [[#"path+with+spaces"
stringByReplacingOccurrencesOfString:#"+" withString:#" "]
stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
Note that the plus-for-space substitution is only used in application/x-www-form-urlencoded data - the query string part of a URL, or the body of a POST request.

// Decode a percent escape encoded string.
- (NSString*) decodeFromPercentEscapeString:(NSString *) string {
return (__bridge NSString *) CFURLCreateStringByReplacingPercentEscapesUsingEncoding(NULL,
(__bridge CFStringRef) string,
CFSTR(""),
kCFStringEncodingUTF8);
}
http://cybersam.com/ios-dev/proper-url-percent-encoding-in-ios
This seems to be the preferred way because...
"Apparently" this is a "bug" apple is aware of, but they haven't done anything about it yet... ( http://simonwoodside.com/weblog/2009/4/22/how_to_really_url_encode/ )

If you are trying to replace the plus sign with percent escapes, perform a string replacement from "+" to " " (single space). Then use stringByAddingPercentEscapesUsingEncoding: to add the percent escapes.
The plus sign is one of many reserved URL characters that is never encoded.
(stringByReplacingPercentEscapesUsingEncoding: decodes the percent escapes)

swift 2 :
extension String {
func uriDecodedString() -> String? {
return self.stringByReplacingOccurrencesOfString("+", withString: " ").stringByRemovingPercentEncoding
}
}

Also you can use the PercentEncoder library from Cocoapods.
Swift 4
Include the library to your Podfile:
pod PercentEncoder
Import the library PercentEncoder
import PercentEncoder
class ViewController{
...
}
Replace the "+" character by "%20" and use the method "ped_decodeURI"
"path+with+spaces".replacingOccurrences(of: "+", with: "%20").ped_decodeURI()
It will return "path with spaces"
Here the link for reference: https://cocoapods.org/pods/PercentEncoder

Related

addingPercentEncoding works different in Swift

I have obj-C method that encodes String:
- (NSString *) encodeValue:(NSString*) unescaped{
return [unescaped stringByAddingPercentEncodingWithAllowedCharacters:
[NSCharacterSet URLHostAllowedCharacterSet]];
}
input: testswiftapppod://
output: testswiftapppod%3A%2F%2F
I wrote the same method in Swift but got different output: testswiftapppod:%2F%2F
static func encodeValue(unescaped:String!) -> String{
return unescaped.addingPercentEncoding(
withAllowedCharacters: CharacterSet.urlHostAllowed)!
}
For some reason colon not converted
How to fix this issue?
I use Xcode 8.3
[EDIT]
From Docs:
// Returns a new string made from the receiver by replacing all
characters not in the allowedCharacters set with percent encoded
characters. UTF-8 encoding is used to determine the correct percent
encoded characters. Entire URL strings cannot be percent-encoded. This
method is intended to percent-encode an URL component or subcomponent
string, NOT the entire URL string. Any characters in allowedCharacters
outside of the 7-bit ASCII range are ignored.
- (nullable NSString *)stringByAddingPercentEncodingWithAllowedCharacters:(NSCharacterSet *)allowedCharacters NS_AVAILABLE(10_9, 7_0);
EDIT:
This is probably undocumented but intended behavior. See is `addingPercentEncoding` broken in Xcode 9 beta 2? for more details.
This is a bug.
I went over different cases, it seems all Swift code works correctly. Note that : is allowed in URL host, therefore it should not be encoded and the bug is in the Obj-C version.
NSCharacterSet *set = [NSCharacterSet URLHostAllowedCharacterSet];
NSLog(#"Colon is member: %#", [set characterIsMember:':'] ? #"true" : #"false"); // prints true
It's an interesting bug because if you add ":" to the character set manually
NSMutableCharacterSet *set = [[NSCharacterSet URLHostAllowedCharacterSet] mutableCopy];
[set addCharactersInString:#":"];
Everything starts to work correctly.
Report it.
Note that when encoding for URL parameters, you shouldn't use urlHostAllowed. If possible, use NSURLQuery to build your URL instead. Neither of the predefined sets is actually suitable for URL encoding. You can start with urlQueryAllowed but you still have to remove some characters from it.
See for example this answer for a correct solution or for example the implementation in Alamofire library.
The desired output can be generated by:
func encodeValue(_ string: String) -> String? {
guard let unescapedString = string.addingPercentEncoding(withAllowedCharacters: CharacterSet(charactersIn: ":/").inverted) else { return nil }
return unescapedString
}
let encodedString = encodeValue("testswiftapppod://") // testswiftapppod%3A%2F%2F

Objective-c URL encode Cloudstack [duplicate]

This question already has answers here:
Objective-C and Swift URL encoding
(13 answers)
Closed 9 years ago.
I am working on an IOS application that needs to communicate with an API (CloudStack). The API requires that each request is signed.
I need to URL encode the parameters and create an HMAC SHA1 hash. Everything works fine until I pass an parameter that contains an plus sign or an colon.
So I guess it is the URL encoding part of my application that isn't working correct. I've searched several sites and tried the provided solutions but without any results.
One of the API specifications is that all the spaces needs to be encoded as "%20" rather than "+".
The API signing guide: http://cloudstack.apache.org/docs/en-US/Apache_CloudStack/4.1.0/html/Developers_Guide/signing-api-requests.html
Currently I am using the following code to URL encode the URL:
-(NSString *)urlenc:(NSString *)val
{
NSString *result = [(NSString *)val stringByReplacingOccurrencesOfString:#"+" withString:#" "];
result = [result stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
return result;
}
I call the method like this:
[self urlenc#"2014-01-20T14:02:48+0100"]
In your case the problem probably is both the "+" and ":" character that stringByAddingPercentEscapesUsingEncoding does not encode.
You need to use an encoder that supports more characters, see this SO answer for more complete information.
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding encodes 14 characrters:
`#%^{}[]|\"<> plus the space character as percent escaped.
Here is sample code (iOS7 and above, otherwise see this SO answer):
You may need to change the characters that are encoded.
NSString *testString = #"2014-01-20T14:02:48+0100";
NSString *encodedString1 = [testString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(#"encodedString1: %#", encodedString1);
NSString *charactersToEscape = #"!*'();:#&=+$,/?%#[]\" ";
NSCharacterSet *allowedCharacters = [[NSCharacterSet characterSetWithCharactersInString:charactersToEscape] invertedSet];
NSString *encodedString2 = [testString stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters];
NSLog(#"encodedString2: %#", encodedString2);
NSLog output:
encodedString1: 2014-01-20T14:02:48+0100
encodedString2: 2014-01-20T14%3A02%3A48%2B0100

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:#"\""];
}

Parsing a Java Properties file in Objective-C for iPhone

I'm looking for a way in the iPhone SDK to read in a Properties file (not the XML flavor) for example this one:
# a comment
! a comment
a = a string
b = a string with escape sequences \t \n \r \\ \" \' \ (space) \u0123
c = a string with a continuation line \
continuation line
d.e.f = another string
would result in four key/value pairs.
I can't change this format as it is sent to me by a web service. Can you please direct me?
Thanks,
Emmanuel
I would take a look at ParseKit http://parsekit.com/. Otherwise you could use RegexKitLite and create some regular expressions.
I've ended with this solution if anybody is interested :
#interface NSDictionary (PropertiesFile)
+ (NSDictionary *)dictionaryWithPropertiesFile:(NSString *)file;
#end
#implementation NSDictionary (PropertiesFile)
+ (NSDictionary *)dictionaryWithPropertiesFile:(NSString *)file {
NSError *error = nil;
NSString *propertyFileContent = [[NSString alloc] initWithContentsOfFile:file encoding:NSUTF8StringEncoding error:&error];
if (error) return nil;
NSArray *properties = [propertyFileContent componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
if (properties.count == 0) return nil;
NSMutableDictionary *result = [[NSMutableDictionary alloc] initWithCapacity:properties.count];
for (NSString *propertySting in properties) {
NSArray *property = [propertySting componentsSeparatedByString:#"="];
if (property.count != 2) continue;
[result setObject:property[1] forKey:property[0]];
}
return result.allKeys.count > 0 ? result : nil;
}
#end
It's a perfectly simple parsing problem. Read a line. Ignore if comment. Check for continuation, and read/append continuation lines as needed. Look for the "=". Make the left side of the "=" (after trimming white space) the key. Either parse the right side yourself or put it into an NSString and use stringWithFormat on it to "reduce" any escapes to pure character form. Return key and reduced right side.
(But refreshing my memory on the properties file format reminds me that:
The key contains all of the characters in the line starting with the
first non-white space character and up to, but not including, the
first unescaped '=', ':', or white space character other than a line
terminator. All of these key termination characters may be included in
the key by escaping them with a preceding backslash character;
So a little scanning of the line is required to separate the key from the rest. Nothing particularly difficult, though.)
Have you considered using lex/yacc or flex/bison to generate your own compiler code from a description of the grammar for properties files? I'm not sure if there are any existing grammars defined for a Java properties file, but it seems like it would be a pretty simple grammar to write.
Here's another SO post that mentions this approach for general purpose parsing
Take a look at this PropertyParser
NSString *text = #"sample key = sample value";
PropertyParser *propertyParser = [[PropertyParser alloc] init];
NSMutableDictionary *keyValueMap = [propertyParser parse:text];
You can now use NSRegularExpression class to do this.

What's the best way to trim whitespace from a string in Cocoa Touch?

I'm looking to determine whether a string value from a user input (UITextField) is "blank" if it's not nil. Checking if [textField.text isEqualToString:""] isn't quite enough because I want to avoid any blank/whitespace input (like say a few space characters).
There does seem to be an indication of a good solution for my particular problem in this StOv post.
Basically it goes something like this, but I suspect there has to (or ought to) be a better way:
NSString *strResult;
NSScanner* scanner = [NSScanner scannerWithString:textField.text];
BOOL hasValidChars = [scanner scanUpToCharactersFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]
intoString:&strResult];
// if hasValidChars == YES, we've got nonwhite space chars collected into strResult
This clearly only works for my particular circumstance, and even then it would fail if the first character was a space but the data I wanted followed. So, I realize I've been a little spoiled by Ruby, but there must be a tried and true idiom for trimming strings in Cocoa.
Aaaand the answer is already out there, my apologies:
NSString's -stringByTrimmingCharactersInSet: would do it:
Returns a new string made by removing
from both ends of the receiver
characters contained in a given
character set.
I'm still curious to hear if anybody has other/preferred ways of doing this.
You're using whitespaceAndNewlineCharacterSet, good. But instead of using scanUpToCharactersFromSet, why not use stringByTrimmingCharactersInSet? Something like this...
strResult = [strResult stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
EDIT: Didn't realize you already found stringByTrimmingCharactersInSet until after I posted this.
What you are looking for is
[string stringByReplacingOccurrencesOfString:#" " withString:#""].
Deleting white space in the middle of a string is not called 'trimming'.
Trimming by definition works from the edges.
To make this easier on yourself and instead of making a subclass, you can modify existing Apple classes and do something like
//
// NSString+MyExtensions.h
//
#interface NSString (MyExtensions)
- (NSString *)trimmed;
#end
and the implementation
//
// NSString+MyExtensions.m
//
#import "NSString+MyExtensions.h"
#implementation NSString (MyExtensions)
- (NSString *)trimmed {
return [self stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
#end
So now anywhere in your app that you use an NSString, you can now call [#" hello world " trimmed] like below
//
// ViewController.m
//
#import "NSString+MyExtensions.h"
#implementation ViewController
- (void)viewDidLoad {
NSString *string = #" This is a string ";
NSLog(#"The original string: %# \n The trimmed string: %#\n\n",
string,
[string trimmed]);
string = #" ";
if([string trimmed].length == 0)
NSLog(#"%#", #"String is empty! :O");
}
#end
Which would print out
The original string: This is a string
The trimmed string: This is a string
String is empty! :O