9

NSDictionary 有 objectForKey 但它对键是区分大小写的。没有可用的功能,如

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

在选项中您可以传递“NSCaseInsensitiveSearch”的位置

要从不区分大小写的 NSDictionary 获取密钥,可以使用下面编写的以下代码。

4

6 回答 6

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;
}
于 2012-11-28T14:39:15.803 回答
10

这不包括在内有几个原因:

  1. NSDictionary 使用哈希相等,并且对于几乎任何好的哈希算法,源字符串的任何变化都会导致不同的哈希。

  2. 更重要的是,NSDictionary 键不是字符串。任何符合 NSCopying 的对象都可以是一个字典键,它包含的内容远不止字符串。NSNumber 与 NSBezierPath 的不区分大小写比较会是什么样子?

这里的许多答案都提供了相当于将字典转换为数组并对其进行迭代的解决方案。那行得通,如果您只需要一次性使用它,那很好。但是该解决方案有点丑陋并且具有不良的性能特征。如果这是我非常需要的东西(例如,足以创建一个 NSDictionary 类别),我想在数据结构级别正确解决它。

您想要的是一个包装 NSDictionary 的类,只允许字符串作为键并在给定键时自动小写键(如果您需要双向映射,还可能记住原始键)。这将是相当简单的实现,并且是一个更清洁的设计。对于一次性来说它太重了,但如果这是你经常做的事情,我认为值得干净地做。

于 2012-11-28T18:18:54.177 回答
2

正确的答案是您应该使用大小写折叠键作为字典键。 这与将它们转换为大写或小写不同,它不会破坏 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;
}

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

所以,当添加到字典时,你现在需要做

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

并再次抬头

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

最后一个观察结果是,您可能希望将大小写折叠的键与原始值一起存储,然后您不必在每次访问字典时都折叠它们。

于 2016-09-22T12:35:54.917 回答
1

在下面编写的代码中,我搜索输入键的实际键。所以,如果输入 key=@"naMe" 那么实际的 key=@"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);
于 2012-11-28T14:26:15.170 回答
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 ;

     }];
于 2012-11-28T14:47:04.393 回答
0

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

[myString 小写字符串]

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

于 2013-06-05T16:26:02.090 回答