12

大文字と小文字やアクセントを区別しない SELECT クエリを実行する必要があります。デモ目的で、次のようなテーブルを作成します。

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 で動作しています。

前もって感謝します、

4

3 に答える 3

18

2つの基本的なアプローチ:

  1. 表に、国際文字を含まない文字列を含む2番目の列を作成できます。さらに、この2次検索列に対して検索を実行する前に、検索対象の文字列から国際文字も削除する必要があります(これにより、非国際と非国際を比較します)。

    これは、国際文字を変換するために使用するルーチンです。

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

    ちなみに、結果を並べ替える必要がある場合は、メインフィールドの代わりにこのセカンダリ検索フィールドで並べ替えることもできます。これにより、SQLiteが国際文字を並べ替えることができないことに起因する問題も回避できます。

  2. または、独自の「アクセントのない」C関数を作成することもできます(このC関数@implementationをクラスの外部で定義します)。

    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);
        }
    }
    

    次に、このC関数を呼び出すSQLite関数を定義できます(データベースを開いた後にこのメソッドを呼び出します。これは、そのデータベースを閉じるまで有効です)。

    - (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));
    }
    

    unaccentedこれで、SQLでこの新しい関数を使用できるようになります。例:

    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));
    
于 2012-04-27T19:18:54.423 に答える
4

ユーザー関数を作成するか、like()関数のデフォルトの実装をオーバーライド (つまり、置換)する必要があります。その理由はLIKE、sqlite の演算子が非 ASCII 大文字と小文字の区別をサポートしていないためです。

SQLite はデフォルトで ASCII 文字の大文字と小文字のみを理解します。LIKE 演算子は、デフォルトで、ASCII 範囲外の Unicode 文字に対して大文字と小文字を区別します。たとえば、表現 'a' LIKE 'A' は TRUE ですが、'æ' LIKE 'Æ' は FALSE です。

これは理にかなっています。そうしないと、大文字と小文字が異なるため、sqlite は異なるカルチャをサポートする必要があります。例として、トルコの首都はドットのみであり、小文字のはドットなしのiIİIıです。このすべてのカルチャ情報を sqlite に埋め込むのは非常に面倒です (つまり、sqlite オブジェクト コードが増加します)。

于 2012-04-29T10:21:34.017 に答える
2

これが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'
于 2015-01-09T20:14:09.200 に答える