如何处理iOS SQLite中的重音字符?

我需要执行对大小写不敏感的SELECT查询。 为了演示目的,我创build了一个如下表格:

create table table ( column text collate nocase ); insert into table values ('A'); insert into table values ('a'); insert into table values ('Á'); insert into table values ('á'); create index table_cloumn_Index on table (column collate nocase); 

然后,我在执行下列查询时得到这些结果:

 SELECT * FROM table WHERE column LIKE 'a'; > A > a SELECT * FROM table WHERE column LIKE 'á'; > á SELECT * FROM table WHERE column LIKE 'Á'; > Á 

我怎样才能解决这个问题,所以下面的任何一个查询的结果都是这样的:

 > A > a > Á > á 

顺便说一句,sqlite在iOS上运行。

提前致谢,

两种基本方法:

  1. 您可以在表中创build第二列,其中包含没有国际字符的string。 而且,在对这个辅助search栏进行search之前,还应该从正在search的string中删除国际字符(这样您就可以比较非国际性和非国际性)。

    这是我用来转换国际字符的例程:

     NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 

    您也可以使用以下代替重音字符:

     NSMutableString *mutableString = [string mutableCopy]; CFStringTransform((__bridge CFMutableStringRef)mutableString, NULL, kCFStringTransformStripCombiningMarks, NO); 

    顺便说一句,如果你需要sorting结果,你也可以sorting在这个辅助search字段而不是主字段,这将避免源于SQLite无法sorting国际字符的问题。

  2. 你也可以创build你自己的“unaccented”C函数(在你的类的@implementation之外定义这个C函数):

     void unaccented(sqlite3_context *context, int argc, sqlite3_value **argv) { if (argc != 1 || sqlite3_value_type(argv[0]) != SQLITE_TEXT) { sqlite3_result_null(context); return; } @autoreleasepool { NSMutableString *string = [NSMutableString stringWithUTF8String:(const char *)sqlite3_value_text(argv[0])]; CFStringTransform((__bridge CFMutableStringRef)string, NULL, kCFStringTransformStripCombiningMarks, NO); sqlite3_result_text(context, [string UTF8String], -1, SQLITE_TRANSIENT); } } 

    然后你可以定义一个SQLite函数来调用这个C函数(在你打开数据库之后调用这个方法,直到你closures这个数据库才会有效):

     - (void)createUnaccentedFunction { if (sqlite3_create_function_v2(database, "unaccented", 1, SQLITE_ANY, NULL, &unaccented, NULL, NULL, NULL) != SQLITE_OK) NSLog(@"%s: sqlite3_create_function_v2 error: %s", __FUNCTION__, sqlite3_errmsg(database)); } 

    完成之后,您现在可以在SQL中使用这个新的不unaccented函数,例如:

     if (sqlite3_prepare_v2(database, "select a from table where unaccented(column) like 'a'", -1, &statement, NULL) != SQLITE_OK) NSLog(@"%s: insert 1: %s", __FUNCTION__, sqlite3_errmsg(database)); 

您将需要创build一些用户函数 ,或覆盖(即replace) like()函数的默认实现。 原因是sqlite中的LIKE运算符不支持非ASCII区分大小写:

SQLite默认只能识别ASCII字符的大/小写。 对于超出ASCII范围的unicode字符,LIKE运算符默认为区分大小写。 例如,expression式'a'LIKE'A'为TRUE,但'æ'LIKE'Æ'为FALSE。

这是有道理的,否则sqlite将需要支持不同的文化,因为案件从一个到另一个。 一个例子就是i在土耳其的首都,不是I而是一个点缀的İ ,而I的小写字母是一个无点ı 。 在sqlite中embedded所有这些文化信息将是非常繁重的(即它会增加sqlite目标代码)。

这是我解决LIKE问题的方法

 static void myLow(sqlite3_context *context, int argc, sqlite3_value **argv) { NSString* str = [[NSString alloc] initWithUTF8String: (const char *)sqlite3_value_text(argv[0])]; const char* s = [[str lowercaseString] UTF8String]; sqlite3_result_text(context, s, strlen(s), NULL); [str release]; } // call it once after opening db sqlite3_create_function(_db, "myLow", 1, SQLITE_UTF8,NULL, &myLow, NULL, NULL); 

然后,而不是查询

 SELECT * FROM table WHERE column LIKE 'a' 

你应该使用

 SELECT * FROM table WHERE myLow(column) LIKE 'a'