26

句読点、スペース、アクセントなどを使用せずに名前を比較しようとしています。現時点では、次のことを行っています。

-(NSString*) prepareString:(NSString*)a {
    //remove any accents and punctuation;
    a=[[[NSString alloc] initWithData:[a dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES] encoding:NSASCIIStringEncoding] autorelease];

    a=[a stringByReplacingOccurrencesOfString:@" " withString:@""];
    a=[a stringByReplacingOccurrencesOfString:@"'" withString:@""];
    a=[a stringByReplacingOccurrencesOfString:@"`" withString:@""];
    a=[a stringByReplacingOccurrencesOfString:@"-" withString:@""];
    a=[a stringByReplacingOccurrencesOfString:@"_" withString:@""];
    a=[a lowercaseString];
    return a;
}

ただし、何百もの文字列に対してこれを行う必要があり、これをより効率的にする必要があります。何か案は?

4

13 に答える 13

81
NSString* finish = [[start componentsSeparatedByCharactersInSet:[[NSCharacterSet letterCharacterSet] invertedSet]] componentsJoinedByString:@""];
于 2009-08-05T08:54:40.117 に答える
39

decomposedStringWithCanonicalMappingこれらのソリューションを使用する前に、 を使用してアクセント付きの文字を分解することを忘れないでください。これにより、たとえば、é (U+00E9) が e ́ (U+0065 U+0301) に変わります。次に、英数字以外の文字を取り除くと、アクセントのない文字が残ります。

これが重要な理由は、たとえば「dän」と「dün」* を同じものとして扱いたくないからです。これらの解決策の一部のように、アクセント付きの文字をすべて削除すると、最終的に「dn」になるため、これらの文字列は等しいものとして比較されます。

したがって、アクセントを取り除いて文字を残すことができるように、最初にそれらを分解する必要があります。

*ドイツ語の例。提供してくれた Joris Weimar に感謝します。

于 2009-08-05T15:46:14.710 に答える
7

BillyTheKid18756 の回答に対する 1 つの重要な精度 (これは Luiz によって修正されましたが、コードの説明では明らかではありませんでした):

アクセントを削除するための 2 番目のステップとして使用 stringWithCStringしないでください。NSData は NULL で終了していないため (stringWithCString が期待するように)、文字列の末尾に不要な文字が追加される可能性があります。または、Luiz がコードで行ったように、それを使用して NSData に追加の NULL バイトを追加します。

より簡単な答えは、次のものを置き換えることだと思います:

NSString *sanitizedText = [NSString stringWithCString:[sanitizedData bytes] encoding:NSASCIIStringEncoding];

に:

NSString *sanitizedText = [[[NSString alloc] initWithData:sanitizedData encoding:NSASCIIStringEncoding] autorelease];

BillyTheKid18756 のコードを取り戻すと、完全に正しいコードは次のようになります。

// The input text
NSString *text = @"BûvérÈ!@$&%^&(*^(_()-*/48";

// Defining what characters to accept
NSMutableCharacterSet *acceptedCharacters = [[NSMutableCharacterSet alloc] init];
[acceptedCharacters formUnionWithCharacterSet:[NSCharacterSet letterCharacterSet]];
[acceptedCharacters formUnionWithCharacterSet:[NSCharacterSet decimalDigitCharacterSet]];
[acceptedCharacters addCharactersInString:@" _-.!"];

// Turn accented letters into normal letters (optional)
NSData *sanitizedData = [text dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
// Corrected back-conversion from NSData to NSString
NSString *sanitizedText = [[[NSString alloc] initWithData:sanitizedData encoding:NSASCIIStringEncoding] autorelease];

// Removing unaccepted characters
NSString* output = [[sanitizedText componentsSeparatedByCharactersInSet:[acceptedCharacters invertedSet]] componentsJoinedByString:@""];
于 2012-07-26T10:29:16.330 に答える
4

LuizとPeterの回答を組み合わせ、数行追加して完全な例を示すと、次のコードが得られます。

コードは次のことを行います。

  1. 受け入れられた文字のセットを作成します
  2. アクセント文字を通常の文字に変換します
  3. セットにない文字を削除する

Objective-C

// The input text
NSString *text = @"BûvérÈ!@$&%^&(*^(_()-*/48";

// Create set of accepted characters
NSMutableCharacterSet *acceptedCharacters = [[NSMutableCharacterSet alloc] init];
[acceptedCharacters formUnionWithCharacterSet:[NSCharacterSet letterCharacterSet]];
[acceptedCharacters formUnionWithCharacterSet:[NSCharacterSet decimalDigitCharacterSet]];
[acceptedCharacters addCharactersInString:@" _-.!"];

// Turn accented letters into normal letters (optional)
NSData *sanitizedData = [text dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *sanitizedText = [NSString stringWithCString:[sanitizedData bytes] encoding:NSASCIIStringEncoding];

// Remove characters not in the set
NSString* output = [[sanitizedText componentsSeparatedByCharactersInSet:[acceptedCharacters invertedSet]] componentsJoinedByString:@""];

Swift(2.2)の例

let text = "BûvérÈ!@$&%^&(*^(_()-*/48"

// Create set of accepted characters
let acceptedCharacters = NSMutableCharacterSet()
acceptedCharacters.formUnionWithCharacterSet(NSCharacterSet.letterCharacterSet())
acceptedCharacters.formUnionWithCharacterSet(NSCharacterSet.decimalDigitCharacterSet())
acceptedCharacters.addCharactersInString(" _-.!")

// Turn accented letters into normal letters (optional)
let sanitizedData = text.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: true)
let sanitizedText = String(data: sanitizedData!, encoding: NSASCIIStringEncoding)

// Remove characters not in the set
let components = sanitizedText!.componentsSeparatedByCharactersInSet(acceptedCharacters.invertedSet)
let output = components.joinWithSeparator("")

出力

両方の例の出力は次のようになります:BuverE!_-48

于 2012-02-15T11:48:38.777 に答える
4

RegexKit フレームワークの使用を検討してください。次のようなことができます。

NSString *searchString      = @"This is neat.";
NSString *regexString       = @"[\W]";
NSString *replaceWithString = @"";
NSString *replacedString    = [searchString stringByReplacingOccurrencesOfRegex:regexString withString:replaceWithString];

NSLog (@"%@", replacedString);
//... Thisisneat
于 2009-08-05T08:12:39.390 に答える
4

NSScanner、具体的には-setCharactersToBeSkipped:(NSCharacterSet を受け入れる) メソッドと-scanString:intoString:(文字列を受け入れ、参照によってスキャンされた文字列を返す) メソッドの使用を検討してください。

これを-[NSString localizedCompare:]、またはおそらくNSDiacriticInsensitiveSearchオプション-[NSString compare:options:]と組み合わせることもできます。これにより、アクセントの削除/置換が簡単になるため、句読点や空白などの削除に集中できます。

質問で提示したようなアプローチを使用する必要がある場合は、少なくとも NSMutableString を使用してください。これreplaceOccurrencesOfString:withString:options:range:は、ほぼ同一の自動解放された文字列を大量に作成するよりもはるかに効率的です。割り当ての数を減らすだけで、当面は「十分に」パフォーマンスが向上する可能性があります。

于 2009-08-05T13:51:31.470 に答える
1
@interface NSString (Filtering)
    - (NSString*)stringByFilteringCharacters:(NSCharacterSet*)charSet;
@end

@implementation NSString (Filtering)
    - (NSString*)stringByFilteringCharacters:(NSCharacterSet*)charSet {
      NSMutableString * mutString = [NSMutableString stringWithCapacity:[self length]];
      for (int i = 0; i < [self length]; i++){
        char c = [self characterAtIndex:i];
        if(![charSet characterIsMember:c]) [mutString appendFormat:@"%c", c];
      }
      return [NSString stringWithString:mutString];
    }
@end
于 2012-11-19T19:27:36.583 に答える
0

Swift での Peter のソリューション:

let newString = oldString.componentsSeparatedByCharactersInSet(NSCharacterSet.letterCharacterSet().invertedSet).joinWithSeparator("")

例:

let oldString = "Jo_ - h !. nn y"
// "Jo_ - h !. nn y"
oldString.componentsSeparatedByCharactersInSet(NSCharacterSet.letterCharacterSet().invertedSet)
// ["Jo", "h", "nn", "y"]
oldString.componentsSeparatedByCharactersInSet(NSCharacterSet.letterCharacterSet().invertedSet).joinWithSeparator("")
// "Johnny"
于 2016-03-27T12:08:29.587 に答える
-1

文字と数字以外のすべてをフィルターで除外したかったので、Lorean の NSString でのカテゴリーの実装を少し異なる動作に適応させました。この例では、保持したい文字のみを含む文字列を指定しており、それ以外はすべて除外されています。

@interface NSString (PraxCategories)
+ (NSString *)lettersAndNumbers;
- (NSString*)stringByKeepingOnlyLettersAndNumbers;
- (NSString*)stringByKeepingOnlyCharactersInString:(NSString *)string;
@end


@implementation NSString (PraxCategories)

+ (NSString *)lettersAndNumbers { return @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; }

- (NSString*)stringByKeepingOnlyLettersAndNumbers {
    return [self stringByKeepingOnlyCharactersInString:[NSString lettersAndNumbers]];
}

- (NSString*)stringByKeepingOnlyCharactersInString:(NSString *)string {
    NSCharacterSet *characterSet = [NSCharacterSet characterSetWithCharactersInString:string];
    NSMutableString * mutableString = @"".mutableCopy;
    for (int i = 0; i < [self length]; i++){
        char character = [self characterAtIndex:i];
        if([characterSet characterIsMember:character]) [mutableString appendFormat:@"%c", character];
    }
    return mutableString.copy;
}

@end

カテゴリを作成したら、それらを使用するのは簡単で、任意のNSStringで使用できます。

NSString *string = someStringValueThatYouWantToFilter;

string = [string stringByKeepingOnlyLettersAndNumbers];

または、たとえば、母音以外のすべてを取り除きたい場合:

string = [string stringByKeepingOnlyCharactersInString:@"aeiouAEIOU"];

まだ Objective-C を学習中で、カテゴリを使用していない場合は、試してみることをお勧めします。これらは、分類するクラスのすべてのオブジェクトにより多くの機能を提供するため、このようなものを配置するのに最適な場所です。

カテゴリは、追加するコードを簡素化してカプセル化するため、すべてのプロジェクトで簡単に再利用できます。これは、Objective-C の優れた機能です。

于 2015-01-10T05:03:40.390 に答える