2013-07-08 11 views
7

Durante la ricerca del testo Çınaraltı Café per il testo Ci utilizzando il codiceStringa di ricerca con errati privi di punti turco I

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

ottengo range.location uguale NSNotFound.

Non ha a che fare con il segno diacritico sull'iniziale Ç perché ottengo lo stesso risultato cercando alti dove l'unico carattere dispari è il ı. Ho anche una corrispondenza valida alla ricerca di Cafe che contiene un segno diacritico (l'é).

La documentazione di mela mention this situation le indicazioni relative al parametro locale ed io penso li sto seguendo. Anche se immagino di non essere perché non funziona.

Come posso ottenere una ricerca di 'i' per abbinare sia 'i' e 'I'?

+0

Non penso che sia valsa la pena di cercare attraverso la documentazione di Apple, vorrei solo usare un'espressione regolare al vostro posto. –

+0

I documenti che menzioni riguardano una situazione diversa da quella che hai qui. Se si dispone di una stringa con il maiuscolo i senza maiuscole e si esegue una ricerca insensibile alle maiuscole e minuscole con una i regolare, funzionerà correttamente a meno che non si utilizzi la lingua turca. Con le impostazioni locali turche, il maiuscolo i senza maiuscole può essere trovato solo con un i senza punto minuscolo, non un normale io. Ho fatto alcuni test e, a prescindere dalle impostazioni locali, non sembra esserci alcun modo per trovare la corrispondenza con la i senza puntini con una i normale. Forse è un bug. – rmaddy

+0

@rmaddy Ho appena pensato che se una ricerca insensibile al caso per 'I' corrisponde sia a' i' che a 'ı', allora _surely_ una ricerca insensibile al maiuscolo per' i' corrisponde sia a 'i' che a' ı'. Forse ho solo bisogno di sapere di più sulla lingua turca :( – deanWombourne

risposta

1

Ho fatto questo e sembra funzionare bene per me .. spero che aiuti!

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

Sì, che funziona _in questo caso esatto_ - sfortunatamente, non controllo i dati di input (è inserito dagli editori in Turchia) quindi ci saranno altri testi che non corrispondono correttamente. Questo è stato il primo che ho visto! Spero che ci sia una soluzione generale al mio problema. Sospetto che questo sia irrisolvibile perché non capisco davvero il turco - potrebbero essere solo lettere diverse; potrebbe essere come aspettarsi una corrispondenza del modello en-gb per 'a' per abbinare 'b': | – deanWombourne

+1

@deanWombourne La mia lingua madre è il turco e posso confermare che questo è l'unico caso limite, la ricerca insensibile ai segni diacritici copre tutti i casi tranne questo. Sto usando questo nei miei progetti e non ho ancora avuto il tuo problema, quindi spero che aiuti!:) – akaralar

+0

sì, è incredibilmente utile, grazie! Sembra che riesca a farla franca sostituendo semplicemente le stringhe :) – deanWombourne

2

Non so se questo aiuta come una risposta, ma forse spiega perché sta accadendo.

Tengo a precisare che non sono un esperto in materia, ma ho cercato in questo per i miei scopi e fatto qualche ricerca.

Guardando il Unicode collation chart for latin, i caratteri equivalenti a ASCII "i" (\u0069) non includono "ı" (\u0131), mentre tutte le altre lettere nel vostro esempio stringa sono come ci si aspetta, vale a dire:

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

Il ı carattere viene elencato separatamente come di differenza principale a i. Ciò potrebbe non avere senso per un oratore turco (non ne sono uno) ma è ciò che Unicode ha da dire al riguardo, e si adatta alla logica del problema che descrivi.

In Chrome si può vedere questo in azione con una ricerca in-page. La ricerca nella pagina per ASCII i evidenzia tutti i caratteri nel suo blocco e non corrisponde a ı. La ricerca di ı fa il contrario.

Al contrario, MySQL's utf8_general_ci collation table mappe ASCII maiuscola I-ı come si desidera.

Così, senza sapere nulla di iOS, sto supponendo che sta utilizzando lo standard Unicode e normalizzare tutti i caratteri di latino da questa tabella.

Quanto a come si corrispondono Çınaraltı con Ci - se non si può ignorare il tavolo di confronto, allora forse si può semplicemente sostituire i nelle stringhe di ricerca con un'espressione regolare, quindi si cerca su Ç[iı] invece.

+0

Inoltre, io Sono stato [giocando con la traslitterazione in JavaScri pt] (http://apps.timwhitlock.info/js/translit) – Tim

1

Come ricorda Tim, possiamo usare espressioni regolari per abbinare testo contenente i o ı. Inoltre non volevo aggiungere un nuovo campo o modificare i dati di origine mentre la ricerca cerca enormi quantità di stringa. Così ho trovato una soluzione usando le espressioni regolari e NSPredicate.

Creare la categoria NSString e copiare questo metodo. Restituisce il modello di corrispondenza or di base. Puoi usarlo con qualsiasi metodo che accetta pattern di espressioni regolari.

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

Quindi, se il termine di ricerca è Şırnak, esso crea Ş[ıi]rnak per maiuscole e minuscole e Ş[ıiIİ]rnak per caso ricerca maiuscole.

E qui ci sono i possibili usi.

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

È inoltre possibile utilizzare NSRegularExpression ma penso che con cassa e diacritic ricerca maiuscole con NSPredicate è molto più semplice.

2

Ho scritto un'estensione semplice in Swift 3 per la ricerca di stringhe turche.

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) 

È possibile controllare il cellulare fuori https://github.com/alpkeser/swift_turkish_string_search/blob/master/TurkishTextSearch.playground/Contents.swift

Problemi correlati