Búsqueda de cadenas con turco dotless i

Al search el text Çınaraltı Café para el text Ci usando el código

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

Obtengo range.location es igual a NSNotFound .

No se trata del diacrítico en la inicial Ç porque obtengo el mismo resultado en la búsqueda de alti donde el único carácter extraño es ı. También obtengo una coincidencia válida buscando Cafe que contiene un diacrítico (el é).

Los documentos de Apple mencionan esta situación como notas sobre el parámetro de locale y creo que las estoy siguiendo. Aunque supongo que no soy porque no funciona.

¿Cómo puedo get una búsqueda de 'i' para que coincida con 'i' y 'ı'?

Lo hice y parece funcionar bien para mí … espero que ayude!

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

No sé si esto ayuda como una respuesta, pero quizás explique por qué está sucediendo.

Debo señalar que no soy un experto en este asunto, pero he estado investigando esto para mis propios propósitos y he estado investigando.

Al mirar la tabla de intercalación de Unicode para latin , los caracteres equivalentes a ASCII "i" (\u0069) no incluyen "ı" (\u0131) , mientras que todas las demás letras de su cadena de ejemplo son las "ı" (\u0131) , es decir:

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

El carácter ı se enumera por separado como una diferencia primaria para i . Eso podría no tener sentido para un hablante turco (no soy uno), pero es lo que Unicode tiene que decir al respecto, y se ajusta a la lógica del problema que usted describe.

En Chrome, puedes ver esto en acción con una búsqueda en la página. Buscando en la página para ASCII resalta todos los caracteres en su bloque y no coincide con ı . La búsqueda de ı hace lo contrario.

Por el contrario, la tabla de sorting utf8_general_ci de MySQL asigna mayúsculas ASCII I a ı como desee.

Entonces, sin saber nada sobre iOS, estoy asumiendo que está usando el estándar Unicode y normalizando todos los caracteres a latin por esta tabla.

En cuanto a cómo Çınaraltı con Ci : si no puede anular la tabla de sorting, quizás pueda replace i en sus cadenas de búsqueda con una expresión regular, por lo que searchá en Ç[iı] lugar.

Escribí una extensión simple en Swift 3 para la búsqueda de cadenas turcas.

 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) 

Puede consultarla en https://github.com/alpkeser/swift_turkish_string_search/blob/master/TurkishTextSearch.playground/Contents.swift

Como menciona Tim, podemos usar la expresión regular para hacer coincidir el text que contiene i o ı . Tampoco quería agregar un campo nuevo ni cambiar los datos de origen a medida que la búsqueda busca grandes cantidades de cadenas. Entonces terminé una solución usando expresiones regulares y NSPnetworkingicate .

Cree la categoría NSString y copie este método. Devuelve el patrón básico or coincidente. Puede usarlo con cualquier método que acepte un patrón de expresión regular.

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

Entonces, si la palabra de búsqueda es Şırnak , crea Ş[ıi]rnak para Ş[ıi]rnak entre mayúsculas y minúsculas y Ş[ıiIİ]rnak para search mayúsculas y minúsculas.

Y aquí están los posibles usos.

 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 // NSPnetworkingicate // c for case insensitive, d for diacritic insensitive NSPnetworkingicate *pnetworkingicate = [NSPnetworkingicate pnetworkingicateWithFormat:@"self matches[cd] %@", pattern]; if ([pnetworkingicate evaluateWithObject:testString]) { // Matches } // If you want to filter an array of objects NSArray *matchedCities = [allAirports filtenetworkingArrayUsingPnetworkingicate: [NSPnetworkingicate pnetworkingicateWithFormat:@"city matches[cd] %@", pattern]]; 

También puede usar NSRegularExpression pero creo que el uso de mayúsculas y minúsculas y la búsqueda insensible diacrítica con NSPnetworkingicate son mucho más simples.