Objective-C에서 NSString 토큰 화
Objective-C에서 NSString을 토큰 화 / 분할하는 가장 좋은 방법은 무엇입니까?
http://borkware.com/quickies/one?topic=NSString (유용한 링크) 에서이를 발견했습니다 .
NSString *string = @"oop:ack:bork:greeble:ponies";
NSArray *chunks = [string componentsSeparatedByString: @":"];
도움이 되었기를 바랍니다!
아담
모든 사람들이 언급 componentsSeparatedByString:
했지만 자연어를 토큰 화 CFStringTokenizer
하는 ( NSString
및 CFString
공백으로 단어를 나누지 않는 중국어 / 일본어와 같이) 상호 교환도 가능합니다.
문자열을 나누려면을 사용하십시오 -[NSString componentsSeparatedByString:]
. 보다 복잡한 토큰 화를 위해서는 NSScanner 클래스를 사용하십시오.
토큰 화가 더 복잡하다면 오픈 소스 Cocoa String 토큰 화 / 파싱 툴킷 ParseKit을 확인하십시오.
구분 문자 (예 : ':')를 사용하여 문자열을 간단하게 분할하려면 ParseKit이 과도하게 사용됩니다. 그러나 복잡한 토큰 화 요구에 대해 ParseKit은 매우 강력하고 유연합니다.
ParseKit 토큰 화 문서 도 참조하십시오 .
여러 문자를 토큰 화하려면 NSString을 사용할 수 있습니다 componentsSeparatedByCharactersInSet
. NSCharacterSet에는 whitespaceCharacterSet
and와 같은 편리한 사전 제작 세트 가 illegalCharacterSet
있습니다. 그리고 유니 코드 범위의 이니셜 라이저가 있습니다.
다음과 같이 문자 세트를 결합하고이를 사용하여 토큰화할 수도 있습니다.
// Tokenize sSourceEntityName on both whitespace and punctuation.
NSMutableCharacterSet *mcharsetWhitePunc = [[NSCharacterSet whitespaceAndNewlineCharacterSet] mutableCopy];
[mcharsetWhitePunc formUnionWithCharacterSet:[NSCharacterSet punctuationCharacterSet]];
NSArray *sarrTokenizedName = [self.sSourceEntityName componentsSeparatedByCharactersInSet:mcharsetWhitePunc];
[mcharsetWhitePunc release];
그주의 componentsSeparatedByCharactersInSet
는 행에서 charset 하나 명 이상의 멤버가 발생할 경우 1보다 작은 길이를 테스트 할 수 있습니다, 그래서 빈 문자열을 생성합니다.
"인용구"를 유지하면서 문자열을 검색어로 토큰 화하려는 경우 NSString
다양한 유형의 따옴표 쌍을 존중 하는 범주는 다음과 같습니다.""
''
‘’
“”
용법:
NSArray *terms = [@"This is my \"search phrase\" I want to split" searchTerms];
// results in: ["This", "is", "my", "search phrase", "I", "want", "to", "split"]
암호:
@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
언어 적 특징의 문자열 (단어, 단락, 문자, 문장 및 줄)을 분할하려면 문자열 열거를 사용하십시오.
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'
이 API는 공백이 항상 분리 문자가 아닌 다른 언어 (예 : 일본어)와 함께 작동합니다. NSStringEnumerationByComposedCharacterSequences
많은 비 서부 문자는 1 바이트 이상이므로 문자를 열거하는 올바른 방법 도 사용 합니다.
ldapsearch를 사용하여 LDAP 쿼리 후 콘솔 출력을 분할 해야하는 경우가있었습니다. 먼저 NSTask를 설정하고 실행하십시오 (여기에서 좋은 코드 샘플을 찾았습니다 : Cocoa app에서 터미널 명령 실행 ). 그러나 Ldap-query-output에서 인쇄 서버 이름 만 추출하기 위해 출력을 분할하고 구문 분석해야했습니다. 불행히도 간단한 C- 배열 연산으로 C- 문자열 / 배열을 조작한다면 전혀 문제가되지 않는 문자열 조작이 문제가되지 않습니다. 여기에 코코아 객체를 사용하는 코드가 있습니다. 더 나은 제안이 있으면 알려주세요.
//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];
}
}
I have my self come across instance where it was not enough to just separate string by component many tasks such as
1) Categorizing token into types
2) Adding new tokens
3)Separating string between custom closures like all words between "{" and "}"
For any such requirements i found Parse Kit a life saver.
I used it to parse .PGN (prtable gaming notation) files successfully its very fast and lite.
참고URL : https://stackoverflow.com/questions/259956/nsstring-tokenize-in-objective-c
'programing tip' 카테고리의 다른 글
SecureString을 System.String로 변환하는 방법? (0) | 2020.06.16 |
---|---|
C에서 "콜백"이란 무엇이며 어떻게 구현됩니까? (0) | 2020.06.16 |
가운데 맞춤을 어떻게 중앙 정렬 (0) | 2020.06.15 |
Java의 디렉토리에 파일을 만드는 방법은 무엇입니까? (0) | 2020.06.15 |
순수한 가상 함수가 0으로 초기화되는 이유는 무엇입니까? (0) | 2020.06.15 |