tildes remover reemplazar quitar leer especiales eliminar caracteres acentos objective-c regex cocoa string nsstring

objective-c - remover - reemplazar ñ y acentos java



NSString-Convierte al alfabeto puro solamente(es decir, elimina acentos+puntuación) (13)

Acabo de tropezar con esto, tal vez es demasiado tarde, pero esto es lo que funcionó para mí:

// text is the input string, and this just removes accents from the letters // lossy encoding turns accented letters into normal letters NSMutableData *sanitizedData = [text dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; // increase length by 1 adds a 0 byte (increaseLengthBy // guarantees to fill the new space with 0s), effectively turning // sanitizedData into a c-string [sanitizedData increaseLengthBy:1]; // now we just create a string with the c-string in sanitizedData NSString *final = [NSString stringWithCString:[sanitizedData bytes]];

Estoy tratando de comparar nombres sin ningún tipo de puntuación, espacios, acentos, etc. En este momento estoy haciendo lo siguiente:

-(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; }

Sin embargo, necesito hacer esto por cientos de cadenas y necesito hacerlo más eficiente. ¿Algunas ideas?


Antes de utilizar cualquiera de estas soluciones, no olvide utilizar decomposedStringWithCanonicalMapping para descomponer las letras acentuadas. Esto cambiará, por ejemplo, é (U + 00E9) en e (U + 0065 U + 0301). Luego, cuando elimine los caracteres no alfanuméricos, las letras sin acentos permanecerán.

La razón por la que esto es importante es que probablemente no desee, por ejemplo, "dän" y "dün" * que se le trate de la misma manera. Si eliminaste todas las letras acentuadas, como algunas de estas soluciones pueden hacer, terminarás con "dn", por lo que esas cuerdas se compararán como iguales.

Entonces, debe descomponerlos primero, para poder quitar los acentos y dejar las letras.

* Ejemplo de alemán. Gracias a Joris Weimar por proporcionarlo.


Considere usar NSScanner , y específicamente los métodos -setCharactersToBeSkipped: (que acepta un NSCharacterSet) y -scanString:intoString: (que acepta una cadena y devuelve la cadena escaneada por referencia).

También puede emparejar esto con -[NSString localizedCompare:] , o quizás -[NSString compare:options:] con la opción NSDiacriticInsensitiveSearch . Eso podría simplificar tener que eliminar / reemplazar acentos, para que pueda concentrarse en eliminar la punción, el espacio en blanco, etc.

Si debe usar un enfoque como el que presentó en su pregunta, al menos use un NSMutableString y replaceOccurrencesOfString:withString:options:range: - eso será mucho más eficiente que crear toneladas de cadenas autoreleased casi idénticas. Podría ser que simplemente reduciendo el número de asignaciones aumentará el rendimiento "suficiente" por el momento.


Considere usar el marco RegexKit . Podrías hacer algo como:

NSString *searchString = @"This is neat."; NSString *regexString = @"[/W]"; NSString *replaceWithString = @""; NSString *replacedString = [searchString stringByReplacingOccurrencesOfRegex:regexString withString:replaceWithString]; NSLog (@"%@", replacedString); //... Thisisneat


Estas respuestas no funcionaron como se esperaba. Específicamente, decomposedStringWithCanonicalMapping no quitó acentos / diéresis como esperaba.

Aquí hay una variación de lo que utilicé que responde al breve:

// replace accents, umlauts etc with equivalent letter i.e ''é'' becomes ''e''. // Always use en_GB (or a locale without the characters you wish to strip) as locale, no matter which language we''re taking as input NSString *processedString = [string stringByFoldingWithOptions: NSDiacriticInsensitiveSearch locale: [NSLocale localeWithLocaleIdentifier: @"en_GB"]]; // remove non-letters processedString = [[processedString componentsSeparatedByCharactersInSet:[[NSCharacterSet letterCharacterSet] invertedSet]] componentsJoinedByString:@""]; // trim whitespace processedString = [processedString stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]]; return processedString;


La solución de Peter en Swift:

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

Ejemplo:

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"


Para dar un ejemplo completo combinando las respuestas de Luiz y Peter, agregando unas líneas, obtienes el código a continuación.

El código hace lo siguiente:

  1. Crea un conjunto de caracteres aceptados
  2. Convierta las letras acentuadas en letras normales
  3. Eliminar caracteres que no están en el conjunto

C objetivo

// 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:@""];

Ejemplo de 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("")

Salida

El resultado para ambos ejemplos sería: BuverE! _- 48


Quería filtrar todo, excepto letras y números, así que adapté la implementación de Lorean de una Categoría en NSString para que funcionara un poco diferente. En este ejemplo, especifica una cadena con solo los caracteres que desea conservar y todo lo demás se filtra:

@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

Una vez que haya creado sus Categorías, usarlas es trivial y puede usarlas en cualquier NSString:

NSString *string = someStringValueThatYouWantToFilter; string = [string stringByKeepingOnlyLettersAndNumbers];

O, por ejemplo, si desea deshacerse de todo, excepto las vocales:

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

Si todavía estás aprendiendo Objective-C y no estás usando Categorías, te animo a probarlas. Son el mejor lugar para poner cosas como esta porque le da más funcionalidad a todos los objetos de la clase que categoriza.

Las categorías simplifican y encapsulan el código que está agregando, lo que facilita su reutilización en todos sus proyectos. ¡Es una gran característica de Objective-C!


Si está intentando comparar cadenas, use uno de estos métodos. No intentes cambiar los datos.

- (NSComparisonResult)localizedCompare:(NSString *)aString - (NSComparisonResult)localizedCaseInsensitiveCompare:(NSString *)aString - (NSComparisonResult)compare:(NSString *)aString options:(NSStringCompareOptions)mask range:(NSRange)range locale:(id)locale

NECESITA considerar la configuración regional del usuario para escribir cosas con cadenas, particularmente cosas como nombres. En la mayoría de los idiomas, los caracteres como ä y å no son lo mismo, aparte de que se ven similares. Son caracteres intrínsecamente distintos con un significado distinto de los demás, pero las reglas y la semántica reales son distintas para cada localidad.

La forma correcta de comparar y ordenar cadenas es teniendo en cuenta la configuración regional del usuario. Cualquier otra cosa es ingenua, equivocada y muy 1990. Deja de hacerlo.

Si está tratando de pasar datos a un sistema que no admite ASCII, bueno, esto es simplemente una acción incorrecta. Pásalo como blobs de datos.

https://developer.apple.com/library/ios/documentation/cocoa/Conceptual/Strings/Articles/SearchingStrings.html

Además de normalizar tus cadenas primero (mira la publicación de Peter Hosey) precompuestas o descompuestas, básicamente, elige una forma normalizada.

- (NSString *)decomposedStringWithCanonicalMapping - (NSString *)decomposedStringWithCompatibilityMapping - (NSString *)precomposedStringWithCanonicalMapping - (NSString *)precomposedStringWithCompatibilityMapping

No, no es tan simple y fácil como tendemos a pensar. Sí, requiere una toma de decisiones informada y cuidadosa. (y un poco de experiencia en el idioma no inglés ayuda)


Una precisión importante sobre la respuesta de BillyTheKid18756 (que fue corregida por Luiz pero no fue obvia en la explicación del código):

NO USE stringWithCString como segundo paso para eliminar acentos, puede agregar caracteres no deseados al final de la cadena ya que NSData no tiene terminación NULL (como lo espera stringWithCString). O úsalo y agrega un byte NULL adicional a tu NSData, como lo hizo Luiz en su código.

Creo que una respuesta más simple es reemplazar:

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

Por:

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

Si recupero el código de BillyTheKid18756, aquí está el código correcto completo:

// 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:@""];


En una pregunta similar, Ole Begemann sugiere usar stringByFoldingWithOptions: y creo que esta es la mejor solución aquí:

NSString *accentedString = @"ÁlgeBra"; NSString *unaccentedString = [accentedString stringByFoldingWithOptions:NSDiacriticInsensitiveSearch locale:[NSLocale currentLocale]];

Dependiendo de la naturaleza de las cadenas que desea convertir, es posible que desee establecer una configuración regional fija (por ejemplo, inglés) en lugar de utilizar la configuración regional actual del usuario. De esta forma, puede estar seguro de obtener los mismos resultados en todas las máquinas.


@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


NSString* finish = [[start componentsSeparatedByCharactersInSet:[[NSCharacterSet letterCharacterSet] invertedSet]] componentsJoinedByString:@""];