This question already has answers here:
Remove white space from contact number fetched from phone book
(2 answers)
Closed 6 years ago.
In my app I am trying to retrieve the list of contact's number and try to do operations on them. I realized that whenever I have added new contacts (after updating to iOS 7) the new contacts formatting has changed, as there are spacings in the newly added numbers.
Using the ordinary replace methods does not remove the spaces.
Are these really spaces or what are these ? my objective is to get back the 'space' free number.
for example, if the number is 1 818 323 323 323, I want to get 1818323323323
I looked at this as not getting rid of 'spaces' but being left with only decimal characters. This code did that for me:
phoneNumberString = [[phoneNumberString componentsSeparatedByCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]] componentsJoinedByString:#""];
This takes out everything that's not a number 0-9.
Swift 4.1:
phoneNumberString = phoneNumberString.components(separatedBy: CharacterSet.decimalDigits.inverted).joined(separator: "")
Try this:
NSString *cleaned = [[phoneNr componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] componentsJoinedByString:#""];
This should work for any kind of space (of which there are many). It may seem somewhat inefficient, but for phone numbers, this should be ok.
Some iOS7 phone numbers are encoded with non-breaking space. Try this:
NSString* stringFormatted = [phoneNumber stringByReplacingOccurrencesOfString:#"\u00a0" withString:#""];
After way too much string cleaning I finally found an answer after printing the CFStringRef straight from the Address Book. Here's what's going on behind the scenes...
Add a contact in iOS7 and Apple stores this: (555).555-5555 (where . is actually U00A0 or  )
My app copies a contact's info in a CFStringRef from AddressBook (when NSLogged the . shows)
CFStringRef is cast into NSString (NSLog now shows 555\U00a0555-5555)
To remove the \U00A0 I tried 3 answers from this thread and [NSCharacterSet characterSetWithRange:(160,1)] which didn't work. What finally worked was this line of code:
phoneNumber = [phoneNumber stringByReplacingOccurrencesOfString:#"." withString:#""];
// where #"." was created by typing Option+Spacebar
Another (very flexible) option is to use a regular expression. This allows you to retain the + or any other characters you want to remain.
let numberFromAddressBook = "+1 818 323 323 323"
let cleanNumber = numberFromAddressBook.stringByReplacingOccurrencesOfString("[^0-9+]", withString: "", options: NSStringCompareOptions.RegularExpressionSearch, range:nil)
"+1818323323323"
The cleanest solution I'm using in my apps is:
NSMutableCharacterSet *phoneNubmerCharacterSet = [NSMutableCharacterSet characterSetWithCharactersInString:#"+"];
[phoneNubmerCharacterSet formUnionWithCharacterSet:[NSCharacterSet decimalDigitCharacterSet]];
NSString* phoneString = [[phoneString componentsSeparatedByCharactersInSet:[phoneNubmerCharacterSet invertedSet]] componentsJoinedByString:#""];
No "if" logic, keeps the + in number, removes all kind of random unwanted characters
I made a small adjustment to the poster's answer in case someone wants to maintain the + at the begining of the number.
I made this small adjustment if you want to keep the plus after removing the spaces.
Boolean shouldAddPlus = NO;
if([[phoneNumber substringToIndex:1] isEqualToString:#"+"])
{
shouldAddPlus = YES;
}
phoneNumber = [[phoneNumber componentsSeparatedByCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]] componentsJoinedByString:#""];
if(shouldAddPlus)
phoneNumber = [base stringByAppendingString:phoneNumber];
The correct solution is to replace the occurences with a valid space
NSString *clean = [dirty stringByReplacingOccurrencesOfString:#"\u00a0" withString:#" "];
So you dont loose the space and the user sees what sees in other apps.
Related
The following code runs fine on iOS 8 but when run on iOS 9.0.2 I get some odd results:
NSString * input = #"Hi there";
NSData * data = [input dataUsingEncoding:NSASCIIStringEncoding];
Byte *byteData = (Byte*)malloc(data.length);
memcpy(byteData, [data bytes], data.length);
NSString * result = [NSString stringWithCString:(const char*)byteData encoding:NSASCIIStringEncoding];
NSLog(#"Result: %#", result);
iOS 8.4 (iPhone 6 Plus) byteData is Hi there
iOS 9.0.2 (iPhone 6S) byteData is Hi there\xb6<M\x13
On iOS 9 I end up with a load of garbage at the end of the string.
This feels like a 32 bit vs 64 bit issue as it looks like on iOS 9 the byteData length is twice as long?
Apple have their table of 32 to 64 bit changes here:
https://developer.apple.com/library/ios/documentation/General/Conceptual/CocoaTouch64BitGuide/Major64-BitChanges/Major64-BitChanges.html
data.length is an unsigned long long. Could this be returning different lengths when malloc is called? The code above returns 8 for data.length when run on each version of iOS.
This just feels quite odd and I've run out of angles to attack it from. Hopefully someone out there might be able to shed some light on this one.
Thanks!
Update
I can fix it using
NSString * result = [[NSString alloc] initWithBytes:byteData length:data.length encoding:NSASCIIStringEncoding];
but I'd still like to know why I get a different result on the two iOS versions with
NSString * result = [NSString stringWithCString:(const char*)byteData encoding:NSASCIIStringEncoding];
A “C string” ends with a NUL byte. Since you created data using dataUsingEncoding:, data does not contain a C string.
Since stringWithCString:encoding: is reading outside of valid memory (looking for the NUL terminator), the behavior is undefined and thus allowed to changed at any time.
Use cStringUsingEncoding: to create data and you'll get the NUL terminator you need.
We have code like the following to retrieved the user language preference:
NSString *language = [[NSLocale preferredLanguages] firstObject];
Before iOS 8.4, language is "zh-Hans", "de", "ru", "ja" and etc. But since iOS 9, I notice that there is additional three characters "-US" appended to language. For example, "zh-Hans" becomes "zh-Hans-US"
I can find any documentation about this change. I assume that I could do something like the following to workaround this issue.
NSRange range = [language rangeOfString:#"-US"];
if (range.location!=NSNotFound && language.length==range.location+3) {
// If the last 3 chars are "-US", remove it
language = [language substringToIndex:range.location];
}
However, I am not sure whether it is safe to do so. It seems that "-US" is the location where the user is using the app? But this doesn't really make sense because we are in Canada. Has any body from other part of the world tried this?
Apple has started adding regions onto the language locales in iOS 9. Per Apple's docs, it has a fallback mechanism now if no region is specified. If you need to only support some languages, here is how I worked around it, per Apple's docs suggestion:
NSArray<NSString *> *availableLanguages = #[#"en", #"es", #"de", #"ru", #"zh-Hans", #"ja", #"pt"];
self.currentLanguage = [[[NSBundle preferredLocalizationsFromArray:availableLanguages] firstObject] mutableCopy];
This will automatically assign one of the languages in the array based off the User's language settings without having to worry about regions.
Source: Technical Note TN2418
To extract the region I think this is a better solution:
// Format is Lang - Region
NSString *fullString = [[NSLocale preferredLanguages] firstObject];
NSMutableArray *langAndRegion = [NSMutableArray arrayWithArray:[fullString componentsSeparatedByString:#"-"]];
// Region is the last item
NSString *region = [langAndRegion objectAtIndex:langAndRegion.count - 1];
// We remove region
[langAndRegion removeLastObject];
// We recreate array with the lang
NSString *lang = [langAndRegion componentsJoinedByString:#"-"];
Swift 5: Remove region from preferred language
Using Locale.preferredLanguages.first gives you the preferred App language (which can be different than device language for the user).
In order to support the script code and language code (but to remove the region code) I think it is best to create a locale given the preferred language and grab the information we need from there.
if let pref = Locale.preferredLanguages.first {
let locale = Locale(identifier: pref)
let code = [locale.languageCode, locale.scriptCode].compactMap{$0}.joined(separator: "-")
print(code)
}
So first we get the preferred app language, Then create a locale from the language.
To get the language code we create an array with locale.languageCode and the locale.scriptCode (which may be nil), remove any nil values with compactMap and then join the values with a "-".
This should allow support for Simplified Chinese and Traditional, and let Apple handle the region instead of assuming it will always be there.
the text that caused the crash is the following:
the error occurred at the following line:
let size = CGSize(width: 250, height: DBL_MAX)
let font = UIFont.systemFontOfSize(16.0)
let attributes = [
NSFontAttributeName:font ,
NSParagraphStyleAttributeName: paraStyle
]
var rect = text.boundingRectWithSize(size, options:.UsesLineFragmentOrigin, attributes: attributes, context: nil)
where text variable contains the inputted string
parastyle is declared as follows:
let paraStyle = NSMutableParagraphStyle()
paraStyle.lineBreakMode = NSLineBreakMode.ByWordWrapping
My initial idea is that the system font can't handle these characters and I need to do an NSCharacterSet, but I'm not sure how to either just ban characters that'll crash my app or make it so i can handle this input (ideal). I don't want to ban emojis/emoticons either.
Thanks!
Not an answer but some information and that possibly provids a way code way to avoid it.
Updated to information from The Register:
The problem isn’t with the Arabic characters themselves, but in how the unicode representing them is processed by CoreText, which is a library of software routines to help apps display text on screens.
The bug causes CoreText to access memory that is invalid, which forces the operating system to kill off the currently running program: which could be your text message app, your terminal, or in the case of the notification screen, a core part of the OS.
From Reddit but this may not be completely correct:
It only works when the message has to be abbreviated with ‘…’. This is usually on the lock screen and main menu of Messages.app.
The words effective and power can be anything as long as they’re on two different lines, which forces the Arabic text farther down the message where some of the letters will be replaced with ‘…’
The crash happens when the first dot replaces part of one of the Arabic characters (they require more than one byte to store) Normally there are safety checks to make sure half characters aren’t stored, but this replacement bypasses those checks for whatever reason.
My solution is the next category:
static NSString *const CRASH_STRING = #"\u0963h \u0963 \u0963";
#implementation NSString (CONEffectivePower)
- (BOOL)isDangerousStringForCurrentOS
{
if (IS_IOS_7_OR_LESS || IS_IOS_8_4_OR_HIGHER) {
return NO;
}
return [self containsEffectivePowerText];
}
- (BOOL)containsEffectivePowerText
{
return [self containsString:CRASH_STRING];
}
#end
Filter all characters to have same directionality. Unfortunately, I'm only aware of such API in Java.
Don't even try. This is a bug in the operating system that will be fixed. It's not your problem. If you try to fix it, you are just wasting your time. And you are very likely to introduce bugs - when you say you "sanitise" input that means you cannot handle some perfectly fine input.
The company I work at develops a multiplatform group video chat.
In Crashlytics report we started noticing that some users are "effectively" trolling iOS users using this famous unicode sequence.
We can't just sit and wait for Apple to fix this bug.
So, I've worked on this problem, this is the shortest crashing sequence I got:
// unichar representation
unichar crashChars[8] = {1585, 1611, 32, 2403, 32, 2403, 32, 2403};
// string representation
NSString *crashString = #"\u0631\u064b \u0963 \u0963 \u0963"
So, I decided to filter out all text messages that contains two U+0963 'ॣ' symbols with one symbol between them (hope you are able to decipher this phrase)
My code from NSString+Extensions category.
static const unichar kDangerousSymbol = 2403;
- (BOOL)isDangerousUnicode {
NSUInteger distance = 0;
NSUInteger charactersFound = 0;
for (NSUInteger i = 0; i < self.length; i++) {
unichar character = [self characterAtIndex:i];
if (charactersFound) {
distance++;
}
if (distance > 2) {
charactersFound = 0;
}
if (kDangerousSymbol == character) {
charactersFound++;
}
if (charactersFound > 1 && distance > 0) {
return YES;
}
}
return NO;
}
Lousy Specta test:
SpecBegin(NSStringExtensions)
describe(#"NSString+Extensions", ^{
//....
it(#"should detect dangerous Unicode sequences", ^{
expect([#"\u0963 \u0963" isDangerousUnicode]).to.beTruthy();
expect([#"\u0631\u064b \u0963 \u0963 \u0963" isDangerousUnicode]).to.beTruthy();
expect([#"\u0631\u064b \u0963 \u0963 \u0963" isDangerousUnicode]).to.beFalsy();
});
//....
});
SpecEnd
I'm not sure if it's OK to "discriminate" messages with too many "devanagari vowel sign vocalic ll".
I'm open to corrections, suggestions, criticism :).
I would love to see a better solution to this problem.
I have a number of strings that have internet links embedded within them that worked fine until I applied NSLocalizedString to each of them for a localization in Spanish. Now the links in the strings are not recognized or operate as such in my app either for English (the base language) or Spanish.
I have been unable to determine why this is happening and haven't found any reference to this issue online. Is there some special formatting that I have to do to the URL part of my strings when using NSLocalizedString that I didn't have to when using NSString? I would greatly appreciate any help that anyone could offer with a solution to my issue?
Here is an example of one of my NSLocalizedStrings and its use in forming the contentString:
aboutContentText = NSLocalizedString(#"\"The Visitation\", by 1737, Jerónimo Ezquerra (1660-1737), http://commons.wikimedia.org/wiki/File:Jerónimo_Ezquerra_Visitation.jpg\n", #"aboutContentText-2nd Joyful Mystery");
contentString = [[NSMutableAttributedString alloc]
initWithString: aboutContentText attributes: contentAttributes2];
Don't localize the URLs, localize only the text:
NSString *preamble = NSLocalizedString(#"\"The Visitation\", by 1737, Jerónimo Ezquerra (1660-1737)", #"preamble aboutContentText-2nd Joyful Mystery");
NSString *urlString = #"http://commons.wikimedia.org/wiki/File:Jerónimo_Ezquerra_Visitation.jpg";
NSString *aboutContentText = [NSString stringWithFormat:#"%#, %#\n", preamble, urlString];
NSLog(#"aboutContentText: %#", aboutContentText);
NSLog output:
aboutContentText: "The Visitation", by 1737, Jerónimo Ezquerra (1660-1737), http://commons.wikimedia.org/wiki/File:Jerónimo_Ezquerra_Visitation.jpg
I'm copying phone number from iPhone address book to a text field. In text field it is showing as 1 (234) 567-8901. I want format it to 12345678901.
Any help?
You can use stringByReplacingOccurrencesOfString: withString: to remove characters you don't want such as #"(" with #""
EDIT: Better solution.
NSCharacterSet *charSet =[NSCharacterSet characterSetWithCharactersInString:#"()- "];
cleanedPhoneNumber = [phoneNumberString stringByTrimmingCharactersInSet:charSet];