【问题标题】:Case insensitive NSPredicate for strings from an array?对数组中的字符串不区分大小写的NSPredicate?
【发布时间】:2010-01-06 22:58:56
【问题描述】:

我有一种情况,我想通过用户名键从我的核心数据存储中获取对象,但我希望比较不区分大小写。我的谓词是这样的:

username IN $usernames

然后,我使用一组字符串进行变量替换,这些字符串是我要查找的用户名。它有效,但区分大小写。我想做这样的事情,我想:

username IN[c] $usernames

不幸的是,这似乎不起作用。字符串比较必须仍然以区分大小写的方式进行。 (我没有收到关于它是不受支持的查询的错误消息。)

是否有不同的方式来编写这个谓词,以便它按照我需要的方式工作,或者我只是在这里遗漏了一些明显的东西?

【问题讨论】:

  • 您是通过谓词构建器还是直接在代码中构建谓词?
  • 这是一个存储在数据模型中的 Fetch Request。

标签: cocoa core-data nspredicate


【解决方案1】:

在对 SQLite 存储执行 fetch 时,显然忽略了 IN 运算符上的 case 修饰符。 (您在问题中省略了商店类型。)

我建议针对文档提交错误,以便记录此限制/行为。

我还建议在错误报告器中提交功能请求,以便将来支持。

与此同时,您必须从数据模型中提取获取请求并以编程方式构建它。您可以构建一个复合谓词 OR 谓词,为您的每个值执行不区分大小写的相等匹配(并测试它是否满足您的性能需求。)

请注意,如果您支持 10.6 之前的操作系统目标,则不支持 == 上的大小写修饰符,在这种情况下,将需要另一个替代解决方案。

【讨论】:

  • 最后一点,当用作谓词字符串时,您的意思是 == 吗?以编程方式构建谓词时它仍然有效吗?我的目标是 10.5。
  • 在10.5上测试后,好像不行了。该死!看来我唯一的选择是构建一个类似的表达式:“用户名包含 [cd] $u AND $u 包含 [cd] 用户名”。叹息。
  • 没有。即使使用两个 CONTAINS 也不起作用,因为我的整体表达式是一堆其他谓词的 OR,而且似乎我不能有一个包含 AND 谓词的 OR 集。废话。在这一切都错了之后,我改用 LIKE[cd] 并转义 * 和 ?我的输入字符串中的字符。奇迹般有效。谓词处理中似乎有相当多的限制......
  • LIKE[c] 和转义 * 和 ?是必须在 10.5 上部署时的典型解决方案。
【解决方案2】:

您可以尝试ANY $usernames LIKE[c] username 之类的方法。我已经做了类似的事情,而不是变量替换,我只有一个像“persons.name”这样的关键路径,并且该谓词对我有用。不确定它是否与那里的变量而不是关键路径有什么不同,但值得一试。

【讨论】:

  • 不幸的是,该谓词不适用于 SQLite 存储。 (未实现的 SQL 生成。)在它确实起作用的情况下,请注意确保字符串 sin $usernames 有文字 LIKE 通配符转义。
【解决方案3】:

这是另一种解决方法,但需要您更改 MOM。

使用户名成为一个完整的实体。在用户名和其他实体之间创建反向关系。

现在对于获取请求,将实体设置为“用户名”,然后运行此谓词(假设有“名称”属性和“父”属性):

   [NSPredicate predicateWithFormat:"(name like[c] %@) && (parent == %@)", theUserName, theParentObject]

这可能有点矫枉过正,但可以让您根据需要运行搜索。

【讨论】:

    【解决方案4】:

    虽然这个问题已经有好几年了,但我只是偶然发现了同样的问题并像这样解决了它:

    NSArray  *values = @[@"FOO", @"bar" ,@"lorem"];
    NSString *predicate;
    
    predicate = @"value LIKE[cd] '";
    predicate = [predicate stringByAppendingString:
                 [values componentsJoinedByString:
                  @"' OR  value LIKE[cd] '"]];
    predicate = [predicate stringByAppendingString:@"'"];
    
    NSLog(@"%@",  predicate);
    // Output:
    // value LIKE[cd] 'FOO' OR  value LIKE[cd] 'bar' OR  value LIKE[cd] 'lorem'
    

    这会从值列表中创建一个静态谓词表达式。也许它会对某人有用。

    更新 2:

    实际上,下面的更新解决方案似乎不适用于 sqlite 并产生一个

    'NSInvalidArgumentException',
    reason: 'unimplemented SQL generation for predicate : ... (bad LHS)'
    

    我认为对于数组/dict/set 比较和IN,运算符左侧只允许使用键。

    更新:

    在对表达式和谓词进行了一些研究之后,我发现了另一种方法,似乎效果很好:

    NSPredicate *predicate =
       [NSPredicate predicateWithFormat:
         @"lowercase(value) IN %@", values];
    

    这使用函数表达式lowercase: 来获取值的小写表示。剩下要做的就是确保values 的所有条目都是小写的,并且您将能够使用不区分大小写的IN 表达式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-01-26
      • 1970-01-01
      • 2022-11-22
      • 2010-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多