NSString:从字符串中删除UTF-8重音的简单方法?

Rob*_*Rob 44 objective-c utf-8 nsstring

我想改变一个句子,例如:

pas pas pas pas re re.C'étaitlà-bas.

会成为:

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

使用NSString有什么简单的方法吗?或者我必须通过检查每个字符来自己开发它?

Luk*_*uke 58

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);
Run Code Online (Sandbox Code Playgroud)

...或尝试使用NSUTF8StringEncoding.

这里的编码类型列表:

https://developer.apple.com/documentation/foundation/nsstringencoding


只是FTR这里有一个单行方式来写这个伟大的答案:

yourString = [[NSString alloc]
  initWithData:
    [yourString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]
  encoding:NSASCIIStringEncoding];
Run Code Online (Sandbox Code Playgroud)

  • 这似乎假设字符串可以转换为ASCII而不会丢失信息(重音除外).它可能适用于该示例,但在其他字符集中使用语言时远远无法保证工作. (3认同)
  • 谢谢,但是当我转换UTF-8字符时,例如**à**不会变成**a**而******. (2认同)

tap*_*api 48

Mattt Thompson在NSHipsterWWDC 2013会议228上再次讨论了这个问题

TL; DR

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

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

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

  • 这个问题是我发现的第二个问题,它有"技巧"转换为NSData并返回为已接受的答案.你的答案应该是被接受的答案,它甚至胜过`[输入stringByFoldingWithOptions:NSDiacriticInsensitiveSearch locale:[NSLocale currentLocale]];`因为它不需要语言环境. (2认同)

Reg*_*ent 26

你有没有尝试过

[string stringByFoldingWithOptions:NSDiacriticInsensitiveSearch locale:[NSLocale currentLocale]]
Run Code Online (Sandbox Code Playgroud)

要么

Boolean CFStringTransform (
   CFMutableStringRef string,
   CFRange *range,
   CFStringRef transform,
   Boolean reverse
);
Run Code Online (Sandbox Code Playgroud)

CFStringTransform转换标识符

NSMutableString *string = ...;
CFMutableStringRef stringRef = (__bridge CFMutableStringRef)string;
CFStringTransform(stringRef, NULL, kCFStringTransformToLatin, NO);
NSLog(@"%@", string);
Run Code Online (Sandbox Code Playgroud)


val*_*alR 16

只是更新说它可以像在swift中那样完成:

"Être ou ne pas être. C'était là-bas.".stringByFoldingWithOptions(NSStringCompareOptions.DiacriticInsensitiveSearch, locale: NSLocale.currentLocale())
Run Code Online (Sandbox Code Playgroud)

- >"Etre ou ne pas etre.C'etait la-bas."


svr*_*vrs 9

这里使用Swift 2.0在iPhone 6 iOS 9.0模拟器上使用以下解决方案进行性能测试:

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

任务2始终更快,例如:

Task 1 took 9.49736100435257 seconds.
Task 2 took 1.96649599075317 seconds.
Run Code Online (Sandbox Code Playgroud)

在这里测试:

    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.")
Run Code Online (Sandbox Code Playgroud)

Klaas的ParkBenchTimer:https://stackoverflow.com/a/26578191/1097106


Pet*_*inz 5

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
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

let umlaut = "äöüÄÖÜ"
let stripped = umlaut.stripCombiningMarks //aouAOU
Run Code Online (Sandbox Code Playgroud)