2010-04-16 26 views
5

Me gusta reemplazar cierto conjunto de caracteres de una cadena con un carácter de reemplazo correspondiente de una manera eficiente.Cómo reemplazar caracteres en una cadena java?

Por ejemplo:

String sourceCharacters = "šđćčŠĐĆČžŽ"; 
String targetCharacters = "sdccSDCCzZ"; 

String result = replaceChars("Gračišće", sourceCharacters , targetCharacters); 

Assert.equals(result,"Gracisce") == true; 

es que hay manera más eficiente que usar el método de la clase String replaceAll?

Mi primera idea era:

final String s = "Gračišće"; 
String sourceCharacters = "šđćčŠĐĆČžŽ"; 
String targetCharacters = "sdccSDCCzZ"; 

// preparation 
final char[] sourceString = s.toCharArray(); 
final char result[] = new char[sourceString.length]; 
final char[] targetCharactersArray = targetCharacters.toCharArray(); 

// main work 
for(int i=0,l=sourceString.length;i<l;++i) 
{ 
    final int pos = sourceCharacters.indexOf(sourceString[i]); 
    result[i] = pos!=-1 ? targetCharactersArray[pos] : sourceString[i]; 
} 

// result 
String resultString = new String(result); 

¿Alguna idea?

Por cierto, los caracteres UTF-8 están causando el problema, con US_ASCII funciona bien.

Respuesta

14

Puede hacer uso de java.text.Normalizer y un tiro de expresiones regulares para deshacerse de la diacritics de los cuales existen mucho más de lo que han recogido en la medida.

He aquí un SSCCE, copy'n'paste'n'run en Java 6:

package com.stackoverflow.q2653739; 

import java.text.Normalizer; 
import java.text.Normalizer.Form; 

public class Test { 

    public static void main(String... args) { 
     System.out.println(removeDiacriticalMarks("Gračišće")); 
    } 

    public static String removeDiacriticalMarks(String string) { 
     return Normalizer.normalize(string, Form.NFD) 
      .replaceAll("\\p{InCombiningDiacriticalMarks}+", ""); 
    } 
} 

Esto debería producir

Gracisce

Al menos, lo hace aquí en Eclipse con carácter consola codificación establecida en UTF-8 (Ventana> Preferencias> General> Espacio de trabajo> Codificación de archivo de texto). Asegúrese de que también se establezca lo mismo en su entorno.

Como alternativa, mantienen una Map<Character, Character>:

Map<Character, Character> charReplacementMap = new HashMap<Character, Character>(); 
charReplacementMap.put('š', 's'); 
charReplacementMap.put('đ', 'd'); 
// Put more here. 

String originalString = "Gračišće"; 
StringBuilder builder = new StringBuilder(); 

for (char currentChar : originalString.toCharArray()) { 
    Character replacementChar = charReplacementMap.get(currentChar); 
    builder.append(replacementChar != null ? replacementChar : currentChar); 
} 

String newString = builder.toString(); 
+0

con esta solución me sale: GraA? IA¡Ae. y, por cierto, me gustaría reemplazar no solo los caracteres diacríticos sino también otros de otros idiomas. entonces realmente me gustaría saber una solución que funcione para un mapeo arbitrario. – ManBugra

+1

Exactamente. El problema es que los signos diacríticos a veces se combinan, a veces no, y el reemplazo cadena por carácter se confunde porque en realidad hay dos personajes, no uno. –

+0

@Mr. Brillante y nuevo: sí, System.out.println ("š" .toCharArray(). Length); salidas '2' – ManBugra

0

me gustaría usar el método replace en un bucle simple.

String sourceCharacters = "šđćčŠĐĆČžŽ"; 
String targetCharacters = "sdccSDCCzZ"; 

String s = "Gračišće"; 
for (int i=0 ; i<sourceCharacters.length() ; i++) 
    s = s.replace(sourceCharacters.charAt[i], targetCharacters.charAt[i]); 

System.out.println(s); 
+0

cada iteración crearía un nuevo objeto de cadena.sería bueno hacerlo 'en su lugar' – ManBugra

+0

En primer lugar, cada iteración solo crea un nuevo objeto si se realiza un cambio; si el personaje que se busca no está allí, se devuelve el objeto original. En segundo lugar, es * mucho * más molesto escribir este código usando 'StringBuilder' o' StringBuffer' ya que tienes que hacer todo el trabajo tú mismo; dado que la administración de memoria de Java está ajustada para la rotación rápida de objetos de todos modos, es más fácil hacerlo de la manera que lo demostré en lugar de tratar de descubrir cómo ser eficiente. Siempre puede optimizar más adelante si es realmente necesario (es decir, si se trata de un cuello de botella real). –

+0

sí, tienes razón en tu primer punto. pero no estoy de acuerdo con tu segundo. escribes código eficiente una vez, incluso es molesto, y luego lo vuelves a usar. de todos modos, BalusC resolvió el enigma. – ManBugra

Cuestiones relacionadas