2010-12-06 13 views
2

Ich mache eine Sprachanwendung, und ich habe eine lange Liste von Vokabeln in Bezug auf diese Sprache (Deutsch, falls jemand interessiert war). Ich habe die Funktionalität in meiner App, zwischen dem Sortieren der Tabellenansicht nach deutschen Wörtern oder nach englischen Wörtern zu wechseln.Ignorieren bestimmter Strings beim Sortieren eines Arrays

Wenn ich folgendes:

NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:type]; 
NSString *string = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]; 
NSArray *array = [[string componentsSeparatedByString:@"\n"] sortedArrayUsingSelector:@selector(compare:)]; 

es absolut perfekt funktioniert - damit meine ich, genau wie erwartet. Was ich jedoch verbessern möchte, ist, dass es bestimmte Wörter wie Verben oder Substantive gibt, denen immer Präfixe vorausgehen, wie "zu", wie "etwas tun" oder "das" vor Substantive. Was ich also tun möchte, ist, diese irgendwie von meiner Sorte auszuschließen, weil ich ansonsten alle Verben alphabetisch unter dem Abschnitt "t" in meinem Array sortiere, was nicht sehr benutzerfreundlich ist.

Ich habe die Apple-Dokumentation über NSString und NSArray durchgesehen, da dies die compare-Funktion ist (sofern ich mich nicht sehr irre), und ich habe keinen Weg gefunden, der für mich Sinn ergibt. Dies ist das erste Mal, dass ich irgendwelche Daten verarbeitet habe, so dass ich etwas Einfaches vermisse und deshalb würde ich mich über Hilfe freuen.

Vielen Dank

Michaeljvdw

Antwort

1

Sie könnten etwas Glück mit localizedCompare: oder localizedStandardCompare: haben, aber ich glaube nicht, dass eine dieser Artikel Streifen aus wird und Präpositionen wie Sie wollen. Stattdessen werden Sie wahrscheinlich eine Kategorie NSString definieren, die den spezifischen Stil bietet Ihnen der Sortierung bist:

@interface NSString (MySortAdditions) 
- (NSComparisonResult)compareWithoutArticles:(NSString *)other; 
@end 

@implementation NSString (MySortAdditions) 
- (NSComparisonResult)compareWithoutArticles:(NSString *)other { 
    NSMutableString *mutableSelf = [NSMutableString stringWithString:self]; 
    [mutableSelf 
     replaceOccurrencesOfString:@"das" 
     withString:@"" 
     options:NSCaseInsensitiveSearch 
     range:NSMakeRange(0, [mutableSelf length]) 
    ]; 

    ... 

    // delete articles from 'other' too 

    NSCharacterSet *trimSet = [NSCharacterSet whitespaceAndNewlineCharacterSet]; 
    NSString *trimmedSelf = [mutableSelf stringByTrimmingCharactersInSet:trimSet]; 
    NSString *trimmedOther = ...; 

    return [trimmedSelf localizedCaseInsensitiveCompare:trimmedOther]; 
} 
@end 

Sie dann @selector(compareWithoutArticles:) als Sortier Selektor für NSArray verwenden können.

+0

Das sieht ziemlich genau so aus, wie ich es will, aber ich bin etwas verwirrt von dem Bit in deinem Code, wenn du replaceOccurrencesOfString sagst: @ "das" withString @ "" ... weil ich eigentlich das "das" brauche (etc) um im Array zu bleiben, muss ich es nur von der Sorte ignoriert. Adressiert dieser Code das? Danke für die Antwort übrigens, ich schätze Ihre Hilfe. – Michaeljvdw

+0

Ja, was dieser Code tatsächlich tut, ist ein Duplikat der zu vergleichenden Zeichenketten zu erstellen, und modifiziert dann diese, um alle Artikel und Leerzeichen zu entfernen. Das heißt, im Nachhinein könnte es sinnvoller sein, den String nicht zu modifizieren, sondern stattdessen 'compare: options: range: locale:', um Unterbereiche beider Strings nur aus Performance-Gründen zu vergleichen. –

1

Zuerst nicht compare: verwenden. Verwenden Sie stattdessen localizedCompare:. Dies ist wichtig, denn ob á erscheint direkt nach a oder nach z als separater Buchstabe hängt von der Sprache ab. localizedCompare: kümmert sich darum.

--edit

Wie Justin sagt, localizedStandardCompare: der Selektor verwendet werden soll! Ich kannte diese Methode nicht. Wie in der Dokumentation geschrieben, localizedStandardCompare: tut mehr als localizedCompare:, obwohl das Dokument nicht genau sagt, was es tut.

--end von bearbeiten

Wenn Sie mehr, müssen Sie das selbst implementieren. Sie können Kategorie für diesen Zweck verwenden. Zuerst erklären es

@interface NSString (MichaelsSuperCompareCategory) 
     -(NSComparisonResult)michaelsSuperCompare:(NSString*)string; 
    @end 

und dann umzusetzen

@interface NSString (MichaelsSuperCompareCategory) 
     -(NSComparisonResult)michaelsSuperCompare:(NSString*)string{ 
      ... 
     } 
    @end 

Auf diese Weise können Methoden zu einer vorhandenen Klasse hinzufügen.Dann können Sie

NSArray *array = [[string componentsSeparatedByString:@"\n"] 
           sortedArrayUsingSelector:@selector(michaelsSuperCompare:)]; 

verwenden Es ist wichtig, die Methodennamen mit etwas unterscheidend, Präfix nicht versehentlich zum Absturz mit internen Methoden von Apple.

Was die Funktionalität angeht, müssen Sie das, soweit ich weiß, selbst implementieren. Sie können das aktuelle Gebietsschema mit [NSLocale currentLocale] abrufen. Sie können ein besseres Verhalten für die Sprachen implementieren, die Sie kennen, und dann standardmäßig auf localizedCompare: für unbekannte Sprachen.

4

Sie sind auf dem richtigen Weg. Was Sie anstelle der (eingebauten) compare Methode verwenden möchten, ist Ihre eigene Methode zu schreiben, die die "bis" oder "die" Bits beseitigen kann, wenn sie existieren, und dann die existierende compare Methode verwenden.

Ihr Anruf würde wie folgt aussehen:

NSArray *array = [[string componentsSeparatedByString:@"\n"] sortedArrayUsingSelector:@selector(myCompare:)]; 

eine benutzerdefinierte Kategorie Verwenden Sie NSString mit den folgenden Methoden geben:

// This method can be exposed in a header 
- (NSComparisonResult)myCompare:(NSString*)aString 
{ 
NSString* selfTrimmed = [self removeArticles]; 
NSString* aStringTrimmed = [s2 removeArticles]; 
return [self compare:aString]; 
} 

// This method can be kept private in the .m implementation 
- (NSString*)removeArticles 
{ 
    NSRange range = NSMakeRange(NSNotFound, 0); 
    if ([self hasPrefix:@"to "]) 
    { 
    range = [self rangeOfString:@"to "]; 
    } 
    else if ([self hasPrefix:@"the "]) 
    { 
    range = [self rangeOfString:@"the "]; 
    } 

if (range.location != NSNotFound) 
{ 
    return [self substringFromIndex:range.length]; 
} 
else 
{ 
    return self; 
} 
} 
+0

+1 für den benutzerdefinierten Vergleich. Wenn es Bedenken gibt, dass "to" oder "the" irgendwo neben dem Anfang der Zeichenkette erscheinen könnten, könnten Sie Shaggys Code verwenden, aber auch range.location == 0 (oder eine weniger elegante substringWithRange isEqualToString-Sache, zuerst die Zeichenkettenlänge prüfen) usw.) –

+0

@Matthew Frederick guter Punkt. Geändert, um 'hasPrefix' zu verwenden, das sicherstellt, dass' rangeOfString' es nur findet, wenn es mit dem Artikel beginnt. –

+0

Ausgezeichnete Lösung. –

0

Ich würde irgendwie tun -replaceOccurancesOfStrings auf dem alle Daten zB "To" -> "" - und dann die Daten neu laden. (oder dies in einem Texteditor)

Eine andere Sache, über die man nachdenken muss, ist z. B. 'zu gehen' geändert zu 'gehen (zu)', was im Voraus erfolgen kann (und weniger Verwirrung für den Benutzer schafft) wie sie alphabetisch scrollen).

Verwandte Themen