Jaki jest najlepszy sposób na tokenize/split NSString w Objective-C?NSString tokenize w Objective-C
Odpowiedz
Znalazłem to na http://borkware.com/quickies/one?topic=NSString (użyteczny link):
NSString *string = @"oop:ack:bork:greeble:ponies";
NSArray *chunks = [string componentsSeparatedByString: @":"];
Nadzieja to pomaga!
Adam
Jeśli chcesz po prostu podzielić ciąg, użyj -[NSString componentsSeparatedByString:]
. Aby uzyskać bardziej złożoną tokenizację, użyj klasy NSScanner.
Jeśli Twoje potrzeby tokenizacja są bardziej skomplikowane, sprawdź moje open source kakao String tokenizing/parsowania zestaw narzędzi: ParseKit:
Do prostego podziału ciągów wykorzystujących char ogranicznika (jak ':') , ParseKit z pewnością będzie przesadą. Ale znowu, dla złożonych potrzeb tokenizacji, ParseKit jest niezwykle potężny/elastyczny.
Zobacz także ParseKit Tokenization documentation.
Czy to nadal działa? Próbowałem i dostałem kilka błędów, których nie jestem w stanie naprawić. – griotspeak
-1 czy ta odpowiedź wciąż żyje? –
Hm? Żywy? Projekt ParseKit jest aktywnie utrzymywany, tak. Jednak komentarze tutaj nie są właściwym miejscem do zgłaszania błędów w projekcie. Jest on dostępny zarówno w Google Code, jak i Github, jeśli chcesz zgłosić błędy. –
Każdy wspomniał componentsSeparatedByString:
ale można również użyć CFStringTokenizer
(należy pamiętać, że NSString
i CFString
są wymienne), które będą zbyt tokenize języków naturalnych (takich jak chiński/japoński które nie podzielić słowa na spacjami).
A w Mac OS X 10.6 i nowszych, NSString ma metody 'enumerateLinesUsingBlock:' i 'enumerateSubstringsInRange: options: usingBlock:', z których ostatni jest blokiem wersja 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: –
Metody "wyliczenia" są dostępne w iOS 4 i później. – bugloaf
Jeśli chcesz tokenize na wielu znakach, możesz użyć NSString componentsSeparatedByCharactersInSet
. NSCharacterSet ma kilka poręcznych gotowych zestawów, takich jak whitespaceCharacterSet
i illegalCharacterSet
. I ma inicjalizatory dla zakresów Unicode.
Można również łączyć zestawy znaków i używać ich do tokenize, tak:
// Tokenize sSourceEntityName on both whitespace and punctuation.
NSMutableCharacterSet *mcharsetWhitePunc = [[NSCharacterSet whitespaceAndNewlineCharacterSet] mutableCopy];
[mcharsetWhitePunc formUnionWithCharacterSet:[NSCharacterSet punctuationCharacterSet]];
NSArray *sarrTokenizedName = [self.sSourceEntityName componentsSeparatedByCharactersInSet:mcharsetWhitePunc];
[mcharsetWhitePunc release];
Należy pamiętać, że componentsSeparatedByCharactersInSet
będzie produkować puste struny, jeśli napotka więcej niż jednego członka charset w rzędzie, więc może chcieć przetestować dla długości mniejszej niż 1.
Miałem przypadek, w którym musiałem podzielić wyniki konsoli po zapytaniu LDAP z ldapsearch. Najpierw skonfiguruj i wykonaj NSTask (znalazłem tutaj dobry przykład kodu: Execute a terminal command from a Cocoa app). Ale wtedy musiałem podzielić i przeanalizować dane wyjściowe, aby wyodrębnić tylko nazwy serwerów wydruku z wyjścia zapytania Ldap. Niestety jest to dość żmudne manipulowanie strunami, co nie byłoby problemem, gdybyśmy mieli manipulować ciągami/tablicami C za pomocą prostych operacji macierzy C. Więc oto mój kod używa obiektów kakaowych. Jeśli masz lepsze sugestie, daj mi znać.
//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];
}
}
Mam własny natknąć przypadku, gdy to nie wystarczyło, aby po prostu osobny ciąg przez składowe wielu zadań, takich jak
1) kategoryzacji znak na typy
2) Dodanie nowych żetonów
3) oddzielenie ciąg między niestandardowymi zamknięć jak wszystkie słowa między "{" i "}"
Dla każdego takiego wymagania znalazłem Parse Kit ratownika.
Użyłem go do parsowania .PGN (pliki z zapisem gier) z powodzeniem jest bardzo szybki i lite.
Jeśli szukasz tokenise ciąg do wyszukiwanych haseł, przy jednoczesnym zachowaniu „cytowane zwroty”, oto kategoria NSString
że szanuje różne typy par Cytat: ""
''
‘’
“”
Zastosowanie:
NSArray *terms = [@"This is my \"search phrase\" I want to split" searchTerms];
// results in: ["This", "is", "my", "search phrase", "I", "want", "to", "split"]
Kod:
@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
Jeśli szukasz do łupania językowa funkcja jest z ciągu (wyrazy, akapity, zdania, znaki i linie), należy użyć ciąg wyliczenie:
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'
tego API współpracuje z innych języków, gdzie nie zawsze obowiązuje separator (np Język japoński). Również używanie NSStringEnumerationByComposedCharacterSequences
jest właściwym sposobem na wyliczanie znaków, ponieważ wiele nie-zachodnich znaków ma więcej niż jeden bajt.
- 1. Wdrożenie ObjectiveC protokół w szybkim
- 2. tokenize ciąg w C++
- 3. Tablica bajtów Tokenize
- 4. Problemy z tokenize
- 5. tokenize string zachowujący ograniczniki w Pythonie
- 6. Tokenize ciąg znaków i ograniczniki w C++
- 7. W XSLT mogę tokenize na nic?
- 8. ObjectiveC Parse Integer from String
- 9. ObjectiveC: gdzie zadeklarować prywatne właściwości instancji?
- 10. Wyszukiwanie NSString w NSSet
- 11. NSString w UIWebview
- 12. Zastąp znaki w NSString
- 13. Pozycja podłańcucha w NSString
- 14. Jak dołączyć NSString do innego NSString
- 15. Jak uzyskać jedną znak NSString z NSString
- 16. W ObjectiveC są to wskaźniki będące instancyjnymi zmiennymi instancji inicjowanymi jako "zero" lub w inny sposób?
- 17. Składnia ObjectiveC do określania nazwy protokołu w argumencie Metoda Argumenty
- 18. Czy czas wywołania metody super klasy jest ważny w ObjectiveC?
- 19. Global NSString
- 20. NSString parsowania
- 21. Drukowanie NSString
- 22. Jak korzystać arrayWithContentsOfFile załadować plik z powodzeniem napisane z WriteToFile w ObjectiveC/XCode
- 23. Jak zmienić NSString w NSDate?
- 24. Zobacz długość NSString w debugerze
- 25. Liczba wystąpień znaku w NSString
- 26. Wykryj adres URL w NSString
- 27. Automatyczne przekształcanie NSString w NSLocalizedString?
- 28. usunięcia znaków specjalnych w NSString
- 29. Wyszukiwanie podciągu w obiekcie NSString
- 30. Zadeklaruj NSString w wielu liniach
Dzięki Adam ... :) – mAc
W odniesieniu do przyszłych czytelników, chciałbym zauważyć, że przeciwieństwem jest "[anArray componentsJoinedByString: @": "];". –
dziękuję, ale jak podzielić NSString, który jest oddzielony przez więcej tokenów? (Jeśli wiesz, co mam na myśli, mój angielski nie jest zbyt dobry) @Adam – 11684