Re: URL Parsing
Re: URL Parsing
- Subject: Re: URL Parsing
- From: Jerry Krinock <email@hidden>
- Date: Thu, 29 Jan 2009 21:08:17 -0800
On 2009 Jan 28, at 20:42, Seth Willits wrote:
I can put together my own solution, but I'm *sure* there has to be
some real way of doing this built-in *somewhere*, so I have to ask...
24 hours with no reply probably means that you haven't missed any
built-in API.
My app has a URL handler, and I want the user to be able to click a
link to save some time to things. The URL would have the form:
myapp://action?key1=valueNoSpaces&key2=value+with+space&key3=value
+with
percent
escapes
Does anyone know of a couple of methods that can simply grab the
action and KV pairs decoded without a lot of hassle?
Well, once you start getting into all the encoding issues, it gets a
little complicated. A couple months ago I collected all my methods
related to this in a category on NSString. I've done some in-house
testing on it, but there still may be bugs. If you use it, and find
any bugs, let me know.
It looks like the last method in the header decodes a query into a
dictionary, which is I believe what you're looking for.
************** NSString+URIQuery.h
******************************************
#import <Cocoa/Cocoa.h>
@interface NSString (URIQuery)
// NSString has a method for decoding percent escapes but none for
encoding
// So, here they are:
- (NSString*)encodePercentEscapesPerRFC2396 ;
- (NSString*)encodePercentEscapesStrictlyPerRFC2396 ;
// Decodes any existing percent escapes which should not be encoded
per RFC 2396 sec. 2.4.3
// Encodes any characters which should be encoded per RFC 2396 sec.
2.4.3.
- (NSString*)encodePercentEscapesPerRFC2396ButNot:(NSString*)butNot
butAlso:(NSString*)butAlso ;
// butNot and/or butAlso may be nil
// I did an experiment to find out which ASCII characters are encoded,
// by encoding a string with all the nonalphanumeric characters
available on the
// Macintosh keyboard, with and without the shift key down. There
were fourteen:
// ` # % ^ [ ] { } \ | " < >
// You only see thirteen because the fourtheenth one is the space
character, " ".
// This agrees with the lists of "space" "delims" and "unwise" in by
RFC 2396 sec. 2.4.3
// Also, I found that all of the non-ASCII characters available on the
Macintosh
// keyboard by using option or shift+option are also encoded. Some of
these have
// two bytes of unicode to encode, for example ¤ for 0xC2A4
/*!
@brief Returns a string of the form "key0=value0&key1=value1&...".
All keys and values are percent-escape encoded
@details For compatibility with POST, does not prepend a "?"
All keys and all values must be NSString objects
@param The dictionary of keys and values to be encoded into the
string
*/
+ stringWithQueryDictionary:(NSDictionary*)dictionary ;
/* Not sure how this is different than -
stringByReplacingPercentEscapesUsingEncoding:
Performing test in implementation to see if I can use that instead
of this.
*/
- (NSString*)decodeAllPercentEscapes ;
/*!
@brief Assuming that the receiver is a query string of key=value
pairs,
of the form "key0=value0&key1=value1&...", with keys and values
percent-escape
encoded per RFC 2396, returns a dictionary of the keys and values.
@details Supports both ampersand "&" and semicolon ";" to delimit
key-value
pairs. The latter is recommended here:
http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#h-B.2.2
*/
- (NSDictionary*)queryDictionaryUsingEncoding:
(NSStringEncoding)encoding ;
@end
************** NSString+URIQuery.m
******************************************
#import "NSString+URIQuery.h"
@implementation NSString (URIQuery)
- (NSString*)encodePercentEscapesPerRFC2396 {
return (NSString*)
[(NSString*)CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)self, NULL, NULL, kCFStringEncodingUTF8) autorelease] ;
}
- (NSString*)encodePercentEscapesStrictlyPerRFC2396 {
CFStringRef decodedString = (CFStringRef)[self
decodeAllPercentEscapes] ;
// The above may return NULL if url contains invalid escape
sequences like ème, èfe, è00 or è11,
// because CFURLCreateStringByReplacingPercentEscapes() isn't
smart enough to ignore them.
CFStringRef recodedString =
CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
decodedString, NULL, NULL, kCFStringEncodingUTF8);
// And then, if decodedString is NULL, recodedString will be NULL
too.
// So, we recover from this rare but possible error by returning
the original self
// because it's "better than nothing".
NSString* answer = (recodedString != NULL) ?
[(NSString*)recodedString autorelease] : self ;
// Note that if recodedString is NULL, we don't need to
CFRelease() it.
// Actually, CFRelease(NULL) causes a crash. That's kind of
stupid, Apple.
return answer ;
}
- (NSString*)encodePercentEscapesPerRFC2396ButNot:(NSString*)butNot
butAlso:(NSString*)butAlso {
return (NSString*)
[(NSString*)CFURLCreateStringByAddingPercentEscapes(
NULL
,
(CFStringRef
)self,
(CFStringRef
)butNot,
(CFStringRef
)butAlso,
kCFStringEncodingUTF8
) autorelease] ;
}
+ stringWithQueryDictionary:(NSDictionary*)dictionary {
NSMutableString* string = [NSMutableString string] ;
NSUInteger countdown = [dictionary count] ;
NSString* additionsToRFC2396 = @"+=;" ;
for (NSString* key in dictionary) {
[string appendFormat:@"%@=%@",
[key encodePercentEscapesPerRFC2396ButNot:nil
butAlso:additionsToRFC2396],
[[dictionary valueForKey:key]
encodePercentEscapesPerRFC2396ButNot:nil
butAlso:additionsToRFC2396]
] ;
countdown-- ;
if (countdown > 0) {
[string appendString:@"&"] ;
}
}
return [NSString stringWithString:string] ;
}
- (NSString*)decodeAllPercentEscapes {
// Unfortunately, CFURLCreateStringByReplacingPercentEscapes()
seems to only replace %[NUMBER] escapes
NSString* cfWay = (NSString*)
[(NSString
*)CFURLCreateStringByReplacingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)self, CFSTR("")) autorelease] ;
NSString* cocoaWay = [self
stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] ;
if (![cfWay isEqualToString:cocoaWay]) {
NSBeep() ;
NSLog(@"[%@ %s]: CF and Cocoa different for %@", [self
class], _cmd, self) ;
}
return cfWay ;
}
- (NSDictionary*)queryDictionaryUsingEncoding:
(NSStringEncoding)encoding {
NSCharacterSet* delimiterSet = [NSCharacterSet
characterSetWithCharactersInString:@"&;"] ;
NSMutableDictionary* pairs = [NSMutableDictionary dictionary] ;
NSScanner* scanner = [[NSScanner alloc] initWithString:self] ;
while (![scanner isAtEnd]) {
NSString* pairString ;
[scanner scanUpToCharactersFromSet:delimiterSet
intoString:&pairString] ;
[scanner scanCharactersFromSet:delimiterSet intoString:NULL] ;
NSArray* kvPair = [pairString
componentsSeparatedByString:@"="] ;
if ([kvPair count] == 2) {
NSString* key = [[kvPair objectAtIndex:0]
stringByReplacingPercentEscapesUsingEncoding:encoding] ;
NSString* value = [[kvPair objectAtIndex:1]
stringByReplacingPercentEscapesUsingEncoding:encoding] ;
[pairs setObject:value forKey:key] ;
}
}
return [NSDictionary dictionaryWithDictionary:pairs] ;
}
@end
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden
References: | |
| >URL Parsing (From: Seth Willits <email@hidden>) |