【发布时间】:2012-06-11 13:01:13
【问题描述】:
我想换个句子,例如:
你不知道。 C'était là-bas。
会变成:
Etre ou ne pas etre。 C'etait la-bas。
有没有什么简单的方法可以用 NSString 做到这一点?还是我必须通过检查每个字符自行开发?
【问题讨论】:
标签: objective-c utf-8 nsstring
我想换个句子,例如:
你不知道。 C'était là-bas。
会变成:
Etre ou ne pas etre。 C'etait la-bas。
有没有什么简单的方法可以用 NSString 做到这一点?还是我必须通过检查每个字符自行开发?
【问题讨论】:
标签: objective-c utf-8 nsstring
NSString *str = @"Être ou ne pas être. C'était là-bas.";
NSData *data = [str dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *newStr = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSLog(@"%@", newStr);
...或尝试改用NSUTF8StringEncoding。
这里的编码类型列表:
https://developer.apple.com/documentation/foundation/nsstringencoding
只是 FTR,这是编写这个出色答案的一种方式:
yourString = [[NSString alloc]
initWithData:
[yourString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]
encoding:NSASCIIStringEncoding];
【讨论】:
Matt Thompson 在NSHipster 和WWDC 2013 session 228 中再次报道了这一点
TL;DR
NSMutableString *str = [@"Être ou ne pas être. C'était là-bas." mutableCopy];
CFStringTransform((__bridge CFMutableStringRef)string, NULL, kCFStringTransformStripCombiningMarks, NO);
应该做的伎俩,它对我很有用。
警告 由于 cmets 中的很多人都说这应该是公认的答案,因此我想对这种方法提出警告。这种方法非常慢,如果需要转换大量的字符串/数据,应该小心使用
【讨论】:
[input stringByFoldingWithOptions:NSDiacriticInsensitiveSearch locale:[NSLocale currentLocale]];,因为它不需要语言环境。
NSMutableString,而不是NSString*。
你试过了吗
[string stringByFoldingWithOptions:NSDiacriticInsensitiveSearch locale:[NSLocale currentLocale]]
或
Boolean CFStringTransform (
CFMutableStringRef string,
CFRange *range,
CFStringRef transform,
Boolean reverse
);
?
CFStringTransform & Transform Identifiers
NSMutableString *string = ...;
CFMutableStringRef stringRef = (__bridge CFMutableStringRef)string;
CFStringTransform(stringRef, NULL, kCFStringTransformToLatin, NO);
NSLog(@"%@", string);
【讨论】:
只是一个更新说它可以像这样在swift中完成:
"Être ou ne pas être. C'était là-bas.".stringByFoldingWithOptions(NSStringCompareOptions.DiacriticInsensitiveSearch, locale: NSLocale.currentLocale())
--> "Etre ou ne pas etre. C'etait la-bas."
【讨论】:
这里是在 iPhone 6 iOS 9.0 模拟器上使用 Swift 2.0 的性能测试,使用以下解决方案:
任务 2 始终更快,例如:
Task 1 took 9.49736100435257 seconds.
Task 2 took 1.96649599075317 seconds.
这里是测试:
let timer = ParkBenchTimer()
for _ in 1...1000000 {
let mStringRef = NSMutableString(string: "Être ou ne pas être. C'était là-bas.") as CFMutableStringRef
CFStringTransform(mStringRef, nil, kCFStringTransformStripCombiningMarks, false)
String(mStringRef)
}
print("Task 1 took \(timer.stop()) seconds.")
let timer2 = ParkBenchTimer()
for _ in 1...1000000 {
"Être ou ne pas être. C'était là-bas.".stringByFoldingWithOptions(NSStringCompareOptions.DiacriticInsensitiveSearch, locale: NSLocale.currentLocale())
}
print("Task 2 took \(timer2.stop()) seconds.")
Klaas 的 ParkBenchTimer:https://stackoverflow.com/a/26578191/1097106
【讨论】:
Swift 3(在游乐场测试)
//String+StripCombiningMarks.swift
extension String {
/// strip combining marks (accents or diacritics)
var stripCombiningMarks: String {
let mStringRef = NSMutableString(string: self) as CFMutableString
CFStringTransform(mStringRef, nil, kCFStringTransformStripCombiningMarks, false)
return mStringRef as String
}
}
用法:
let umlaut = "äöüÄÖÜ"
let stripped = umlaut.stripCombiningMarks //aouAOU
【讨论】:
这里是完整的代码。 使用函数 stringbyfoldignWithOptions。
NSString *str1=@"Être ou ne pas être C'était là-bas";
NSString *str2=[str1 stringByFoldingWithOptions:NSDiacriticInsensitiveSearch
locale:[NSLocale systemLocale]];
NSLog(@"%@",str2);
【讨论】:
对于那些想要 CFStringTransform 解决方案的 Swift 版本的人:
let stripAccentAndDiacritics: (String) -> String = {
var mStringRef = NSMutableString(string: $0) as CFMutableStringRef
CFStringTransform(mStringRef, nil, kCFStringTransformStripCombiningMarks, Boolean(0))
return String(mStringRef)
}
【讨论】: