NSMutableString *pinyin = [[NSMutableString alloc] initWithString:#"你好"];
if (CFStringTransform((__bridge CFMutableStringRef)pinyin, 0, kCFStringTransformMandarinLatin, NO)) {
NSLog(#"%#", pinyin);
// nǐ hǎo
}
if (CFStringTransform((__bridge CFMutableStringRef)pinyin, 0, kCFStringTransformStripDiacritics, NO)) {
NSLog(#"%#", pinyin);
// ni hao
}
From the first if statement above code, I can get the pinyin with the phonetic alphabet.The second if statement, I can get the pinyin which don't carry phonetic alphabet(like ni hao).
But the problem is that I want is phonetic. For example, 'hǎo' represents a third tone in pinyin. And the third tone is what I need.
I use Google to search for a long time, but did not find a correlation method.
Please let me know if any open source or method or other already present for this.
Thanks in advance.
Maybe this can help you :PinYin4Objc.
You can set the format ToneType like this [format setToneType:ToneTypeWithToneNumber], and you'll get the result "ni3 hao3"
Related
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 an iOS app that receives data from the PARSE.COM.
How did not know nothing about 'parse.com' , I used the tutorial "http://www.raywenderlich.com/15916/how-to-synchronize-core-data-with-a-web-service-part-1".
The synchronization occurs only from the server to the device (iOS), and one time the object is added to the device, it should not be inserted again.
Turns out I got 131 objects in a class and 145 in another, but the Parse.com always returns me the first 100 items, even those already are in the device (iOS).
The worst thing is that in my code I have a variable "limit" in "request" that should work, but does not work for me.
I need your help, please ...
Code:
- (NSMutableURLRequest *)GETRequestForAllRecordsOfClass:(NSString *)className updatedAfterDate:(NSDate *)updatedDate
{
NSMutableURLRequest *request = nil;
NSDictionary *paramters = nil;
if (updatedDate) {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.'999Z'"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"GMT"]];
NSString *jsonString = [NSString
stringWithFormat:#"{\"updatedAt\":{\"$gte\":{\"__type\":\"Date\",\"iso\":\"%#\"}}}",
[dateFormatter stringFromDate:updatedDate]];
//That's line of 'paramters' is from original tutorial Raywenderlich
// paramters = [NSDictionary dictionaryWithObject:jsonString forKey:#"where"];
//This line was add for the autors of tutorial in a comment from your blog, and he say that has work, but not for me =(
paramters = #{#"where" : jsonString, #"limit" : #(1000)};
}
request = [self GETRequestForClass:className parameters:paramters];
return request;
}
The print of variable "request" after this method is this:
URL: https://api.parse.com/1/classes/Substancia?where=%7B%22updatedAt%22%3A%7B%22%24gte%22%3A%7B%22__type%22%3A%22Date%22%2C%22iso%22%3A%222014-09-23T02%3A13%3A01.999Z%22%7D%7D%7D&limit=1000
Why do same having the variable "LIMIT = 1000", the parse.com every returns me 100 items?
And even that returns 100 items, why do in the next time he does the "request" he it does not catch the next 100 since the other 100 registers earlier have already been entered?
Can anyone help me?
(Answering here since I don't have enough reputation to comment.)
For the limit=1000 not seeming to work: perhaps the "where" clause (i.e. constraining to items with updatedAt value >= 2014-09-23T02:13:01.999Z) is limiting results to less than 1000?
(To Ian's point) There is a 'skip' parameter that tells the API how many items to skip ahead, for pagination. i.e. limit=100&skip=100 to see page 2.
I'm not sure, but I think this is what you're looking for. A great solution on how to retrieve all the objects from Parse instead of the max limit i.e. 1000.
i am implementing speech to text by OpenEars feature in my app.
i am also using Rejecto plugin to make the recognition better and RapidEars for faster results. the goal is to detect phrase and single words, for example :
lmGenerator = [[LanguageModelGenerator alloc] init];
NSArray *words = [NSArray arrayWithObjects:#"REBETANDEAL",#"NEWBET",#"REEEBET", nil];
NSString *name = #"NameIWantForMyLanguageModelFiles";
NSError *err = [lmGenerator generateRejectingLanguageModelFromArray:words
withFilesNamed:name
withOptionalExclusions:nil
usingVowelsOnly:FALSE
withWeight:nil
forAcousticModelAtPath:[AcousticModel pathToModel:#"AcousticModelEnglish"]]; // Change "AcousticModelEnglish" to "AcousticModelSpanish" to create a Spanish Rejecto model.
// Change "AcousticModelEnglish" to "AcousticModelSpanish" to create a Spanish language model instead of an English one.
NSDictionary *languageGeneratorResults = nil;
NSString *lmPath = nil;
NSString *dicPath = nil;
if([err code] == noErr) {
languageGeneratorResults = [err userInfo];
lmPath = [languageGeneratorResults objectForKey:#"LMPath"];
dicPath = [languageGeneratorResults objectForKey:#"DictionaryPath"];
} else {
NSLog(#"Error: %#",[err localizedDescription]);
}
// Change "AcousticModelEnglish" to "AcousticModelSpanish" to perform Spanish recognition instead of English.
[self.pocketsphinxController setRapidEarsToVerbose:FALSE]; // This defaults to FALSE but will give a lot of debug readout if set TRUE
[self.pocketsphinxController setRapidEarsAccuracy:10]; // This defaults to 20, maximum accuracy, but can be set as low as 1 to save CPU
[self.pocketsphinxController setFinalizeHypothesis:TRUE]; // This defaults to TRUE and will return a final hypothesis, but can be turned off to save a little CPU and will then return no final hypothesis; only partial "live" hypotheses.
[self.pocketsphinxController setFasterPartials:TRUE]; // This will give faster rapid recognition with less accuracy. This is what you want in most cases since more accuracy for partial hypotheses will have a delay.
[self.pocketsphinxController setFasterFinals:FALSE]; // This will give an accurate final recognition. You can have earlier final recognitions with less accuracy as well by setting this to TRUE.
[self.pocketsphinxController startRealtimeListeningWithLanguageModelAtPath:lmPath dictionaryAtPath:dicPath acousticModelAtPath:[AcousticModel pathToModel:#"AcousticModelEnglish"]]; // Starts the rapid recognition loop. Change "AcousticModelEnglish" to "AcousticModelSpanish" in order to perform Spanish language recognition.
[self.openEarsEventsObserver setDelegate:self];
most of the time the result is fine, but sometime it makes a mix from separate strings objects. for example i pass the words array : #[#"ME AND YOU",#"YOU",#"ME"] and the output can be : "YOU ME ME ME AND". i dont want it to recognize only part of a phrase.
any ideas please?
On the pocketsphinxDidReceiveHypothesis:(NSString *)hypothesis recognitionScore:(NSString *)recognitionScore utteranceID:(NSString *)utteranceID you can check if the hypothesis is in your words array before showing it.
- (void) pocketsphinxDidReceiveHypothesis:(NSString *)hypothesis recognitionScore:(NSString *)recognitionScore utteranceID:(NSString *)utteranceID {
if ([words containsObject:hypothesis]) {
//show hypothesis
}
}
OpenEars developer here. To detect fixed phrases using OpenEars, use the new dynamic grammar generator method of LanguageModelGenerator to create a rules-based grammar dynamically rather than a statistical language model: http://www.politepix.com/2014/04/10/openears-1-7-introducing-dynamic-grammar-generation/
My App sends html to a Arduino with an Ethernet Shield. The Ethernet shield acts as a webserver and sends a simple message back to a UIWebview in the App. I'm using
NSString *myText = [myWebView2 stringByEvaluatingJavaScriptFromString:#"document.body.innerHTML"];
If I ask NSLog to print my "myText" It prints out
<h2>Relay1 ON</h2>
Which is what is sent to the webview. Now if I try to Compare myText with a static string that matches exactly, I get no result.
Heres the entire code block.
- (void)webViewDidFinishLoad:(UIWebView *)myWebView2;
{
NSString *myText = [myWebView2
stringByEvaluatingJavaScriptFromString:#"document.body.innerHTML"];
NSLog(#"my Text=%#",myText);
if ([myText isEqualToString:#"<h2>Relay1 ON</h2>"]) {
NSLog (#"If statement was triggered");
}
}
If I look at the value of myText in NSLog it exactly matches yet the if statement is never triggered.
What am I missing in that if statement?
Thanks!!
Not Really Solved but I used NSRange to search myText for "Relay1 ON" and that works more efficiently than dealing with hidden Characters. Thanks so Much for your help.