Extracting an NSString from both Parenthesis and Quotations - objective-c

I have a string that is returned from a WebAPI call that looks like this:
(
"username#domain.com"
)
As a workaround, I am trying to extract just the email address i.e. username#domain.com
I am not sure what the best approach to do this is as I'm extracting the data within the parenthesis and the quotations.
Any pointers (no pun intended) are appreciated.

The easiest way is to use stringByTrimmingCharactersInSet::
NSString *source = /* your source */;
NSCharacterSet *charSet =
[NSCharacterSet characterSetWithCharactersInString:#" \"()\n"];
NSString *email = [source stringByTrimmingCharactersInSet:charSet];
Harder one involves NSRegularExpression.

An even easier one, if you know that the string always starts with (" and ends by "):
NSString *email = [response substringWithRange:NSMakeRange(2, [response length] - 4)];

Related

Objective-C URL encoding issues

I am creating a URL string like so:
[Items appendString:[object objectForKey:#"Items"]];
[Items appendString:#"*"];
[Items deleteCharactersInRange:NSMakeRange([Items length]-1, 1)];
//This returns this: ~SEWER/FLATWORK SUPPLY & INSTALL - 25% of CONTRACT*~SEWER/FLATWORK SUPPLY & INSTALL - 75% of CONTRACT*SUMP PUMP PIT
//add Items to URL
NSString *fullURL = [NSString stringWithFormat:#"https://example.com?Items=%#, [Items stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
but it returns like so:
Items=~SEWER/FLATWORK%20SUPPLY%20&%20INSTALL%20-%2025%25%20of%20CONTRACT*~SEWER/FLATWORK%20SUPPLY%20&%20INSTALL%20-%2075%25%20of%20CONTRACT*SUMP%20PUMP%20PIT
how do I get it return like this:
%20%26%20 instead of %20&%20 for the & ?
I think the issue is that the method tries to be too clever - it only does as much as is necessary to get a legal URL and because you don't have a question mark in your string, it probably thinks it is OK to leave the ampersands in.
Try constructing the whole URL and do the escaping on the whole URL.
NSString *fullURL = [[#"https://example.com?Items=" stringByAppendingString: items]
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
Or perhaps use stringByAddingPercentEncodingWithAllowedCharacters:.
Try this.
fullURL=[fullURL stringByReplacingOccurrencesOfString:#"&" withString:#"%26"];
NSLog(#"fullURL: %# ...", fullURL);
Use CFURLCreateStringByAddingPercentEscapes() for getting UTF8stringencoding of characters
NSString *urlString = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef) Items, NULL, CFSTR("!*'();:#&=+$,/?%#[]"), kCFStringEncodingUTF8))

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

NSString - Convert to pure alphabet only (i.e. remove accents+punctuation)

I'm trying to compare names without any punctuation, spaces, accents etc.
At the moment I am doing the following:
-(NSString*) prepareString:(NSString*)a {
//remove any accents and punctuation;
a=[[[NSString alloc] initWithData:[a dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES] encoding:NSASCIIStringEncoding] autorelease];
a=[a stringByReplacingOccurrencesOfString:#" " withString:#""];
a=[a stringByReplacingOccurrencesOfString:#"'" withString:#""];
a=[a stringByReplacingOccurrencesOfString:#"`" withString:#""];
a=[a stringByReplacingOccurrencesOfString:#"-" withString:#""];
a=[a stringByReplacingOccurrencesOfString:#"_" withString:#""];
a=[a lowercaseString];
return a;
}
However, I need to do this for hundreds of strings and I need to make this more efficient. Any ideas?
NSString* finish = [[start componentsSeparatedByCharactersInSet:[[NSCharacterSet letterCharacterSet] invertedSet]] componentsJoinedByString:#""];
Before using any of these solutions, don't forget to use decomposedStringWithCanonicalMapping to decompose any accented letters. This will turn, for example, é (U+00E9) into e ‌́ (U+0065 U+0301). Then, when you strip out the non-alphanumeric characters, the unaccented letters will remain.
The reason why this is important is that you probably don't want, say, “dän” and “dün”* to be treated as the same. If you stripped out all accented letters, as some of these solutions may do, you'll end up with “dn”, so those strings will compare as equal.
So, you should decompose them first, so that you can strip the accents and leave the letters.
*Example from German. Thanks to Joris Weimar for providing it.
On a similar question, Ole Begemann suggests using stringByFoldingWithOptions: and I believe this is the best solution here:
NSString *accentedString = #"ÁlgeBra";
NSString *unaccentedString = [accentedString stringByFoldingWithOptions:NSDiacriticInsensitiveSearch locale:[NSLocale currentLocale]];
Depending on the nature of the strings you want to convert, you might want to set a fixed locale (e.g. English) instead of using the user's current locale. That way, you can be sure to get the same results on every machine.
One important precision over the answer of BillyTheKid18756 (that was corrected by Luiz but it was not obvious in the explanation of the code):
DO NOT USE stringWithCString as a second step to remove accents, it can add unwanted characters at the end of your string as the NSData is not NULL-terminated (as stringWithCString expects it).
Or use it and add an additional NULL byte to your NSData, like Luiz did in his code.
I think a simpler answer is to replace:
NSString *sanitizedText = [NSString stringWithCString:[sanitizedData bytes] encoding:NSASCIIStringEncoding];
By:
NSString *sanitizedText = [[[NSString alloc] initWithData:sanitizedData encoding:NSASCIIStringEncoding] autorelease];
If I take back the code of BillyTheKid18756, here is the complete correct code:
// The input text
NSString *text = #"BûvérÈ!#$&%^&(*^(_()-*/48";
// Defining what characters to accept
NSMutableCharacterSet *acceptedCharacters = [[NSMutableCharacterSet alloc] init];
[acceptedCharacters formUnionWithCharacterSet:[NSCharacterSet letterCharacterSet]];
[acceptedCharacters formUnionWithCharacterSet:[NSCharacterSet decimalDigitCharacterSet]];
[acceptedCharacters addCharactersInString:#" _-.!"];
// Turn accented letters into normal letters (optional)
NSData *sanitizedData = [text dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
// Corrected back-conversion from NSData to NSString
NSString *sanitizedText = [[[NSString alloc] initWithData:sanitizedData encoding:NSASCIIStringEncoding] autorelease];
// Removing unaccepted characters
NSString* output = [[sanitizedText componentsSeparatedByCharactersInSet:[acceptedCharacters invertedSet]] componentsJoinedByString:#""];
If you are trying to compare strings, use one of these methods. Don't try to change data.
- (NSComparisonResult)localizedCompare:(NSString *)aString
- (NSComparisonResult)localizedCaseInsensitiveCompare:(NSString *)aString
- (NSComparisonResult)compare:(NSString *)aString options:(NSStringCompareOptions)mask range:(NSRange)range locale:(id)locale
You NEED to consider user locale to do things write with strings, particularly things like names.
In most languages, characters like ä and å are not the same other than they look similar. They are inherently distinct characters with meaning distinct from others, but the actual rules and semantics are distinct to each locale.
The correct way to compare and sort strings is by considering the user's locale. Anything else is naive, wrong and very 1990's. Stop doing it.
If you are trying to pass data to a system that cannot support non-ASCII, well, this is just a wrong thing to do. Pass it as data blobs.
https://developer.apple.com/library/ios/documentation/cocoa/Conceptual/Strings/Articles/SearchingStrings.html
Plus normalizing your strings first (see Peter Hosey's post) precomposing or decomposing, basically pick a normalized form.
- (NSString *)decomposedStringWithCanonicalMapping
- (NSString *)decomposedStringWithCompatibilityMapping
- (NSString *)precomposedStringWithCanonicalMapping
- (NSString *)precomposedStringWithCompatibilityMapping
No, it's not nearly as simple and easy as we tend to think.
Yes, it requires informed and careful decision making. (and a bit of non-English language experience helps)
Consider using the RegexKit framework. You could do something like:
NSString *searchString = #"This is neat.";
NSString *regexString = #"[\W]";
NSString *replaceWithString = #"";
NSString *replacedString = [searchString stringByReplacingOccurrencesOfRegex:regexString withString:replaceWithString];
NSLog (#"%#", replacedString);
//... Thisisneat
Consider using NSScanner, and specifically the methods -setCharactersToBeSkipped: (which accepts an NSCharacterSet) and -scanString:intoString: (which accepts a string and returns the scanned string by reference).
You may also want to couple this with -[NSString localizedCompare:], or perhaps -[NSString compare:options:] with the NSDiacriticInsensitiveSearch option. That could simplify having to remove/replace accents, so you can focus on removing puncuation, whitespace, etc.
If you must use an approach like you presented in your question, at least use an NSMutableString and replaceOccurrencesOfString:withString:options:range: — that will be much more efficient than creating tons of nearly-identical autoreleased strings. It could be that just reducing the number of allocations will boost performance "enough" for the time being.
To give a complete example by combining the answers from Luiz and Peter, adding a few lines, you get the code below.
The code does the following:
Creates a set of accepted characters
Turn accented letters into normal letters
Remove characters not in the set
Objective-C
// The input text
NSString *text = #"BûvérÈ!#$&%^&(*^(_()-*/48";
// Create set of accepted characters
NSMutableCharacterSet *acceptedCharacters = [[NSMutableCharacterSet alloc] init];
[acceptedCharacters formUnionWithCharacterSet:[NSCharacterSet letterCharacterSet]];
[acceptedCharacters formUnionWithCharacterSet:[NSCharacterSet decimalDigitCharacterSet]];
[acceptedCharacters addCharactersInString:#" _-.!"];
// Turn accented letters into normal letters (optional)
NSData *sanitizedData = [text dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *sanitizedText = [NSString stringWithCString:[sanitizedData bytes] encoding:NSASCIIStringEncoding];
// Remove characters not in the set
NSString* output = [[sanitizedText componentsSeparatedByCharactersInSet:[acceptedCharacters invertedSet]] componentsJoinedByString:#""];
Swift (2.2) example
let text = "BûvérÈ!#$&%^&(*^(_()-*/48"
// Create set of accepted characters
let acceptedCharacters = NSMutableCharacterSet()
acceptedCharacters.formUnionWithCharacterSet(NSCharacterSet.letterCharacterSet())
acceptedCharacters.formUnionWithCharacterSet(NSCharacterSet.decimalDigitCharacterSet())
acceptedCharacters.addCharactersInString(" _-.!")
// Turn accented letters into normal letters (optional)
let sanitizedData = text.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: true)
let sanitizedText = String(data: sanitizedData!, encoding: NSASCIIStringEncoding)
// Remove characters not in the set
let components = sanitizedText!.componentsSeparatedByCharactersInSet(acceptedCharacters.invertedSet)
let output = components.joinWithSeparator("")
Output
The output for both examples would be: BuverE!_-48
Just bumped into this, maybe its too late, but here is what worked for me:
// text is the input string, and this just removes accents from the letters
// lossy encoding turns accented letters into normal letters
NSMutableData *sanitizedData = [text dataUsingEncoding:NSASCIIStringEncoding
allowLossyConversion:YES];
// increase length by 1 adds a 0 byte (increaseLengthBy
// guarantees to fill the new space with 0s), effectively turning
// sanitizedData into a c-string
[sanitizedData increaseLengthBy:1];
// now we just create a string with the c-string in sanitizedData
NSString *final = [NSString stringWithCString:[sanitizedData bytes]];
#interface NSString (Filtering)
- (NSString*)stringByFilteringCharacters:(NSCharacterSet*)charSet;
#end
#implementation NSString (Filtering)
- (NSString*)stringByFilteringCharacters:(NSCharacterSet*)charSet {
NSMutableString * mutString = [NSMutableString stringWithCapacity:[self length]];
for (int i = 0; i < [self length]; i++){
char c = [self characterAtIndex:i];
if(![charSet characterIsMember:c]) [mutString appendFormat:#"%c", c];
}
return [NSString stringWithString:mutString];
}
#end
These answers didn't work as expected for me. Specifically, decomposedStringWithCanonicalMapping didn't strip accents/umlauts as I'd expected.
Here's a variation on what I used that answers the brief:
// replace accents, umlauts etc with equivalent letter i.e 'é' becomes 'e'.
// Always use en_GB (or a locale without the characters you wish to strip) as locale, no matter which language we're taking as input
NSString *processedString = [string stringByFoldingWithOptions: NSDiacriticInsensitiveSearch locale: [NSLocale localeWithLocaleIdentifier: #"en_GB"]];
// remove non-letters
processedString = [[processedString componentsSeparatedByCharactersInSet:[[NSCharacterSet letterCharacterSet] invertedSet]] componentsJoinedByString:#""];
// trim whitespace
processedString = [processedString stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]];
return processedString;
Peter's Solution in Swift:
let newString = oldString.componentsSeparatedByCharactersInSet(NSCharacterSet.letterCharacterSet().invertedSet).joinWithSeparator("")
Example:
let oldString = "Jo_ - h !. nn y"
// "Jo_ - h !. nn y"
oldString.componentsSeparatedByCharactersInSet(NSCharacterSet.letterCharacterSet().invertedSet)
// ["Jo", "h", "nn", "y"]
oldString.componentsSeparatedByCharactersInSet(NSCharacterSet.letterCharacterSet().invertedSet).joinWithSeparator("")
// "Johnny"
I wanted to filter out everything except letters and numbers, so I adapted Lorean's implementation of a Category on NSString to work a little different. In this example, you specify a string with only the characters you want to keep, and everything else is filtered out:
#interface NSString (PraxCategories)
+ (NSString *)lettersAndNumbers;
- (NSString*)stringByKeepingOnlyLettersAndNumbers;
- (NSString*)stringByKeepingOnlyCharactersInString:(NSString *)string;
#end
#implementation NSString (PraxCategories)
+ (NSString *)lettersAndNumbers { return #"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; }
- (NSString*)stringByKeepingOnlyLettersAndNumbers {
return [self stringByKeepingOnlyCharactersInString:[NSString lettersAndNumbers]];
}
- (NSString*)stringByKeepingOnlyCharactersInString:(NSString *)string {
NSCharacterSet *characterSet = [NSCharacterSet characterSetWithCharactersInString:string];
NSMutableString * mutableString = #"".mutableCopy;
for (int i = 0; i < [self length]; i++){
char character = [self characterAtIndex:i];
if([characterSet characterIsMember:character]) [mutableString appendFormat:#"%c", character];
}
return mutableString.copy;
}
#end
Once you've made your Categories, using them is trivial, and you can use them on any NSString:
NSString *string = someStringValueThatYouWantToFilter;
string = [string stringByKeepingOnlyLettersAndNumbers];
Or, for example, if you wanted to get rid of everything except vowels:
string = [string stringByKeepingOnlyCharactersInString:#"aeiouAEIOU"];
If you're still learning Objective-C and aren't using Categories, I encourage you to try them out. They're the best place to put things like this because it gives more functionality to all objects of the class you Categorize.
Categories simplify and encapsulate the code you're adding, making it easy to reuse on all of your projects. It's a great feature of Objective-C!

How to remove first 3 characters from NSString?

I have a string like this "A. rahul VyAs"
and i want to remove "A. " and the space after the "A." so that new string would be "rahul VyAs"
How do i achieve this?
You can use the NSString instance methods substringWithRange: or substringFromIndex:
NSString *str = #"A. rahul VyAs";
NSString *newStr = [str substringWithRange:NSMakeRange(3, [str length]-3)];
or
NSString *str = #"A. rahul VyAs";
NSString *newStr = [str substringFromIndex:3];
This is a solution I have seen specifically for removing regularly occurring prefixes and solving the answer to the question How do I remove "A. "?
NSString * name = #"A. rahul VyAs";
NSString * prefixToRemove = #"A. ";
name = [name stringByReplacingOccurrencesOfString:prefixToRemove withString:#""];
This code will remove what you tell it to remove/change if the character set exists, such as "A. ", even if the three characters (or more/less) are in the middle of the string.
If you wanted to remove rahul, you can. It's diverse in that you specify exactly what you want removed or changed, and if it exists anywhere in the String, it will be removed or changed.
If you only want a certain specified number of characters removed from the front of the text that are always random or unknown, use the [string length] method as is the top answer.
If you want to remove or change certain characters that repeatedly appear, the method I have used will enable that, similar to Wordsearch on document editors.
Try this,
char *string=[#"A. rahul VyAs" cStringUsingEncoding:NSUTF8StringEncoding];
char *subString=&name[3];
NSString *newString=[NSString stringWithCString:subString encoding:NSUTF8StringEncoding];
It's this simple:
myString = [myString subStringFromIndex:3]
That's it.

How to add percent sign to NSString

I want to have a percentage sign in my string after a digit. Something like this: 75%.
How can I have this done? I tried:
[NSString stringWithFormat:#"%d\%", someDigit];
But it didn't work for me.
The code for percent sign in NSString format is %%. This is also true for NSLog() and printf() formats.
The escape code for a percent sign is "%%", so your code would look like this
[NSString stringWithFormat:#"%d%%", someDigit];
Also, all the other format specifiers can be found at Conceptual Strings Articles
If that helps in some cases, it is possible to use the unicode character:
NSLog(#"Test percentage \uFF05");
The accepted answer doesn't work for UILocalNotification. For some reason, %%%% (4 percent signs) or the unicode character '\uFF05' only work for this.
So to recap, when formatting your string you may use %%. However, if your string is part of a UILocalNotification, use %%%% or \uFF05.
seems if %% followed with a %#, the NSString will go to some strange codes
try this and this worked for me
NSString *str = [NSString stringWithFormat:#"%#%#%#", #"%%",
[textfield text], #"%%"];
uese following code.
NSString *searchText = #"Bhupi"
NSString *formatedSearchText = [NSString stringWithFormat:#"%%%#%%",searchText];
will output: %Bhupi%
iOS 9.2.1, Xcode 7.2.1, ARC enabled
You can always append the '%' by itself without any other format specifiers in the string you are appending, like so...
int test = 10;
NSString *stringTest = [NSString stringWithFormat:#"%d", test];
stringTest = [stringTest stringByAppendingString:#"%"];
NSLog(#"%#", stringTest);
For iOS7.0+
To expand the answer to other characters that might cause you conflict you may choose to use:
- (NSString *)stringByAddingPercentEncodingWithAllowedCharacters:(NSCharacterSet *)allowedCharacters
Written out step by step it looks like this:
int test = 10;
NSString *stringTest = [NSString stringWithFormat:#"%d", test];
stringTest = [[stringTest stringByAppendingString:#"%"]
stringByAddingPercentEncodingWithAllowedCharacters:
[NSCharacterSet alphanumericCharacterSet]];
stringTest = [stringTest stringByRemovingPercentEncoding];
NSLog(#"percent value of test: %#", stringTest);
Or short hand:
NSLog(#"percent value of test: %#", [[[[NSString stringWithFormat:#"%d", test]
stringByAppendingString:#"%"] stringByAddingPercentEncodingWithAllowedCharacters:
[NSCharacterSet alphanumericCharacterSet]] stringByRemovingPercentEncoding]);
Thanks to all the original contributors. Hope this helps. Cheers!