NSPredicate без учета регистра для строк из массива?

У меня есть ситуация, когда я хочу получить объекты из своего основного хранилища данных по ключу имени пользователя, но я хочу, чтобы сравнение было без учета регистра. Предикат, который у меня есть, таков:

username IN $usernames

Затем я выполняю замену переменной с помощью массива строк, которые представляют собой имена пользователей, которые я хочу найти. Он работает, но чувствителен к регистру. Я бы хотел сделать что-то подобное, я думаю:

username IN[c] $usernames

К сожалению, это не работает. Сравнение строк по-прежнему должно производиться с учетом регистра. (Я не получаю сообщения о том, что это неподдерживаемый запрос.)

Есть ли другой способ написать этот предикат, чтобы он работал так, как мне нужно, или я просто упускаю что-то очевидное?


person Sean    schedule 06.01.2010    source источник
comment
вы строите предикат с помощью построителя предикатов или непосредственно в коде?   -  person Anurag    schedule 07.01.2010
comment
Это запрос на выборку, хранящийся в модели данных.   -  person Sean    schedule 07.01.2010


Ответы (4)


Модификатор case в операторе IN явно игнорируется при выполнении выборки из хранилища SQLite. (Вы не указали тип магазина в своем вопросе.)

Я бы рекомендовал зарегистрировать ошибку в документации, чтобы можно было задокументировать это ограничение / поведение.

Я также рекомендую отправить запрос на добавление функции в репортер ошибок, чтобы его можно было рассмотреть для будущей поддержки.

А пока вам придется вытащить запрос на выборку из модели данных и создать его программно. Вы можете создать составной предикат ИЛИ, который проверяет равенство без учета регистра для каждого из ваших значений (и проверяет, соответствует ли он вашим требованиям к производительности).

Обратите внимание, что если вы поддерживаете цели ОС до 10.6, модификатор case на == не поддерживается, и в этом случае потребуется еще одно альтернативное решение.

person Jim Correia    schedule 07.01.2010
comment
В качестве последнего пункта, вы имеете в виду ==, когда используется как строка предиката? Работает ли он по-прежнему при программном построении предиката? Я нацелен на 10,5. - person Sean; 07.01.2010
comment
После тестирования на 10.5 похоже не пойдет. Черт возьми! Кажется, что мой единственный вариант - создать выражение, подобное: username CONTAINS [cd] $ u AND $ u CONTAINS [cd] username. Вздох. - person Sean; 07.01.2010
comment
И нет. Даже использование двух CONTAINS не сработает, потому что мое общее выражение представляет собой OR для множества других предикатов, и, похоже, у меня не может быть набора OR, содержащего предикаты AND. Мля. После того, как я все сделал неправильно, я переключился на использование LIKE [cd] и экранирование символов * и? символы из моей входной строки. Работает как шарм. Кажется, существует довольно неприятное количество ограничений в обработке предикатов ... - person Sean; 07.01.2010
comment
LIKE [c] и экранирование * и? - типичное решение, когда необходимо развернуть версию 10.5. - person Jim Correia; 08.01.2010

Вы можете попробовать что-нибудь вроде ANY $usernames LIKE[c] username. Я сделал что-то подобное, где вместо подстановки переменных у меня есть только ключевой путь, такой как «person.name», и этот предикат работает для меня. Не уверен, работает ли он по-другому с переменной вместо ключевого пути, но попробовать стоит.

person Brian Webster    schedule 07.01.2010
comment
К сожалению, этот предикат не будет работать с хранилищем SQLite. (Нереализованная генерация SQL.) В ситуациях, когда это действительно работает, убедитесь, что в строке sin $ usernames есть буквальные экранированные символы подстановки LIKE. - person Jim Correia; 07.01.2010

Вот еще один обходной путь, но он требует изменения MOM.

Сделайте имя пользователя полноценной сущностью. Создайте обратную связь между именем пользователя и другой вашей сущностью.

Теперь для запроса на выборку установите сущность как «Имя пользователя», затем запустите этот предикат (предполагая свойство «имя» и свойство «родитель»):

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

Это может быть излишним, но позволит вам выполнить поиск по своему усмотрению.

person Corey Floyd    schedule 07.01.2010

Хотя этому вопросу несколько лет, я просто наткнулся на ту же проблему и решил ее следующим образом:

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)'

Я думаю, что для сравнений array / dict / set и IN разрешены только ключи в левой части оператора.

ОБНОВИТЬ:

После некоторого исследования выражений и предикатов я нашел другой подход, который, кажется, работает достаточно хорошо:

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

Здесь используется функциональное выражение lowercase: для получения значения в нижнем регистре. Все, что осталось сделать, это убедиться, что все записи values написаны в нижнем регистре, и вы сможете использовать IN выражения без учета регистра.

person lupz    schedule 13.04.2015