Trim whitespace in between characters - objective-c

i just updated to ios 7 sdk, and I would like to trim/replace the whitespace between characters of a string whereby the numbers are taken out from ABAddressBook.
I have tried using the replace " " with "" code below, but this code doesnt seems to work in ios7 sdk, it works fine in ios 6 sdk by the way.
NSString *TrimmedNumberField = [self.numberField.text
stringByReplacingOccurrencesOfString:#" " withString:#""];
is there any other way I could do it in IOS 7?
EDIT:
It's a phone number type that I'm trying.
Input: "+65 12 345 6789"
The output i got from NSLog is " 12 345 6789"
I realized that when I added into NSDictionary and view it in NSLog, it appears that it contains a unix code representation of \u00a0 which is similar to the "dot in the middle" which is not equals to a fullstop.
thanks in advance.

Found the answer from here
phoneNumber = [phoneNumber stringByReplacingOccurencesOfString:#"." withString:#""];
// where #"." was created by typing Option+ Spacebar
The number is extracted from ABAddressbook.

You can loop over the string and remove whitespace as long as there is any
NSString *someString = #"A string with multiple spaces and other whitespace.";
NSMutableString *mutableCopy = [someString mutableCopy];
// get first occurance of whitespace
NSRange range = [mutableCopy rangeOfCharacterFromSet:[NSCharacterSet whitespaceCharacterSet]];
// If there is a match for the whitespace ...
while (range.location != NSNotFound) {
// ... delete it
[mutableCopy deleteCharactersInRange:range];
// and get the next whitespace
range = [mutableCopy rangeOfCharacterFromSet:[NSCharacterSet whitespaceCharacterSet]];
}
// no more whitespace. You can get back to an immutable string
someString = [mutableCopy copy];
The result with the string above is Astringwithmultiplespacesandotherwhitespace.

Try This:
NSString *str = #" untrimmed string ";
NSString *trimmed = [str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

Try This
[yourString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
whitespaceCharacterSet Apple Documentation for iOS says
Returns an NSData object encoding the receiver in binary format.
(NSData *)bitmapRepresentation
Return Value
An NSData object encoding the receiver in binary format.
Discussion
This format is suitable for saving to a file or otherwise transmitting or archiving.
A raw bitmap representation of a character set is a byte array of 2^16 bits (that is, 8192 bytes). The value of the bit at position n represents the presence in the character set of the character with decimal Unicode value n. To test for the presence of a character with decimal Unicode value n in a raw bitmap representation, use an expression such as the following:
So Try This
NSString *testString = #" Eek! There are leading and trailing spaces ";
NSString *trimmedString = [testString stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];

Related

Trimmed string change it's length only by half

Could anyone give some advise please.
In my iOS app I am parsing XML (with a help of third-party-library) and have a problem with extra whitespaces/newLines at the beginning/end of the strings. Initial string, that return this third-party-library, it's a C++ std::wstring that I convert to NSString (the encoding should be right as the content of new NSString is equal to proper part of my XML-file). After the trim length of "empty" elements (that contain only whitespaces and new lines) doesn't become zero but change it's value by half.
The code is below....
std::wstring val;
NSString *initial = [[NSString alloc] initWithBytes:val.data() length:sizeof (wchar_t)*val.size() encoding:NSUTF16LittleEndianStringEncoding];
NSString *trimmed = [initial stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
If try to output like NSLog(#"bybyby'%#'bebebe", trimmed); 'bebebe have never displayed. Looks like that there are left some new lines, whitespaces that can't be detected.
wchar_t is a 32-bit integer (on iOS and OS X), therefore you must use NSUTF32LittleEndianStringEncoding for the conversion to NSString.
Example:
std::wstring val (L" Hello World ");
NSString *initial = [[NSString alloc] initWithBytes:val.data() length:sizeof (wchar_t)*val.size() encoding:NSUTF32LittleEndianStringEncoding];
NSString *trimmed = [initial stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSLog(#"'%#'", trimmed);
// Output: 'Hello World'
What probably happened in your case (with NSUTF16LittleEndianStringEncoding)
is that every second character in the initial string is a NUL character,
which acts as a terminator when printed.

line break at starting of UILabel text

I have string to display in UILabel, but the UILabel isn't displaying the text of the below string.
string is : " \n \n If you are using a corticosteroid medication"
I know \n at the start isn't logical but I am getting it from server and hence I can not change it. So is there any way to resolve this issue.
Any way that label displays rest text by adding two line break at start or how can I truncate \n if it is in the beginning of string.
Thanks.
Did you try this?
[yourString stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
If you are wanting to remove \n from your string you could just use something as simple as
NSString *myString = #" \n \n If you are using a corticosteroid medication";
myString = [[myString stringByReplacingOccurrencesOfString:#"\n"
withString:#""];
stringByReplacingOccurencesOFString: withString: will replace all occurrences of the given string (In your case \n) with the given string.
The above should technically do the exact same as [myString stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
If you want to replace only within a specific range then you could use stringByReplacingOccurrencesOfString:withString:options:range: instead like:
myString = [myString replaceOccurencesOfString:#"\n"
withString:#""
options:NULL
range:NSMakeRange(0, 7)];
This will remove all occurrences of \n within the given range, for this example from 0 - 7
Check out he Apple documentation for this here
Try this
NSString *text = #" \n \n If you are using a corticosteroid medication";
text = [text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

How to replace occurrence of \xa0 character in NSString

I have already looked at this question but there was no solution.
Here is the problem.
po [myNumberFormatter stringFromNumber:myNumber]
Output--> (id) $4 = 1.500,00
p (char) [(NSString *)[myNumberFormatter stringFromNumber:myNumber] characterAtIndex:1]
Output--> (char) $5 = '\xa0'
po [(NSString *)[myNumberFormatter stringFromNumber:myNumber] stringByReplacingOccurrencesOfString:#"\xa0" withString:#" "]
Output--> (id) $6 = 1.500,00
One thing to note though is that on the screen, the value 1.500,00 looks like 1 500,00.
But is there any way to convert the '\xa0' character to a #" " within the string?
This following solution already works, but it has the problem of converting everything not included into a blank character.
po [(NSString *)[myNumberFormatter stringFromNumber:myNumber] stringByReplacingSequenceOfCharactersInSet:(NSCharacterSet *)[[NSCharacterSet characterSetWithCharactersInString:#"0123456789,."] invertedSet] with:#" "]
Edit --------------
I've tried the answer below and i thought it was wrong becuase
po [(NSString *)[numberFormatter stringFromNumber:theNumber] stringByReplacingOccurrencesOfString:#"\u00a0" withString:#" "]
still produced the same result (the \xa0 char was still not removed). But when I did not place it in the debugger, but instead placed it in a NSString within the code, the correct answer was stored and the \xa0 character was removed. Guess I should not depend on debugger log alone.
NSString *str = // string to cleanup
str = [str stringByReplacingOccurrencesOfString:#"\u00a0" withString:#" "];
The \u00a0 will get replaced at compile time with an actual no-break space.
In my opinion replacing "\u00a0" is not a generic solution because there are chances that nect time server may send any other unicode character then the code will not be able to handle that. Also "\u00a0" isnot a string its a character.PFB the code that i used to filter out only digits from server response that was:
phoneNumber= "000 \U00a0950";
Since i just wanted numbers in phoneNumber i wrote:
self.phoneNumber = [NSMutableString stringWithCapacity:[[_storeDetails objectForKey "phone"] length]]; //which is 000 \U00a0950
NSCharacterSet *numberCharacterSet = [NSCharacterSet decimalDigitCharacterSet];
for (int i = 0; i < [[_storeDetails objectForKey "phone"] length]; i++)
{
unichar characterOfPhoneNumber = [[_store objectForKey "phone"] characterAtIndex:i];
if ([numberCharacterSet characterIsMember:characterOfPhoneNumber])
{ [self.phoneNumber appendString:[NSString stringWithFormat "%c",characterOfPhoneNumber]];
}
}
//in the above code i parsed each character and checked if that was a number, added that in an array and hence the array is unicode free.
PS:\U00a0 is a character

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.

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!