Regular expression to validate a URL safe string in Objective C - objective-c

In my iPhone application I am constructing a URL by passing some params
as in
NSURL * url;
url = [url URLByAppendingPathComponent:Param1];
Now I want to validate Param1 to accept only the URL safe characters, other way around is to encode the URL I agree , but I need to validate the Param1 since it is exposed to the user to change, is there any stright forward native API to do so?, or Regex is the only way? please provide me the Regex if so , Thanx in advance

You could encode it
NSString *encodedString = (__bridge_transfer NSString *)
CFURLCreateStringByAddingPercentEscapes(
kCFAllocatorDefault,
(__bridge CFStringRef)originalString,
NULL,
CFSTR(":/?#[]#!$&'()*+,;="),
kCFStringEncodingUTF8);
if (![encodedString isEqualToString:originalString]) {
// It contains characters that are probably not legal.
}
Or you could just check for the characters listed above, but what fun would that be? :-)
NSCharacterSet *charSet = [NSCharacterSet
characterSetWithCharactersInString:
#":/?#[]#!$&'()*+,;="];
NSRange range = [string rangeOfCharacterFromSet:charSet];
if (range.location != NSNotFound) { ... }

Related

stringByAddingPercentEscapesUsingEncoding does not escape "&"

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

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

Detect type from string objective-c

Whats the best way of detecting a data type from a string in Objective-c?
I'm importing CSV files but each value is just a string.
E.g. How do I tell that "2.0" is a number, "London" should be treated as a category and that "Monday 2nd June" or "2/6/2012" is a date.
I need to test the datatype some how and be confident about which type I use before passing the data downstream.
Regex is the only thing I can think about, but if you are on mac or iphone, than you might try e.g. RegexKitLite
----------UPDATE----------
Instead of my previous suggestion, try this:
NSString *csvString = #"333";
NSString *charSet = #"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.,";
NSScanner *typeScanner = [NSScanner scannerWithString: csvString];
[typeScanner setCharactersToBeSkipped: [NSCharacterSet characterSetWithCharactersInString:charSet]];
NSString *checkString = [[NSString alloc] init];
[typeScanner scanString:csvString intoString:&checkString];
if([csvString length] == [checkString length]){
//the string "csvString" is an integer
}
To check for other types (float, string, etc.), change this line (which checks for int type) NSString *charSet = #"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.,"; to NSString *charSet = #"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; (which checks for float type) or NSString *charSet = #"1234567890"; (which checks for a string composed only of letters).
-------Initial Post-------
You could do this:
NSString *stringToTest = #"123";
NSCharacterSet *intValueSet = [NSCharacterSet decimalDigitCharacterSet];
NSArray *test = [stringToTest componentsSeparatedByCharactersInSet:intValueSet];
if ([test count]==[stringToTest length]+1){
NSLog(#"It's an int!");
}
else {
NSLog(#"It's not an int");
}
This works for numbers that don't have a decimal point or commas as thousands separators, like "8493" and "883292837". I've tested it and it works.
Hope this provides a start for you! I'll try to figure out how to test for numbers with decimal points and strings.
Like Andrew said, regular expressions are probably good for this, but they're a bit complicated.

Decoding word-encoded Content-Disposition header file name in Objective-C

I am trying to retrieve a file name that can't be represented in ASCII from the content-disposition header.
This file name is word-encoded. Below is the encoded file name:
=?UTF-8?Q?=C3=ABst=C3=A9_=C3=A9_=C3=BAm_n=C3=B4m=C3=A9?= =?UTF-8?Q?_a=C3=A7ent=C3=BAad=C3=B5.xlsx?=
How do I get the decoded file name (that actually is "ësté é úm nômé açentúadõ.xlsx")?
PS: I am looking for an Objective-C implementation.
You probably want to search for a MIME handling framework, but I searched online and came up with nothing, so....
I couldn't find an example online, so I'm just showing the algorithm here. It's not the best example since I'm making a big assumption. That being that the string is always UTF-8 Q-encoded.
Q-encoding is like URL-encoding (percent-encoding), which Foundation's NSString already has support for decoding. The only (practical) difference when decoding (there are bigger differences when encoding) is that % encodings are = encodings instead.
Then there's the lead-in and lead-out stuff. Each encoded block has the format =?charset-name?encoding-type? ... encoded string here ... ?=. You should really read the charset name is use that encoding, and you should really read the encoding-type, since it may be "Q" or "B" (Base64).
This example only works for Q-encoding (a subset of quoted-printable). You should be able to easily modify it to handle the different charsets and to handle Base64 encoding however.
#import <Foundation/Foundation.h>
int main(void) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *encodedString = #"=?UTF-8?Q?=C3=ABst=C3=A9_=C3=A9_=C3=BAm_n=C3=B4m=C3=A9?= =?UTF-8?Q?_a=C3=A7ent=C3=BAad=C3=B5.xlsx?=";
NSScanner *scanner = [NSScanner scannerWithString:encodedString];
NSString *buf = nil;
NSMutableString *decodedString = [[NSMutableString alloc] init];
while ([scanner scanString:#"=?UTF-8?Q?" intoString:NULL]
|| ([scanner scanUpToString:#"=?UTF-8?Q?" intoString:&buf] && [scanner scanString:#"=?UTF-8?Q?" intoString:NULL])) {
if (buf != nil) {
[decodedString appendString:buf];
}
buf = nil;
NSString *encodedRange;
if (![scanner scanUpToString:#"?=" intoString:&encodedRange]) {
break; // Invalid encoding
}
[scanner scanString:#"?=" intoString:NULL]; // Skip the terminating "?="
// Decode the encoded portion (naively using UTF-8 and assuming it really is Q encoded)
// I'm doing this really naively, but it should work
// Firstly I'm encoding % signs so I can cheat and turn this into a URL-encoded string, which NSString can decode
encodedRange = [encodedRange stringByReplacingOccurrencesOfString:#"%" withString:#"=25"];
// Turn this into a URL-encoded string
encodedRange = [encodedRange stringByReplacingOccurrencesOfString:#"=" withString:#"%"];
// Remove the underscores
encodedRange = [encodedRange stringByReplacingOccurrencesOfString:#"_" withString:#" "];
[decodedString appendString:[encodedRange stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
}
NSLog(#"Decoded string = %#", decodedString);
[decodedString release];
[pool drain];
return 0;
}
This outputs:
chrisbook-pro:~ chris$ ./qp-decode
2010-12-01 18:54:42.903 qp-decode[9643:903] Decoded string = ësté é úm nômé açentúadõ.xlsx
Created an easier / successful method here using a trick involving NSString percent escapes..
https://stackoverflow.com/a/10888548/285694
I recently implemented a NSString category that decodes MIME Encoded-Word with either Q-encoding or B-encoding.
The code is available on GitHub and is briefly explained in this answer.

How to check if NSString begins with a certain character

How do you check if an NSString begins with a certain character (the character *).
The * is an indicator for the type of the cell, so I need the contents of this NSString without the *, but need to know if the * exists.
You can use the -hasPrefix: method of NSString:
Objective-C:
NSString* output = nil;
if([string hasPrefix:#"*"]) {
output = [string substringFromIndex:1];
}
Swift:
var output:String?
if string.hasPrefix("*") {
output = string.substringFromIndex(string.startIndex.advancedBy(1))
}
You can use:
NSString *newString;
if ( [[myString characterAtIndex:0] isEqualToString:#"*"] ) {
newString = [myString substringFromIndex:1];
}
hasPrefix works especially well.
for example if you were looking for a http url in a NSString, you would use componentsSeparatedByString to create an NSArray and the iterate the array using hasPrefix to find the elements that begin with http.
NSArray *allStringsArray =
[myStringThatHasHttpUrls componentsSeparatedByString:#" "]
for (id myArrayElement in allStringsArray) {
NSString *theString = [myArrayElement description];
if ([theString hasPrefix:#"http"]) {
NSLog(#"The URL is %#", [myArrayElement description]);
}
}
hasPrefix returns a Boolean value that indicates whether a given string matches the beginning characters of the receiver.
- (BOOL)hasPrefix:(NSString *)aString,
parameter aString is a string that you are looking for
Return Value is YES if aString matches the beginning characters of the receiver, otherwise NO. Returns NO if aString is empty.
As a more general answer, try using the hasPrefix method. For example, the code below checks to see if a string begins with 10, which is the error code used to identify a certain problem.
NSString* myString = #"10:Username taken";
if([myString hasPrefix:#"10"]) {
//display more elegant error message
}
Use characterAtIndex:. If the first character is an asterisk, use substringFromIndex: to get the string sans '*'.
NSString *stringWithoutAsterisk(NSString *string) {
NSRange asterisk = [string rangeOfString:#"*"];
return asterisk.location == 0 ? [string substringFromIndex:1] : string;
}
Another approach to do it..
May it help someone...
if ([[temp substringToIndex:4] isEqualToString:#"http"]) {
//starts with http
}
This might help? :)
http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/occ/instm/NSString/characterAtIndex:
Just search for the character at index 0 and compare it against the value you're looking for!
This nice little bit of code I found by chance, and I have yet to see it suggested on Stack. It only works if the characters you want to remove or alter exist, which is convenient in many scenarios. If the character/s does not exist, it won't alter your NSString:
NSString = [yourString stringByReplacingOccurrencesOfString:#"YOUR CHARACTERS YOU WANT TO REMOVE" withString:#"CAN either be EMPTY or WITH TEXT REPLACEMENT"];
This is how I use it:
//declare what to look for
NSString * suffixTorRemove = #"</p>";
NSString * prefixToRemove = #"<p>";
NSString * randomCharacter = #"</strong>";
NSString * moreRandom = #"<strong>";
NSString * makeAndSign = #"&amp;";
//I AM INSERTING A VALUE FROM A DATABASE AND HAVE ASSIGNED IT TO returnStr
returnStr = [returnStr stringByReplacingOccurrencesOfString:suffixTorRemove withString:#""];
returnStr = [returnStr stringByReplacingOccurrencesOfString:prefixToRemove withString:#""];
returnStr = [returnStr stringByReplacingOccurrencesOfString:randomCharacter withString:#""];
returnStr = [returnStr stringByReplacingOccurrencesOfString:moreRandom withString:#""];
returnStr = [returnStr stringByReplacingOccurrencesOfString:makeAndSign withString:#"&"];
//check the output
NSLog(#"returnStr IS NOW: %#", returnStr);
This one line is super easy to perform three actions in one:
Checks your string for the character/s you do not want
Can replaces them with whatever you like
Does not affect surrounding code
NSString* expectedString = nil;
if([givenString hasPrefix:#"*"])
{
expectedString = [givenString substringFromIndex:1];
}