2010-03-15 46 views
9

Estoy tratando de convertir la primera letra de una cadena a minúscula.¿Reemplazar la primera letra de una cadena en Java?

value.substring(0,1).toLowerCase() + value.substring(1) 

Esto funciona, pero ¿hay formas mejores de hacerlo?

Podría utilizar una función de reemplazo, pero el reemplazo de Java no acepta un índice. Tienes que pasar el personaje/subcadena real. Se podría hacer de esta manera:

value.replaceFirst(value.charAt(0), value.charAt(0).toLowerCase()) 

Excepto que espera replaceFirst 2 cadenas, por lo que los value.charAt(0) s probablemente tendría que ser reemplazado con value.substring(0,1).

¿Hay alguna manera estándar de reemplazar la primera letra de un String?

+1

Verificar StringUtils: http://commons.apache.org/lang/api-2.3/org/apache/commons/lang/StringUtils.html – Trick

Respuesta

12

Le sugiero que eche un vistazo a la biblioteca Commons-Lang de Apache. Tienen una clase

StringUtils 

que le permite realizar muchas tareas con Strings. En su caso sólo tiene que utilizar

StringUtils.uncapitalize(value) 

read here about uncapitalize, así como sobre otras funcionalidades de la clase sugirió

Agregado: mi experiencia dice que coomon-Lang es bastante bueno optimizado, por lo que si quieren saber lo que es mejor desde el punto de vista algorítmico, podría echar un vistazo a su fuente de Apache.

+0

excepto que utiliza carácter ' .toLowerCase' (http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/StringUtils.java?view=markup), que no es una buena idea (específicamente, no recomendado en los documentos de Java) porque no maneja las configuraciones regionales o Unicode correctamente. Ver mi comentario (jambjo originalmente lo señaló, pero en una respuesta eliminada) en la respuesta de Marcus para más detalles: http://stackoverflow.com/questions/2447427/whats-the-best-way-to-replace-the-first -letter-of-a-string-in-java/2447655 # 2447655 –

+0

Entonces yo diría que usar Character.toLowerCase o String # toLowerCase depende de la situación. Si está seguro de que Character.toLowerCase no causará problemas en su caso, úselo porque su rendimiento debería ser mejor. Depende ;-) – Maxym

+0

Bastante, pero dudo que haya suficiente ganancia de rendimiento para que valga la pena configurar el problema de mantenimiento en línea (ya que las aplicaciones de hoy en día se ocupan de un * lote * de configuración regional y cosas Unicode). :-) –

3

La desventaja del código que usaste (y lo he usado en situaciones similares) es que parece un poco torpe y en teoría genera al menos dos cadenas temporales que se tiran inmediatamente. También está la cuestión de qué sucede si su cadena tiene menos de dos caracteres.

Lo bueno es que no hace referencia a esas cadenas temporales fuera de la expresión (dejándola abierta a la optimización por el compilador de bytecode o el optimizador JIT) y su intención queda clara para cualquier desarrollador de código futuro.

Salvo que necesite hacer varios millones de estos en un segundo cualquiera y detectando un problema de rendimiento notable al hacerlo, no me preocuparía el rendimiento y preferiría claridad. También lo enterraría en una clase de utilidad en alguna parte. :-) Vea también la respuesta de jambjo a otra respuesta señalando que hay una diferencia importante entre String#toLowerCase y Character.toLowerCase. (Editar: La respuesta y por lo tanto comentario que haya sido eliminado Básicamente, hay una gran diferencia en relación con lugares y Unicode y los documentos recomiendan utilizar String#toLowerCase, no Character.toLowerCase; more here..)

Editar Porque estoy un estado de ánimo extraño, pensé que vería si hubiera una diferencia medible en el rendimiento en una prueba simple. Ahi esta. Podría ser debido a la diferencia local (por ejemplo, manzanas contra naranjas):

public class Uncap 
{ 
    public static final void main(String[] params) 
    { 
     String s; 
     String s2; 
     long start; 
     long end; 
     int  counter; 

     // Warm up 
     s = "Testing"; 
     start = System.currentTimeMillis(); 
     for (counter = 1000000; counter > 0; --counter) 
     { 
      s2 = uncap1(s); 
      s2 = uncap2(s); 
      s2 = uncap3(s); 
     } 

     // Test v2 
     start = System.currentTimeMillis(); 
     for (counter = 1000000; counter > 0; --counter) 
     { 
      s2 = uncap2(s); 
     } 
     end = System.currentTimeMillis(); 
     System.out.println("2: " + (end - start)); 

     // Test v1 
     start = System.currentTimeMillis(); 
     for (counter = 1000000; counter > 0; --counter) 
     { 
      s2 = uncap1(s); 
     } 
     end = System.currentTimeMillis(); 
     System.out.println("1: " + (end - start)); 

     // Test v3 
     start = System.currentTimeMillis(); 
     for (counter = 1000000; counter > 0; --counter) 
     { 
      s2 = uncap3(s); 
     } 
     end = System.currentTimeMillis(); 
     System.out.println("3: " + (end - start)); 

     System.exit(0); 
    } 

    // The simple, direct version; also allows the library to handle 
    // locales and Unicode correctly 
    private static final String uncap1(String s) 
    { 
     return s.substring(0,1).toLowerCase() + s.substring(1); 
    } 

    // This will *not* handle locales and unicode correctly 
    private static final String uncap2(String s) 
    { 
     return Character.toLowerCase(s.charAt(0)) + s.substring(1); 
    } 

    // This will *not* handle locales and unicode correctly 
    private static final String uncap3(String s) 
    { 
     StringBuffer sb; 

     sb = new StringBuffer(s); 
     sb.setCharAt(0, Character.toLowerCase(sb.charAt(0))); 
     return sb.toString(); 
    } 
} 

mezclé el orden en varias pruebas (moverlos y volver a compilar) para evitar problemas de tiempo de aceleración (y tratado para forzar al principio de todos modos).Muy poco científica, pero uncap1 fue consistentemente más lenta que uncap2 y uncap3 en alrededor de 40%. No es que importe, estamos hablando de una diferencia de 400ms en un millón de iteraciones en un procesador Intel Atom. :-)

Por lo tanto: me gustaría ir con su código sencillo, directo, envuelto en una función de utilidad.

+0

Este tipo de microbenchmark no es apropiado para la JVM en muchos casos. Ver http://www.ibm.com/developerworks/java/library/j-benchmark1.html – deamon

+0

@deamon: No me sorprendería en absoluto. :-) (Y gracias por el enlace, tengo que darle una lectura alguna vez.) Dije "no científico" y que realmente no debería preocuparse por eso hasta que haya un problema de rendimiento específico para solucionarlo. –

+0

buen trabajo! Simplemente observe cómo se implementará el método no capitalizado en Common-Lang 3.0 (o probablemente ya se haya implementado de la misma manera en la versión actual 2.3): nuevo StringBuilder (strLen) .append (Character.toLowerCase (str.charAt (0))). append (str.substring (1)). toString(); – Maxym

1

Cuidado con cualquiera de las funciones de caracteres en cadenas. Debido a Unicode, no siempre es una asignación de 1 a 1. Se adhieren a los métodos basados ​​en cadenas, a menos que Char sea realmente lo que usted desea. Como otros han sugerido, hay herramientas de cadenas disponibles, pero incluso si no las quiere usar para su proyecto, solo haga una usted mismo mientras trabaja. Lo peor que puede hacer es hacer una función especial para minúsculas y ocultarla en una clase y luego usar el mismo código de forma ligeramente diferente en 12 lugares diferentes. Ponlo en algún lugar que pueda ser compartido fácilmente.

1

Uso StringBuffer:

buffer.setCharAt(0, Character.toLowerCase(buffer.charAt(0))); 
+3

¿Quieres evitar las versiones de carácter de estas cosas: * "En general, String.toLowerCase() debe ser utilizado para asignar caracteres en minúsculas métodos de mapeo caso de cuerdas tienen varias ventajas sobre los métodos de mapeo de mayúsculas o minúsculas. Los métodos de asignación de mayúsculas y minúsculas pueden realizar asignaciones sensibles a la configuración regional, mapeos sensibles al contexto y mapeos de caracteres 1: M, mientras que los métodos de mapeo de Caracteres de caracteres no pueden. "* - http://java.sun.com/javase/6/docs /api/java/lang/Character.html#toLowerCase%28char%29 Además, el uso explícito de 'StringBuffer' para un concat de' String' en realidad no ayudará a perf (y puede dificultar). –

Cuestiones relacionadas