7

使用代码搜索文本Çınaraltı CaféCi

NSStringCompareOptions options =
    NSCaseInsensitiveSearch |
    NSDiacriticInsensitiveSearch |
    NSWidthInsensitiveSearch;
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:@"tr"];
NSRange range = [haystack rangeOfString:needle 
                                options:options
                                  range:NSMakeRange(o, haystack.length)
                                 locale:locale];

我得到range.location了 equals NSNotFound

这与初始 Ç 上的变音符号无关,因为我得到相同的结果来搜索alti唯一奇怪的字符是 ı 的位置。我还得到了一个有效的匹配搜索,Cafe其中包含一个变音符号(é)。

苹果文档将这种情况作为参数注释提到locale,我我正在关注它们。虽然我想我不是因为它不起作用。

如何搜索“i”以匹配“i”和“ı”?

4

4 回答 4

4

我不知道这是否有助于作为答案,但也许可以解释为什么会这样。

我应该指出我不是这方面的专家,但我一直在为自己的目的研究这个并进行了一些研究。

查看 latin的Unicode 排序规则表,ASCII 的等效字符"i" (\u0069)不包括"ı" (\u0131),而示例字符串中的所有其他字母都如您所料,即:

  • "c" (\u0063) 确实包括"Ç" (\u00c7)
  • "e" (\u0065) 确实包括"é" (\u00e9)

ı字符被单独列为与 的主要区别i。对于土耳其语使用者(我不是)来说,这可能没有意义,但这是 Unicode 不得不说的,它确实符合您描述的问题的逻辑。

在 Chrome 中,您可以通过页内搜索看到这一点。在页面中搜索 ASCIIi突出显示其块中的所有字符并且不匹配ı。搜索ı则相反。

相比之下,MySQL 的 utf8_general_ci 排序表将大写 ASCII 映射Iı您想要的。

因此,在不了解 iOS 的情况下,我假设它使用 Unicode 标准并通过该表将所有字符标准化为拉丁语。

至于你如何匹配- 如果你不能覆盖排序规则表,那么也许你可以用正则表达式替换Çınaraltı你的搜索字符串,所以你可以继续搜索。CiiÇ[iı]

于 2013-07-25T00:34:10.067 回答
3

我在 Swift 3 中为土耳其语字符串搜索编写了一个简单的扩展。

let turkishSentence = "Türkçe ya da Türk dili, batıda Balkanlar’dan başlayıp doğuda Hazar Denizi sahasına kadar konuşulan Altay dillerinden biridir."
let turkishWannabe = "basLayip"

let shouldBeTrue = turkishSentence.contains(turkishString: turkishWannabe, caseSensitive: false)
let shouldBeFalse = turkishSentence.contains(turkishString: turkishWannabe, caseSensitive: true)

您可以从https://github.com/alpkeser/swift_turkish_string_search/blob/master/TurkishTextSearch.playground/Contents.swift查看

于 2017-02-05T09:28:13.297 回答
1

正如 Tim 所说,我们可以使用正则表达式来匹配包含ior的文本ı。当搜索查找大量字符串时,我也不想添加新字段或更改源数据。所以我最终使用正则表达式和NSPredicate.

创建NSString类别并复制此方法。它返回基本or匹配模式。您可以将它与任何接受正则表达式模式的方法一起使用。

- (NSString *)zst_regexForTurkishLettersWithCaseSensitive:(BOOL)caseSensitive
{
    NSMutableString *filterWordRegex = [NSMutableString string];
    for (NSUInteger i = 0; i < self.length; i++) {
        NSString *letter = [self substringWithRange:NSMakeRange(i, 1)];
        if (caseSensitive) {
            if ([letter isEqualToString:@"ı"] || [letter isEqualToString:@"i"]) {
                letter = @"[ıi]";
            } else if ([letter isEqualToString:@"I"] || [letter isEqualToString:@"İ"]) {
                letter = @"[Iİ]";
            }
        } else {
            if ([letter isEqualToString:@"ı"] || [letter isEqualToString:@"i"] ||
                [letter isEqualToString:@"I"] || [letter isEqualToString:@"İ"]) {
                letter = @"[ıiIİ]";
            }
        }
        [filterWordRegex appendString:letter];
    }
    return filterWordRegex;
}

因此,如果搜索词是Şırnak,它会创建Ş[ıi]rnak区分大小写和Ş[ıiIİ]rnak不区分大小写的搜索。

以下是可能的用法。

NSString *testString = @"Şırnak";

// First create your search regular expression.
NSString *searchWord = @"şır";
NSString *searchPattern = [searchWord zst_regexForTurkishLettersWithCaseSensitive:NO];

// Then create your matching pattern.
NSString *pattern = searchPattern; // Direct match
// NSString *pattern = [NSString stringWithFormat:@".*%@.*", searchPattern]; // Contains
// NSString *pattern = [NSString stringWithFormat:@"\\b%@.*", searchPattern]; // Begins with

// NSPredicate
// c for case insensitive, d for diacritic insensitive
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"self matches[cd] %@", pattern]; 
if ([predicate evaluateWithObject:testString]) {
    // Matches
}

// If you want to filter an array of objects
NSArray *matchedCities = [allAirports filteredArrayUsingPredicate:
    [NSPredicate predicateWithFormat:@"city matches[cd] %@", pattern]];

您也可以使用NSRegularExpression,但我认为使用大小写和变音符号不敏感搜索NSPredicate要简单得多。

于 2014-09-23T10:45:46.203 回答
1

我这样做了,似乎对我很有效..希望它有所帮助!

NSString *cleanedHaystack = [haystack stringByReplacingOccurrencesOfString:@"ı"
                                                                withString:@"i"];
cleanedHaystack = [cleanedHaystack stringByReplacingOccurrencesOfString:@"İ"
                                                             withString:@"I"];

NSString *cleanedNeedle = [needle stringByReplacingOccurrencesOfString:@"ı"
                                                            withString:@"i"];
cleanedNeedle = [cleanedNeedle stringByReplacingOccurrencesOfString:@"İ"
                                                         withString:@"I"];

NSUInteger options = (NSDiacriticInsensitiveSearch |
                      NSCaseInsensitiveSearch |
                      NSWidthInsensitiveSearch);
NSRange range = [cleanedHaystack rangeOfString:cleanedNeedle
                                       options:options];
于 2014-07-25T01:12:17.033 回答