字符串搜索土耳其无点我

时间:2013-07-08 22:11:53

标签: ios objective-c localization nsstring turkish

使用代码

在文本Çı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等于NSNotFound

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

苹果文档mention this situation作为locale参数的注释,我认为我正在关注它们。虽然我想我不是因为它不起作用。

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

4 个答案:

答案 0 :(得分:3)

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

我应该指出我不是这方面的专家,但我一直在为自己的目的研究这个问题并且正在做一些研究。

查看Unicode collation chart for latin,ASCII "i" (\u0069)的等效字符不包括"ı" (\u0131),而示例字符串中的所有其他字母都符合您的预期,即:

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

ı字符单独列为主要差异i。这对土耳其语发言者来说可能没有意义(我不是其中之一),但它是Unicode必须说的,它确实符合你描述的问题的逻辑。

在Chrome中,您可以通过页内搜索查看此操作。在页面中搜索ASCII i会突出显示其块中的所有字符,但与ı不匹配。搜索ı则恰恰相反。

相比之下,MySQL's utf8_general_ci collation table可以根据需要将大写ASCII I映射到ı

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

关于如何将ÇınaraltıCi匹配 - 如果您无法覆盖整理表,那么您可以只用正则表达式替换搜索字符串中的i,您可以搜索Ç[iı]

答案 1 :(得分: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

查看

答案 2 :(得分: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];

答案 3 :(得分:1)

Tim提到,我们可以使用正则表达式来匹配包含iı的文字。当搜索查找大量字符串时,我也不想添加新字段或更改源数据。所以我最终得到了一个使用正则表达式和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使用案例和变音符号不敏感搜索要简单得多。