簡體   English   中英

NSDictionary不區分大小寫的objectForKey:

[英]NSDictionary case insensitive objectForKey:

NSDictionary有objectForKey,但它是密鑰的大小寫。 沒有可用的功能

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

您可以在選項中傳遞“NSCaseInsensitiveSearch”

要從NSDictionary獲取密鑰,這是一個案例中的一個,可以使用下面編寫的代碼。

您需要使用此功能添加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. NSDictionary使用哈希等式,對於幾乎任何好的哈希算法,源字符串中的任何變化都會產生不同的哈希值。

  2. 更重要的是, NSDictionary鍵不是字符串 符合NSCopying的任何對象都可以是字典鍵,並且包含的​​字符串多於字符串。 NSNumber與NSBezierPath的不區分大小寫的比較是什么樣的?

這里的許多答案提供的解決方案相當於將字典轉換為數組並迭代它。 這是有效的,如果你只需要一次性,這很好。 但是這種解決方案有點難看並且具有糟糕的性能特征。 如果這是我需要的東西(比如足以創建一個NSDictionary類別),我想在數據結構級別正確地解決它。

你想要的是一個包裝NSDictionary的類,它只允許鍵的字符串,並在給出鍵時自動降低鍵(如果你需要雙向映射,也可能還記住原始鍵)。 這實現起來相當簡單,設計更加簡潔。 這對於一次性來說太沉重了,但是如果這是你做了很多事情,我認為值得干凈利落。

在下面編寫的代碼中,我搜索輸入鍵的實際鍵。 因此,如果輸入鍵= @“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);

正確的答案是你應該使用大小寫折疊的鍵作為字典鍵。 這與將它們轉換為大寫或小寫不同,並且它不會破壞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)];

最后一個觀察結果是,您可能希望將案例折疊的密鑰與原始值一起存儲,然后您不必在每次訪問字典時折疊它們。

許多答案都是正確的,但這里有一個更多的例子:

    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 ;

     }];

如果您只在一個地方(可能是兩個或三個)存儲和檢索NSDictionary,您可以使用

[myString lowercaseString]

同時。 如果在您的代碼中使用字典對象,則更嚴格的答案非常有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM