2013-07-08 37 views
7

當使用代碼土耳其帶點字符串搜索我

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

搜索文本Çınaraltı Café文本Ci我得到range.location等於NSNotFound

這不是關於最初的變音符號,因爲我得到了相同的結果搜索alti,其中唯一的奇怪字符是ı。我也收到一個有效的匹配搜索Cafe其中包含一個變音符號(é)。

蘋果文檔mention this situation作爲對locale參數說明和我認爲我跟了上去。雖然我猜我並不是因爲它不工作。

如何獲得'我'以匹配'我'和'我'的搜索?

+0

檢查出來,我不認爲這是值得通過蘋果的文檔搜索的努力,我只想用一個正則表達式在你的地方。 –

+0

您提到的文檔涵蓋了與您在此處不同的情況。如果你有一個大寫無字符串的字符串,並且你用普通的我做了一個不區分大小寫的搜索,那麼除非你使用土耳其語區域,否則它將正常工作。隨着土耳其語區域,大寫無點我只能找到一個小寫無點我,而不是一個普通的我。我做了一些測試,不管區域設置如何,似乎沒有任何方法可以找到與普通i相匹配的無點。也許這是一個錯誤。 – rmaddy

+0

@rmaddy我只是假設如果不區分大小寫的'I'搜索匹配'i'和'ı',那麼_surely_對'i'的大小寫不敏感的搜索匹配'i'和'ı'。也許我只需要更多地瞭解土耳其語:( – deanWombourne

回答

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]; 
+0

是的,這工作_在這個確切case_ - 不幸的是,我不控制輸入數據(它是由編輯在土耳其輸入),所以會有其他文字不正確。這恰好是我發現的第一個!我希望有一個通用的解決方案來解決我的問題。我懷疑這是無法解決的,因爲我不太瞭解土耳其語 - 他們可能只是不同的信件;它可能就像期待'a'的en-gb模式匹配匹配'b':| – deanWombourne

+1

@deanWombourne我的母語是土耳其語,我可以證實這是唯一的邊緣案例,除了這個之外,區別性的不敏感搜索涵蓋了每個案例。我在我的項目中使用了這個功能,並且還沒有解決您的問題,所以我希望它有幫助!:) – akaralar

+0

是的,這非常有幫助,謝謝!看起來像我可以逃脫只是字符串替換:) – deanWombourne

2

我不知道這是否有助於解答,但也許解釋了爲什麼會發生。

我應該指出,我不是這方面的專家,但我一直在爲我自己的目的而進行研究,並一直在做一些研究。

望着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ı]搜索代替。

+0

除此之外,我已經[在JavaScri中使用音譯了(http://apps.timwhitlock.info/js/translit) – Tim

1

作爲添提到,我們可以使用正則表達式來匹配包含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,它區分大小寫和Ş[ıiIİ]rnak不區分大小寫的搜索創建Ş[ıi]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更加簡單。

2

我在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