StringTokenizer
? Convertir el String
que una char[]
y iterar sobre eso? ¿Algo más?
StringTokenizer
? Convertir el String
que una char[]
y iterar sobre eso? ¿Algo más?
Respuestas:
Utilizo un bucle for para iterar la cadena y utilizo charAt()
para que cada personaje lo examine. Como la cadena se implementa con una matriz, el charAt()
método es una operación de tiempo constante.
String s = "...stuff...";
for (int i = 0; i < s.length(); i++){
char c = s.charAt(i);
//Process char
}
Eso es lo que yo haría. Me parece lo más fácil.
En lo que respecta a la corrección, no creo que exista aquí. Todo se basa en tu estilo personal.
String.charAt(int)
es simplemente hacer value[index]
. Creo que estás confundiendo chatAt()
con algo más que te da puntos de código.
Dos opciones
for(int i = 0, n = s.length() ; i < n ; i++) {
char c = s.charAt(i);
}
o
for(char c : s.toCharArray()) {
// process c
}
El primero es probablemente más rápido, luego el segundo es probablemente más legible.
Tenga en cuenta que la mayoría de las otras técnicas descritas aquí se desglosan si se trata de caracteres fuera del BMP ( Plano multilingüe básico Unicode ), es decir , puntos de código que están fuera del rango u0000-uFFFF. Esto solo ocurrirá en raras ocasiones, ya que los puntos de código fuera de esto se asignan principalmente a idiomas muertos. Pero hay algunos caracteres útiles fuera de esto, por ejemplo, algunos puntos de código utilizados para la notación matemática, y algunos utilizados para codificar nombres propios en chino.
En ese caso su código será:
String str = "....";
int offset = 0, strLen = str.length();
while (offset < strLen) {
int curChar = str.codePointAt(offset);
offset += Character.charCount(curChar);
// do something with curChar
}
El Character.charCount(int)
método requiere Java 5+.
Estoy de acuerdo en que StringTokenizer es excesivo aquí. En realidad probé las sugerencias anteriores y me tomé el tiempo.
Mi prueba fue bastante simple: crear un StringBuilder con aproximadamente un millón de caracteres, convertirlo en una Cadena y atravesar cada uno de ellos con charAt () / después de convertirlo en una matriz de caracteres / con un CharacterIterator mil veces (por supuesto asegurándose de hacer algo en la cadena para que el compilador no pueda optimizar todo el ciclo :-)).
El resultado en mi Powerbook de 2.6 GHz (eso es un mac :-)) y JDK 1.5:
Como los resultados son significativamente diferentes, la forma más directa también parece ser la más rápida. Curiosamente, charAt () de un StringBuilder parece ser un poco más lento que el de String.
Por cierto, sugiero no usar CharacterIterator ya que considero que su abuso del carácter '\ uFFFF' como "final de la iteración" es un truco realmente horrible. En los grandes proyectos siempre hay dos tipos que usan el mismo tipo de pirateo para dos propósitos diferentes y el código se bloquea realmente misteriosamente.
Aquí hay una de las pruebas:
int count = 1000;
...
System.out.println("Test 1: charAt + String");
long t = System.currentTimeMillis();
int sum=0;
for (int i=0; i<count; i++) {
int len = str.length();
for (int j=0; j<len; j++) {
if (str.charAt(j) == 'b')
sum = sum + 1;
}
}
t = System.currentTimeMillis()-t;
System.out.println("result: "+ sum + " after " + t + "msec");
En Java 8 podemos resolverlo como:
String str = "xyz";
str.chars().forEachOrdered(i -> System.out.print((char)i));
str.codePoints().forEachOrdered(i -> System.out.print((char)i));
El método chars () devuelve un IntStream
como se menciona en doc :
Devuelve una secuencia de int cero que extiende los valores de caracteres de esta secuencia. Cualquier carácter que se asigne a un punto de código sustituto se pasa sin interpretación. Si la secuencia está mutada mientras se lee la secuencia, el resultado no está definido.
El método codePoints()
también devuelve un IntStream
según el documento:
Devuelve una secuencia de valores de puntos de código de esta secuencia. Cualquier par sustituto encontrado en la secuencia se combina como si fuera por Character.toCodePoint y el resultado se pasa a la secuencia. Cualquier otra unidad de código, incluidos los caracteres BMP ordinarios, los sustitutos no apareados y las unidades de código indefinidas, se extienden a cero a valores int que luego se pasan a la secuencia.
¿En qué se diferencian char y code point? Como se menciona en este artículo:
Unicode 3.1 agregó caracteres suplementarios, elevando el número total de caracteres a más de 216 caracteres que se pueden distinguir por un solo 16 bits
char
. Por lo tanto, unchar
valor ya no tiene un mapeo uno a uno a la unidad semántica fundamental en Unicode. JDK 5 se actualizó para admitir el conjunto más grande de valores de caracteres. En lugar de cambiar la definición delchar
tipo, algunos de los nuevos caracteres suplementarios están representados por un par sustituto de doschar
valores. Para reducir la confusión de nombres, se usará un punto de código para referirse al número que representa un carácter Unicode particular, incluidos los complementarios.
Finalmente por qué forEachOrdered
y no forEach
?
El comportamiento de forEach
es explícitamente no determinista donde, a medida que forEachOrdered
realiza una acción para cada elemento de esta secuencia, en el orden de encuentro de la secuencia si la secuencia tiene un orden de encuentro definido. Por forEach
lo tanto , no garantiza que se mantenga el pedido. También revise esta pregunta para más.
Para ver la diferencia entre un personaje, un punto de código, un glifo y un grafema, consulte esta pregunta .
Hay algunas clases dedicadas para esto:
import java.text.*;
final CharacterIterator it = new StringCharacterIterator(s);
for(char c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
// process c
...
}
char
proporciona Java . Un Java char
contiene 16 bits y puede contener caracteres Unicode hasta U + FFFF, pero Unicode especifica caracteres hasta U + 10FFFF. El uso de 16 bits para codificar Unicode da como resultado una codificación de caracteres de longitud variable. La mayoría de las respuestas en esta página asumen que la codificación Java es una codificación de longitud constante, lo cual es incorrecto.
Si tienes guayaba en tu classpath, la siguiente es una alternativa bastante legible. La guayaba incluso tiene una implementación de Lista personalizada bastante sensata para este caso, por lo que esto no debería ser ineficiente.
for(char c : Lists.charactersOf(yourString)) {
// Do whatever you want
}
ACTUALIZACIÓN: Como señaló @Alex, con Java 8 también hay CharSequence#chars
que usarlo. Incluso el tipo es IntStream, por lo que se puede asignar a caracteres como:
yourString.chars()
.mapToObj(c -> Character.valueOf((char) c))
.forEach(c -> System.out.println(c)); // Or whatever you want
Si necesita iterar a través de los puntos de código de a String
(vea esta respuesta ), una forma más corta / más legible es usar el CharSequence#codePoints
método agregado en Java 8:
for(int c : string.codePoints().toArray()){
...
}
o usando la secuencia directamente en lugar de un bucle for:
string.codePoints().forEach(c -> ...);
También existe CharSequence#chars
si desea una secuencia de los caracteres (aunque es un IntStream
, ya que no hay CharStream
).
No lo usaría, StringTokenizer
ya que es una de las clases en el JDK que es legado.
El javadoc dice:
StringTokenizer
es una clase heredada que se conserva por razones de compatibilidad, aunque se desaconseja su uso en el nuevo código. Se recomienda que cualquiera que busque esta funcionalidad use el método divididoString
o eljava.util.regex
paquete en su lugar.
Si necesita rendimiento, debe probar en su entorno. Ninguna otra manera.
Aquí el código de ejemplo:
int tmp = 0;
String s = new String(new byte[64*1024]);
{
long st = System.nanoTime();
for(int i = 0, n = s.length(); i < n; i++) {
tmp += s.charAt(i);
}
st = System.nanoTime() - st;
System.out.println("1 " + st);
}
{
long st = System.nanoTime();
char[] ch = s.toCharArray();
for(int i = 0, n = ch.length; i < n; i++) {
tmp += ch[i];
}
st = System.nanoTime() - st;
System.out.println("2 " + st);
}
{
long st = System.nanoTime();
for(char c : s.toCharArray()) {
tmp += c;
}
st = System.nanoTime() - st;
System.out.println("3 " + st);
}
System.out.println("" + tmp);
En Java en línea obtengo:
1 10349420
2 526130
3 484200
0
En Android x86 API 17 obtengo:
1 9122107
2 13486911
3 12700778
0
Consulte los Tutoriales de Java: cadenas .
public class StringDemo {
public static void main(String[] args) {
String palindrome = "Dot saw I was Tod";
int len = palindrome.length();
char[] tempCharArray = new char[len];
char[] charArray = new char[len];
// put original string in an array of chars
for (int i = 0; i < len; i++) {
tempCharArray[i] = palindrome.charAt(i);
}
// reverse array of chars
for (int j = 0; j < len; j++) {
charArray[j] = tempCharArray[len - 1 - j];
}
String reversePalindrome = new String(charArray);
System.out.println(reversePalindrome);
}
}
Ponga la longitud int len
y use el for
bucle.
StringTokenizer es totalmente inadecuado para la tarea de dividir una cadena en sus caracteres individuales. Con String#split()
usted puede hacerlo fácilmente utilizando una expresión regular que no coincida con nada, por ejemplo:
String[] theChars = str.split("|");
Pero StringTokenizer no usa expresiones regulares, y no hay una cadena delimitadora que pueda especificar que no coincida con la nada entre los caracteres. No es un lindo truco que puede utilizar para lograr lo mismo: utilizar la cadena como la cadena delimitadora (haciendo todos los personajes en un delimitador) y tienen que devolver los delimitadores:
StringTokenizer st = new StringTokenizer(str, str, true);
Sin embargo, solo menciono estas opciones con el propósito de descartarlas. Ambas técnicas dividen la cadena original en cadenas de un carácter en lugar de primitivas de caracteres, y ambas implican una gran sobrecarga en forma de creación de objetos y manipulación de cadenas. Compare eso con llamar a charAt () en un bucle for, que prácticamente no genera gastos generales.
Elaborando sobre esta respuesta y esta respuesta .
Las respuestas anteriores señalan el problema de muchas de las soluciones aquí que no iteran por el valor del punto de código: tendrían problemas con cualquier carácter sustituto . Los documentos de Java también describen el problema aquí (consulte "Representaciones de caracteres Unicode"). De todos modos, aquí hay un código que usa algunos caracteres sustitutos reales del conjunto Unicode suplementario, y los convierte de nuevo en una Cadena. Tenga en cuenta que .toChars () devuelve una serie de caracteres: si se trata de sustitutos, necesariamente tendrá dos caracteres. Este código debería funcionar para cualquier carácter Unicode.
String supplementary = "Some Supplementary: 𠜎𠜱𠝹𠱓";
supplementary.codePoints().forEach(cp ->
System.out.print(new String(Character.toChars(cp))));
¡Este código de ejemplo te ayudará!
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class Solution {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("a", 10);
map.put("b", 30);
map.put("c", 50);
map.put("d", 40);
map.put("e", 20);
System.out.println(map);
Map sortedMap = sortByValue(map);
System.out.println(sortedMap);
}
public static Map sortByValue(Map unsortedMap) {
Map sortedMap = new TreeMap(new ValueComparator(unsortedMap));
sortedMap.putAll(unsortedMap);
return sortedMap;
}
}
class ValueComparator implements Comparator {
Map map;
public ValueComparator(Map map) {
this.map = map;
}
public int compare(Object keyA, Object keyB) {
Comparable valueA = (Comparable) map.get(keyA);
Comparable valueB = (Comparable) map.get(keyB);
return valueB.compareTo(valueA);
}
}
Por lo general, hay dos formas de iterar a través de una cadena en java que ya ha sido respondida por varias personas aquí en este hilo, solo agregando mi versión de él Primero está usando
String s = sc.next() // assuming scanner class is defined above
for(int i=0; i<s.length; i++){
s.charAt(i) // This being the first way and is a constant time operation will hardly add any overhead
}
char[] str = new char[10];
str = s.toCharArray() // this is another way of doing so and it takes O(n) amount of time for copying contents from your string class to character array
Si el rendimiento está en juego, recomendaré usar el primero en tiempo constante, si no es así, ir con el segundo hace que su trabajo sea más fácil teniendo en cuenta la inmutabilidad con las clases de cadena en java.