Was ist der beste Weg, um einen NSString in Objective-C zu zerlegen/teilen?NSString-Tokenize in Objective-C
Antwort
Gefunden dies bei http://borkware.com/quickies/one?topic=NSString (nützlich Link):
NSString *string = @"oop:ack:bork:greeble:ponies";
NSArray *chunks = [string componentsSeparatedByString: @":"];
hoffe, das hilft!
Adam
Wenn Sie nur eine Zeichenfolge teilen möchten, verwenden Sie -[NSString componentsSeparatedByString:]
. Verwenden Sie für eine komplexere Tokenisierung die NSScanner-Klasse.
Wenn Ihr tokenization Bedürfnisse komplexer sind, überprüfen Sie meine Open-Source-Cocoa String Tokenisieren/Parsing-Toolkit aus: ParseKit:
Für einfache Aufspaltung von Strings ein Trennzeichen char (wie ':') , ParseKit wäre definitiv übertrieben. Aber auch für komplexe Tokenisierungsanforderungen ist ParseKit äußerst leistungsfähig/flexibel.
Siehe auch die ParseKit Tokenization documentation.
Funktioniert das noch? Ich habe es versucht und ein paar Fehler bekommen, ich bin misstrauisch, mich selbst zu reparieren. – griotspeak
-1 ist diese Antwort noch am Leben? –
Hm? Am Leben? Das ParseKit-Projekt wird aktiv gepflegt, ja. Kommentare hier sind jedoch nicht der richtige Ort, um Fehler im Projekt zu archivieren. Es ist sowohl auf Google Code als auch auf Github, wenn Sie Fehler melden müssen. –
Jeder hat componentsSeparatedByString:
erwähnt, aber auch CFStringTokenizer
verwenden können (denken Sie daran, dass ein NSString
und CFString
austauschbar sind), die zu natürlichen Sprachen tokenize wird (wie Chinesisch/Japanisch, die keine Wörter auf Räume aufgeteilt).
Und in Mac OS X 10.6 und höher, hat NSString Methoden 'enumerateLinesUsingBlock:' und 'enumerateSubstringsInRange: options: usingBlock:', wobei letzteres ein Block ist Version von CFStringTokenizer. http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/occ/instm/NSString/enumerateLinesUsingBlock: http: // developer. apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/occ/instm/NSString/enumerateSubstringsInRange:options:usingBlock: –
Die 'enumerate' Methoden sind verfügbar in iOS 4 und später auch. – bugloaf
Wenn Sie mehrere Zeichen in Token zerlegen möchten, können Sie NSString componentsSeparatedByCharactersInSet
verwenden. NSCharacterSet hat einige handliche vorgefertigte Sets wie die whitespaceCharacterSet
und die illegalCharacterSet
. Und es hat Initialisierer für Unicode-Bereiche.
Sie können auch Zeichensätze kombinieren und nutzen sie, wie dies tokenize,:
// Tokenize sSourceEntityName on both whitespace and punctuation.
NSMutableCharacterSet *mcharsetWhitePunc = [[NSCharacterSet whitespaceAndNewlineCharacterSet] mutableCopy];
[mcharsetWhitePunc formUnionWithCharacterSet:[NSCharacterSet punctuationCharacterSet]];
NSArray *sarrTokenizedName = [self.sSourceEntityName componentsSeparatedByCharactersInSet:mcharsetWhitePunc];
[mcharsetWhitePunc release];
Beachten Sie, dass componentsSeparatedByCharactersInSet
leere Saiten erzeugen wird, wenn es mehr als ein Mitglied der charSet in einer Reihe trifft, so dass Sie Vielleicht möchten Sie für Längen von weniger als 1 zu testen.
Adressiert keine Sprachen, in denen Whitespace nicht alle logischen Token voneinander trennt. Schlechte Lösung. – uchuugaka
@uchuugaka In diesem Fall würden Sie einen anderen Zeichensatz oder andere Zeichensätze verwenden, mit denen zu Tokenisieren. Ich verwende nur bestimmte Beispiele, um ein allgemeines Konzept zu veranschaulichen. – Wienke
Ich hatte einen Fall, wo ich die Konsolenausgabe nach einer LDAP-Abfrage mit ldapsearch teilen musste. Richten Sie zuerst die NSTask ein und führen Sie sie aus (ich habe hier ein gutes Codebeispiel gefunden: Execute a terminal command from a Cocoa app). Aber dann musste ich die Ausgabe aufteilen und analysieren, um nur die Print-Server-Namen aus der Ldap-Abfrage-Ausgabe zu extrahieren. Leider ist es eine mühsame String-Manipulation, die überhaupt kein Problem wäre, wenn wir C-Strings/Arrays mit einfachen C-Array-Operationen manipulieren würden. Also hier ist mein Code mit Kakao-Objekten. Wenn Sie bessere Vorschläge haben, lassen Sie es mich wissen.
//as the ldap query has to be done when the user selects one of our Active Directory Domains
//(an according comboBox should be populated with print-server names we discover from AD)
//my code is placed in the onSelectDomain event code
//the following variables are declared in the interface .h file as globals
@protected NSArray* aDomains;//domain combo list array
@protected NSMutableArray* aPrinters;//printer combo list array
@protected NSMutableArray* aPrintServers;//print server combo list array
@protected NSString* sLdapQueryCommand;//for LDAP Queries
@protected NSArray* aLdapQueryArgs;
@protected NSTask* tskLdapTask;
@protected NSPipe* pipeLdapTask;
@protected NSFileHandle* fhLdapTask;
@protected NSMutableData* mdLdapTask;
IBOutlet NSComboBox* comboDomain;
IBOutlet NSComboBox* comboPrinter;
IBOutlet NSComboBox* comboPrintServer;
//end of interface globals
//after collecting the print-server names they are displayed in an according drop-down comboBox
//as soon as the user selects one of the print-servers, we should start a new query to find all the
//print-queues on that server and display them in the comboPrinter drop-down list
//to find the shares/print queues of a windows print-server you need samba and the net -S command like this:
// net -S yourPrintServerName.yourBaseDomain.com -U yourLdapUser%yourLdapUserPassWord -W adm rpc share -l
//which dispalays a long list of the shares
- (IBAction)onSelectDomain:(id)sender
{
static int indexOfLastItem = 0; //unfortunately we need to compare this because we are called also if the selection did not change!
if ([comboDomain indexOfSelectedItem] != indexOfLastItem && ([comboDomain indexOfSelectedItem] != 0))
{
indexOfLastItem = [comboDomain indexOfSelectedItem]; //retain this index for next call
//the print-servers-list has to be loaded on a per univeristy or domain basis from a file dynamically or from AN LDAP-QUERY
//initialize an LDAP-Query-Task or console-command like this one with console output
/*
ldapsearch -LLL -s sub -D "cn=yourLdapUser,ou=yourOuWithLdapUserAccount,dc=yourDomain,dc=com" -h "yourLdapServer.com" -p 3268 -w "yourLdapUserPassWord" -b "dc=yourBaseDomainToSearchIn,dc=com" "(&(objectcategory=computer)(cn=ps*))" "dn"
//our print-server names start with ps* and we want the dn as result, wich comes like this:
dn: CN=PSyourPrintServerName,CN=Computers,DC=yourBaseDomainToSearchIn,DC=com
*/
sLdapQueryCommand = [[NSString alloc] initWithString: @"/usr/bin/ldapsearch"];
if ([[comboDomain stringValue] compare: @"firstDomain"] == NSOrderedSame) {
aLdapQueryArgs = [NSArray arrayWithObjects: @"-LLL",@"-s", @"sub",@"-D", @"cn=yourLdapUser,ou=yourOuWithLdapUserAccount,dc=yourDomain,dc=com",@"-h", @"yourLdapServer.com",@"-p",@"3268",@"-w",@"yourLdapUserPassWord",@"-b",@"dc=yourFirstDomainToSearchIn,dc=com",@"(&(objectcategory=computer)(cn=ps*))",@"dn",nil];
}
else {
aLdapQueryArgs = [NSArray arrayWithObjects: @"-LLL",@"-s", @"sub",@"-D", @"cn=yourLdapUser,ou=yourOuWithLdapUserAccount,dc=yourDomain,dc=com",@"-h", @"yourLdapServer.com",@"-p",@"3268",@"-w",@"yourLdapUserPassWord",@"-b",@"dc=yourSecondDomainToSearchIn,dc=com",@"(&(objectcategory=computer)(cn=ps*))",@"dn",nil];
}
//prepare and execute ldap-query task
tskLdapTask = [[NSTask alloc] init];
pipeLdapTask = [[NSPipe alloc] init];//instead of [NSPipe pipe]
[tskLdapTask setStandardOutput: pipeLdapTask];//hope to get the tasks output in this file/pipe
//The magic line that keeps your log where it belongs, has to do with NSLog (see https://stackoverflow.com/questions/412562/execute-a-terminal-command-from-a-cocoa-app and here http://www.cocoadev.com/index.pl?NSTask)
[tskLdapTask setStandardInput:[NSPipe pipe]];
//fhLdapTask = [[NSFileHandle alloc] init];//would be redundand here, next line seems to do the trick also
fhLdapTask = [pipeLdapTask fileHandleForReading];
mdLdapTask = [NSMutableData dataWithCapacity:512];//prepare capturing the pipe buffer which is flushed on read and can overflow, start with 512 Bytes but it is mutable, so grows dynamically later
[tskLdapTask setLaunchPath: sLdapQueryCommand];
[tskLdapTask setArguments: aLdapQueryArgs];
#ifdef bDoDebug
NSLog (@"sLdapQueryCommand: %@\n", sLdapQueryCommand);
NSLog (@"aLdapQueryArgs: %@\n", aLdapQueryArgs);
NSLog (@"tskLdapTask: %@\n", [tskLdapTask arguments]);
#endif
[tskLdapTask launch];
while ([tskLdapTask isRunning]) {
[mdLdapTask appendData: [fhLdapTask readDataToEndOfFile]];
}
[tskLdapTask waitUntilExit];//might be redundant here.
[mdLdapTask appendData: [fhLdapTask readDataToEndOfFile]];//add another read for safety after process/command stops
NSString* sLdapOutput = [[NSString alloc] initWithData: mdLdapTask encoding: NSUTF8StringEncoding];//convert output to something readable, as NSData and NSMutableData are mere byte buffers
#ifdef bDoDebug
NSLog(@"LdapQueryOutput: %@\n", sLdapOutput);
#endif
//Ok now we have the printservers from Active Directory, lets parse the output and show the list to the user in its combo box
//output is formatted as this, one printserver per line
//dn: CN=PSyourPrintServer,OU=Computers,DC=yourBaseDomainToSearchIn,DC=com
//so we have to search for "dn: CN=" to retrieve each printserver's name
//unfortunately splitting this up will give us a first line containing only "" empty string, which we can replace with the word "choose"
//appearing as first entry in the comboBox
aPrintServers = (NSMutableArray*)[sLdapOutput componentsSeparatedByString:@"dn: CN="];//split output into single lines and store it in the NSMutableArray aPrintServers
#ifdef bDoDebug
NSLog(@"aPrintServers: %@\n", aPrintServers);
#endif
if ([[aPrintServers objectAtIndex: 0 ] compare: @"" options: NSLiteralSearch] == NSOrderedSame){
[aPrintServers replaceObjectAtIndex: 0 withObject: slChoose];//replace with localized string "choose"
#ifdef bDoDebug
NSLog(@"aPrintServers: %@\n", aPrintServers);
#endif
}
//Now comes the tedious part to extract only the print-server-names from the single lines
NSRange r;
NSString* sTemp;
for (int i = 1; i < [aPrintServers count]; i++) {//skip first line with "choose". To get rid of the rest of the line, we must isolate/preserve the print server's name to the delimiting comma and remove all the remaining characters
sTemp = [aPrintServers objectAtIndex: i];
sTemp = [sTemp stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];//remove newlines and line feeds
#ifdef bDoDebug
NSLog(@"sTemp: %@\n", sTemp);
#endif
r = [sTemp rangeOfString: @","];//now find first comma to remove the whole rest of the line
//r.length = [sTemp lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
r.length = [sTemp length] - r.location;//calculate number of chars between first comma found and lenght of string
#ifdef bDoDebug
NSLog(@"range: %i, %i\n", r.location, r.length);
#endif
sTemp = [sTemp stringByReplacingCharactersInRange:r withString: @"" ];//remove rest of line
#ifdef bDoDebug
NSLog(@"sTemp after replace: %@\n", sTemp);
#endif
[aPrintServers replaceObjectAtIndex: i withObject: sTemp];//put back string into array for display in comboBox
#ifdef bDoDebug
NSLog(@"aPrintServer: %@\n", [aPrintServers objectAtIndex: i]);
#endif
}
[comboPrintServer removeAllItems];//reset combo box
[comboPrintServer addItemsWithObjectValues:aPrintServers];
[comboPrintServer setNumberOfVisibleItems:aPrintServers.count];
[comboPrintServer selectItemAtIndex:0];
#ifdef bDoDebug
NSLog(@"comboPrintServer reloaded with new values.");
#endif
//release memory we used for LdapTask
[sLdapQueryCommand release];
[aLdapQueryArgs release];
[sLdapOutput release];
[fhLdapTask release];
[pipeLdapTask release];
// [tskLdapTask release];//strangely can not be explicitely released, might be autorelease anyway
// [mdLdapTask release];//strangely can not be explicitely released, might be autorelease anyway
[sTemp release];
}
}
Ich habe mich selbst über Instanz kommen, wo es nicht genug war, um nur getrennte Zeichenfolge von Komponente viele Aufgaben wie
1) Kategorisieren von Token in Typen
2) Das Hinzufügen von neuen Token
3) Zeichenfolge zwischen benutzerdefinierten Verschlüsse Trennung wie alle Wörter zwischen "{" und "}"
Für solche Anforderungen fand ich Parse Kit ein Lebensretter.
Ich habe es verwendet, um .PGN (prtable Gaming Notation) Dateien erfolgreich zu analysieren, es ist sehr schnell und lite.
Wenn Sie suchen einen String in Suchbegriffe tokenise während „zitierte Sätze“ zu bewahren, ist hier eine NSString
Kategorie, die verschiedene Arten von Kurspaare respektiert: ""
''
‘’
“”
Verbrauch:
NSArray *terms = [@"This is my \"search phrase\" I want to split" searchTerms];
// results in: ["This", "is", "my", "search phrase", "I", "want", "to", "split"]
Code:
@interface NSString (Search)
- (NSArray *)searchTerms;
@end
@implementation NSString (Search)
- (NSArray *)searchTerms {
// Strip whitespace and setup scanner
NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
NSString *searchString = [self stringByTrimmingCharactersInSet:whitespace];
NSScanner *scanner = [NSScanner scannerWithString:searchString];
[scanner setCharactersToBeSkipped:nil]; // we'll handle whitespace ourselves
// A few types of quote pairs to check
NSDictionary *quotePairs = @{@"\"": @"\"",
@"'": @"'",
@"\u2018": @"\u2019",
@"\u201C": @"\u201D"};
// Scan
NSMutableArray *results = [[NSMutableArray alloc] init];
NSString *substring = nil;
while (scanner.scanLocation < searchString.length) {
// Check for quote at beginning of string
unichar unicharacter = [self characterAtIndex:scanner.scanLocation];
NSString *startQuote = [NSString stringWithFormat:@"%C", unicharacter];
NSString *endQuote = [quotePairs objectForKey:startQuote];
if (endQuote != nil) { // if it's a valid start quote we'll have an end quote
// Scan quoted phrase into substring (skipping start & end quotes)
[scanner scanString:startQuote intoString:nil];
[scanner scanUpToString:endQuote intoString:&substring];
[scanner scanString:endQuote intoString:nil];
} else {
// Single word that is non-quoted
[scanner scanUpToCharactersFromSet:whitespace intoString:&substring];
}
// Process and add the substring to results
if (substring) {
substring = [substring stringByTrimmingCharactersInSet:whitespace];
if (substring.length) [results addObject:substring];
}
// Skip to next word
[scanner scanCharactersFromSet:whitespace intoString:nil];
}
// Return non-mutable array
return results.copy;
}
@end
Wenn Sie schauen, zum Spalten von linguistischen Merkmals eines Strings (Wörter, Absätze, Zeichen, Sätze und Zeilen), verwenden String Aufzählung:
NSString * string = @" \n word1! word2,%$?'/word3.word4 ";
[string enumerateSubstringsInRange:NSMakeRange(0, string.length)
options:NSStringEnumerationByWords
usingBlock:
^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
NSLog(@"Substring: '%@'", substring);
}];
// Logs:
// Substring: 'word1'
// Substring: 'word2'
// Substring: 'word3'
// Substring: 'word4'
Diese api mit anderen Sprachen funktioniert, wo Räume sind nicht immer das Trennzeichen (z Japanisch). Auch die Verwendung von NSStringEnumerationByComposedCharacterSequences
ist die richtige Methode zum Aufzählen von Zeichen, da viele nicht-westliche Zeichen mehr als ein Byte lang sind.
- 1. AMF0 Parser in ObjectiveC
- 2. ObjectiveC-Blöcke Java-Äquivalent
- 3. 2D Dynamische Speicherzuweisung - ObjectiveC
- 4. ObjectiveC: Wo private Instanzeigenschaften deklarieren?
- 5. ObjectiveC - wie NSUserNotification Kennung Eigenschaft
- 6. Präsentieren Sie kleine ModalViewController ObjectiveC
- 7. ObjectiveC - Anzeigefenster durch verteilte Objekte
- 8. UIImage codiert in NSData in ObjectiveC und dann in Swift
- 9. ObjectiveC - Freigabe von Objekten als Parameter
- 10. TwitPic API von ObjectiveC/iPhone verwenden
- 11. ObjectiveC UISwitch Standard auf OFF setzen
- 12. Kann ich einen ObjectiveC @selector in ein NSDictionary einfügen?
- 13. Wie Frame von UIView geschachtelt in UIView bekommen - ObjectiveC
- 14. Wie deklarieren und verwenden Sie 3-dimensionale Array in ObjectiveC?
- 15. CALayer.compositingFilter funktioniert auf ObjectiveC aber nicht in swift
- 16. Setzen Sie das Limit auf UITextField in ObjectiveC
- 17. ObjectiveC-Syntax zum Angeben des Protokollnamens im Methodenargument
- 18. Delphi Berlin EObjectiveC mit Meldung ‚ObjectiveC Klasse CTCallCenter konnte nicht
- 19. post BOOL zu JSON mit AFNetworking 3.X ObjectiveC
- 20. Wie konvertiere ich den NSUInteger-Wert in den int-Wert in objectiveC?
- 21. Wie zeichne ich einen Halbkreis in ObjectiveC und Cocoa für MacOS?
- 22. Erstellen Sie eine farbige Blase/Kreis programmgesteuert in ObjectiveC und Cocoa
- 23. UITabBar Auswahl Indikator Bild nimmt nicht die gesamte Größe der TabBar Höhe in ObjectiveC
- 24. Referenzzählung beim Implementieren eines Delegaten für die benutzerdefinierte Klasse in ObjectiveC
- 25. Mit C++ 11 Lambda-Funktionen in ARC ObjectiveC++ - wie es richtig geht?
- 26. Ist das Timing des Aufrufs der Methode der Superklasse in ObjectiveC?
- 27. möchten Counter auf Boxen drucken, wie viele Boxen das Programm druckt. für OS X ObjectiveC
- 28. Darwin und ObjectiveC - Wie ruft man Shell-Skripte aus einer Cocoa-App auf?
- 29. Sind in ObjectiveC Zeiger, bei denen es sich um Klasseninstanzvariablen handelt, die auf 'Null' initialisiert wurden, oder anders?
- 30. Strukturiertes Array in Java
Danke Adam ... :) – mAc
Als Verweis auf zukünftige Leser, möchte ich darauf hinweisen, dass das Gegenteil ist "[anArray componentsJoinedByString: @": "];'. –
Danke, aber wie teilt man einen NSString auf, der durch mehrere Token getrennt ist? (Wenn du weißt, was ich meine, mein Englisch ist nicht sehr gut) @Adam – 11684