【问题标题】:NSString : easy way to remove UTF-8 accents from a string?NSString:从字符串中删除 UTF-8 重音的简单方法?
【发布时间】: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


    【解决方案1】:
    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];
    

    【讨论】:

    • 谢谢,但是当我转换 UTF-8 字符时,例如 à 不会变成 a 而是 ? .
    • 已编辑帖子 - 抱歉,我使用了错误的编码类型。我使用 ASCII 编码的版本在 Xcode 中工作 - 也许使用正确的编码对你有用。
    • 这似乎假设字符串可以转换为 ASCII 而不会丢失信息(重音除外)。它可能适用于该示例,但远不能保证在使用其他字符集中的语言时也能正常工作。
    • @vomako 您要转换为数据的字符串可能为 nil - 该代码在 iOS 8 下运行良好。
    • @vomako 如果你不能解决问题(使用谷歌和这个网站!),那么我建议在这里提出一个新问题,并链接到这个问题和你的 cmets 以供参考。跨度>
    【解决方案2】:

    Matt Thompson 在NSHipsterWWDC 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 中的很多人都说这应该是公认的答案,因此我想对这种方法提出警告。这种方法非常慢,如果需要转换大量的字符串/数据,应该小心使用

    【讨论】:

    • 这个问题是我发现的第二个问题,它具有转换为 NSData 并返回为可接受的答案的“技巧”。您的答案应该是被接受的答案,它甚至胜过[input stringByFoldingWithOptions:NSDiacriticInsensitiveSearch locale:[NSLocale currentLocale]];,因为它不需要语言环境。
    • 谢谢,原来 Core Foundation 中有很多很酷的东西被忽略了
    • 应该是认可的答案,感谢您提供指向 Mattt Thompson 页面的链接。
    • 我同意 - 这是一个更可靠的答案。
    • 还要注意,字符串必须是NSMutableString,而不是NSString*
    【解决方案3】:

    你试过了吗

    [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);
    

    【讨论】:

    • 查看更改后的解决方案答案,无需中间 NSData 转换和 UTF-8 编码丢失。
    • @Regexident 我试过了,但没用我在 CFStringTransform(stringRef, NULL, kCFStringTransformToLatin, NO);这一行……​​
    【解决方案4】:

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

    【讨论】:

    • 出色的答案,很高兴看到更多 Swift 变体。
    【解决方案5】:

    这里是在 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

    【讨论】:

    • 感谢您回答我关于两种方法性能比较的问题!
    【解决方案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
    

    【讨论】:

      【解决方案7】:

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

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

      【讨论】:

        【解决方案8】:

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

        let stripAccentAndDiacritics: (String) -> String = {
            var mStringRef = NSMutableString(string: $0) as CFMutableStringRef
            CFStringTransform(mStringRef, nil, kCFStringTransformStripCombiningMarks, Boolean(0))
            return String(mStringRef)
        }
        

        【讨论】:

          猜你喜欢
          • 2013-02-17
          • 1970-01-01
          • 1970-01-01
          • 2013-12-22
          • 2018-01-05
          • 2021-08-13
          • 2018-01-23
          • 1970-01-01
          • 2014-02-12
          相关资源
          最近更新 更多