NSDictionary不区分大小写的objectForKey:

时间:2012-11-28 14:26:15

标签: objective-c ios nsdictionary key-value case-insensitive

NSDictionary有objectForKey,但它是密钥的大小写。有 功能,如

- (id)objectForKey:(id)aKey options:(id) options;

在选项中你可以传递“NSCaseInsensitiveSearch”

要从NSDictionary获取密钥,这是一个案例非常重要的,可以使用下面编写的代码。

6 个答案:

答案 0 :(得分:12)

您需要使用此功能添加NSDictionary类的类别

- (id)objectForCaseInsensitiveKey:(NSString *)key {
    NSArray *allKeys = [self allKeys];
    for (NSString *str in allKeys) {
        if ([key caseInsensitiveCompare:str] == NSOrderedSame) {
            return [self objectForKey:str];
        }
    }
    return nil;
}

答案 1 :(得分:9)

由于以下几个原因,不包括此内容:

  1. NSDictionary使用哈希等式,对于几乎任何好的哈希算法,源字符串中的任何变化都会产生不同的哈希值。

  2. 更重要的是, NSDictionary键不是字符串。符合NSCopying的任何对象都可以是字典键,并且包含的​​字符串多于字符串。 NSNumber与NSBezierPath的不区分大小写的比较是什么样的?

  3. 这里的许多答案提供的解决方案相当于将字典转换为数组并迭代它。这是有效的,如果你只需要一次性,这很好。但是这种解决方案有点难看并且具有糟糕的性能特征。如果这是我需要的东西(比如足以创建一个NSDictionary类别),我想在数据结构级别正确地解决它。

    你想要的是一个包装NSDictionary的类,它只允许键的字符串并在给出键时自动降低键(如果需要双向映射,也可能记住原始键)。这实现起来相当简单,设计更加简洁。这对于一次性而言太沉重了,但如果这是你做的很多事情,我认为值得干净利落。

答案 2 :(得分:1)

在下面的代码中,我搜索输入键的实际键。因此,如果输入键= @“naMe”,则实际键= @“name”。

NSDictionary *dic=[NSDictionary dictionaryWithObjectsAndKeys:@"John",@"Name",@"123456",@"empId", nil];


NSString *key=@"naMe";
NSString *name=[dic objectForKey:key];

if(name==nil){
    NSPredicate *searchPred=[NSPredicate predicateWithFormat:@"self LIKE[cd] %@",key];
    NSArray *searchedKeys=[[dic allKeys] filteredArrayUsingPredicate:searchPred];

    if(searchedKeys.count>0){
        name=[dic objectForKey:[searchedKeys objectAtIndex:0]];

    }
}

NSLog(@"Name = %@",name);

答案 3 :(得分:1)

正确的答案是你应该使用大小写折叠的键作为字典键。 这与将它们转换为大写或小写不同,它不会破坏O(1)平均案例搜索/插入复杂性。

不幸的是,Cocoa似乎没有合适的NSString方法来对字符串进行大小写,但Core Foundation有CFStringFold()可以用于此目的。让我们写一个简短的函数来完成必要的工作:

NSString *foldedString(NSString *s, NSLocale *locale)
{
  CFMutableStringRef ret = CFStringCreateMutableCopy(kCFAllocatorDefault, 0,
                                                     (__bridge CFStringRef)s);
  CFStringNormalize(ret, kCFStringNormalizationFormD);
  CFStringFold(ret, kCFCompareCaseInsensitive, (__bridge CFLocaleRef)locale);
  return (__bridge_transfer NSString *)ret;
}

注意 locale 参数很重要。如果指定NULL,您将获得当前系统区域设置。这在大多数情况下会没问题,但土耳其用户可能会对“我”与“我”匹配而不是“ı”感到惊讶。您可能因此希望传递[NSLocale currentLocale],如果您要保存结果,可能也希望保存区域设置标识符并从中创建区域设置。

因此,在添加到字典时,您现在需要执行

[dict setObject:obj forKey:foldedString(myKey, locale)];

再次抬头

[dict objectForKey:foldedString(myKey, locale)];

最后一个观察结果是,您可能希望将案例折叠的密钥与原始值一起存储,然后您不必在每次访问字典时都将其折叠。

答案 4 :(得分:0)

许多答案都是正确的,但这里有一个更多的例子:

    NSDictionary* dict= @{ @"hello" : @"Hey" };
    NSArray* keys= [dict allKeys];
    NSUInteger index=[keys indexOfObjectPassingTest:  ^BOOL (id obj, NSUInteger index, BOOL* stop)
     {
         if( [obj caseInsensitiveCompare: @"Hello"]==NSOrderedSame)
         {
             *stop= YES;
             return YES;
         }
         else
         {
             return NO;
         }
     }];

我个人觉得这种方法比较简单,但每个人都有自己的编程风格。

修改

不太可读但更短的解决方案:

    NSDictionary* dict= @{ @"hello" : @"Hey" };
    NSArray* keys= [dict allKeys];
    NSUInteger index=[keys indexOfObjectPassingTest:  ^BOOL (id obj, NSUInteger index, BOOL* stop)
     {
         return *stop= [obj caseInsensitiveCompare: @"Hello"]==NSOrderedSame ;

     }];

答案 5 :(得分:0)

如果您只在一个地方(可能是两个或三个)存储和检索NSDictionary,您可以使用

  

[myString lowercaseString]

两者都有。如果在整个代码中使用字典对象,则更严格的答案很有用。