46

我想换一个句子,例如:

Être ou ne pas être。C'était là-bas。

会成为:

Etre ou ne pas etre。C'etait la-bas。

有没有简单的方法可以用 NSString 做到这一点?还是我必须通过检查每个字符自行开发?

4

8 回答 8

59
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];
于 2012-06-07T13:12:36.087 回答
48

Mattt Thompson 在NSHipsterWWDC 2013 session 228中再次介绍了这一点

TL;博士

NSMutableString *str = [@"Être ou ne pas être. C'était là-bas." mutableCopy];
CFStringTransform((__bridge CFMutableStringRef)string, NULL, kCFStringTransformStripCombiningMarks, NO);

应该做的伎俩,它对我很有用。

警告 由于评论中的很多人说这应该是公认的答案,因此我想对这种方法提出警告。这种方法非常慢,如果需要转换大量的字符串/数据,应该小心使用

于 2013-08-19T18:43:28.920 回答
27

你有没有尝试过

[string stringByFoldingWithOptions:NSDiacriticInsensitiveSearch locale:[NSLocale currentLocale]]

或者

Boolean CFStringTransform (
   CFMutableStringRef string,
   CFRange *range,
   CFStringRef transform,
   Boolean reverse
);

?

CFStringTransform &转换标识符

NSMutableString *string = ...;
CFMutableStringRef stringRef = (__bridge CFMutableStringRef)string;
CFStringTransform(stringRef, NULL, kCFStringTransformToLatin, NO);
NSLog(@"%@", string);
于 2012-06-07T13:09:27.670 回答
16

只是一个更新说它可以像这样在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。”

于 2015-01-25T22:02:32.533 回答
9

这是在 iPhone 6 iOS 9.0 模拟器上使用 Swift 2.0 的性能测试,在解决方案之间使用:

  • CFStringTransform(任务 1)
  • stringByFoldingWithOptions(任务 2)

任务 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

于 2015-09-25T13:00:50.840 回答
6

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
于 2017-04-13T11:23:45.467 回答
3

这是完整的代码。使用函数 stringbyfoldignWithOptions。

NSString *str1=@"Être ou ne pas être C'était là-bas"; NSString *str2=[str1 stringByFoldingWithOptions:NSDiacriticInsensitiveSearch locale:[NSLocale systemLocale]]; NSLog(@"%@",str2);

于 2016-06-23T07:02:27.570 回答
1

对于那些想要 CFStringTransform 解决方案的 Swift 版本的人:

let stripAccentAndDiacritics: (String) -> String = {
    var mStringRef = NSMutableString(string: $0) as CFMutableStringRef
    CFStringTransform(mStringRef, nil, kCFStringTransformStripCombiningMarks, Boolean(0))
    return String(mStringRef)
}
于 2015-05-06T09:11:37.333 回答