2010-06-27 11 views
36

¿Cómo formateo mi cadena en GWT?Formateador de cadenas en GWT

Hice un método

Formatter format = new Formatter(); 
    int matches = 0; 
    Formatter formattedString = format.format("%d numbers(s, args) in correct position", matches); 
    return formattedString.toString(); 

Pero se queja diciendo

Validating newly compiled units 
    [ERROR] Errors in 'file:/C:/Documents%20and%20Settings/kkshetri/workspace/MasterMind/MasterMind/src/com/kunjan/MasterMind/client/MasterMind.java' 
     [ERROR] Line 84: No source code is available for type java.util.Formatter; did you forget to inherit a required module? 

No es formateador incluido?

+0

hizo u importar java.util.Formatter en su archivo MasterMind.java? –

Respuesta

21

ACTUALIZACIÓN: Consulte (y vote arriba) la publicación de Joseph Lust a continuación antes de seguir leyendo esta respuesta.

Parece que el formateador no está incluido de acuerdo con this post. Sin embargo, sugieren algunas alternativas.

+5

Merece la pena mencionar también 'NumberFormat' y' DateTimeFormat'. –

+0

Mi IDE se queja de que NumberFormat no está presente en la emulación JRE, pero parece funcionar ... – dhardy

+0

Esta fue la verdadera y legítima [Solución GWT] (http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsFormatting.html# numberformat) para mí. [como se hace referencia por @Joseph Lust respuesta a continuación, que creo que debería ser la respuesta realmente aceptada ..] – cellepo

21

un reemplazo muy simple para String.Format() en GWT 2.1 +:

import com.google.gwt.regexp.shared.RegExp; 
import com.google.gwt.regexp.shared.SplitResult; 

public static String format(final String format, final Object... args) { 
    final RegExp regex = RegExp.compile("%[a-z]"); 
    final SplitResult split = regex.split(format); 
    final StringBuffer msg = new StringBuffer(); 
    for (int pos = 0; pos < split.length() - 1; ++pos) { 
    msg.append(split.get(pos)); 
    msg.append(args[pos].toString()); 
    } 
    msg.append(split.get(split.length() - 1)); 
    return msg.toString(); 
} 
0

Como alternativa, se puede utilizar la clase NumberFormat:

NumberFormat fmt = NumberFormat.getDecimalFormat(); 
double value = 12345.6789; 
String formatted = fmt.format(value); 
// Prints 1,2345.6789 in the default locale 
0

otra reemplazo muy muy simple para Java. text.MessageFormat.format():

public static String format(final String format, final Object... args) { 
    StringBuilder sb = new StringBuilder(); 
    int cur = 0; 
    int len = format.length(); 
    while (cur < len) { 
     int fi = format.indexOf('{', cur); 
     if (fi != -1) { 
      sb.append(format.substring(cur, fi)); 
      int si = format.indexOf('}', fi); 
      if (si != -1) { 
       String nStr = format.substring(fi + 1, si); 
       int i = Integer.parseInt(nStr); 
       sb.append(args[i]); 
       cur = si + 1; 
      } else { 
       sb.append(format.substring(fi)); 
       break; 
      } 
     } else { 
      sb.append(format.substring(cur, len)); 
      break; 
     } 
    } 
    return sb.toString(); 
} 
5

O incluso más simple, no utiliza RegE XP, y utilizando sólo Cuerdas:

public static String format(final String format, final String... args) { 
    String[] split = format.split("%s"); 
    final StringBuffer msg = new StringBuffer(); 
    for (int pos = 0; pos < split.length - 1; pos += 1) { 
     msg.append(split[pos]); 
     msg.append(args[pos]); 
    } 
    msg.append(split[split.length - 1]); 
    return msg.toString(); 
} 
+3

'pos + = 1' en un bucle' for'? De Verdad? –

+1

+1 por no usar el paquete de google. Esto tiene un problema si el formato finaliza en '% s'. Solo agrega 'if (args.length == split.longitud) \t \t msg.append (args [args.length - 1]); 'antes de volver a arreglarlo. –

+0

, excepto que la división de cadena no está disponible en gwt – NimChimpsky

1

Esta es bastante rápido y hace caso omiso de los valores malos rizado delimitado por:

public static String format(final String format, final Object... args) 
{ 
    if (format == null || format.isEmpty()) return ""; 

    // Approximate the result length: format string + 16 character args 
    StringBuilder sb = new StringBuilder(format.length() + (args.length*16)); 

    final char openDelim = '{'; 
    final char closeDelim = '}'; 

    int cur = 0; 
    int len = format.length(); 
    int open; 
    int close; 

    while (cur < len) 
    { 
     switch (open = format.indexOf(openDelim, cur)) 
     { 
      case -1: 
       return sb.append(format.substring(cur, len)).toString(); 

      default: 
       sb.append(format.substring(cur, open)); 
       switch (close = format.indexOf(closeDelim, open)) 
       { 
        case -1: 
         return sb.append(format.substring(open)).toString(); 

        default: 
         String nStr = format.substring(open + 1, close); 
         try 
         { 
          // Append the corresponding argument value 
          sb.append(args[Integer.parseInt(nStr)]); 
         } 
         catch (Exception e) 
         { 
          // Append the curlies and the original delimited value 
          sb.append(openDelim).append(nStr).append(closeDelim); 
         } 
         cur = close + 1; 
       } 
     } 
    } 

    return sb.toString(); 
} 
33

Véase el official page en la fecha de GWT y formato de número.

Ellos sugieren lo siguiente:

myNum decimal = 33.23232; 
myString = NumberFormat.getFormat("#.00").format(decimal); 

Lo mejor es utilizar sus métodos, optimizado compatible, que a cocinar su propio método no óptima. Su compilador los optimizará todos a casi lo mismo de todos modos al final.

0

Quizás la forma más fácil de hacer algo como String.format, se puede hacer con un String.reemplazar, por ejemplo;

en lugar de hacerlo String.format("Hello %s", "Daniel"); ==>"Hello %s".replace("%s", "Daniel"),

tanto nos dan el mismo resultado, pero sólo la segunda forma en que funciona en el lado del cliente GWT

+1

Si va a usar el formateo, es probable que necesite más de un parámetro, por lo que la sustitución ciega de "% s" no es realmente una solución. –

1

no estoy interesado en abusar de manipulación de cadenas para hacer las expresiones regulares 'trabajo, pero, basado en la solución de bodrin, puede codificar:

public static String format (String pattern, final Object ... args) { 
    for (Object arg : args) { 
     String part1 = pattern.substring(0,pattern.indexOf('{')); 
     String part2 = pattern.substring(pattern.indexOf('}') + 1); 
     pattern = part1 + arg + part2; 
    } 
    return pattern; 
} 
+1

Algo me asusta a la hora de modificar su parámetro en su método. –

+0

@RyanShillington String es inmutable. – NateS

3

Otra sugerencia que hace uso de JSNI y una bonita función de formato de JavaScript another post:

import com.google.gwt.core.client.JsArrayString; 

public abstract class StringFormatter { 
    public static String format(final String format, final Object... args) { 
     if (null == args || 0 == args.length) 
      return format; 
     JsArrayString array = newArray(); 
     for (Object arg : args) { 
      array.push(String.valueOf(arg)); // TODO: smarter conversion? 
     } 
     return nativeFormat(format, array); 
    } 

    private static native JsArrayString newArray()/*-{ 
     return []; 
    }-*/; 

    private static native String nativeFormat(final String format, final JsArrayString args)/*-{ 
     return format.replace(/{(\d+)}/g, function(match, number) { 
      return typeof args[number] != 'undefined' ? args[number] : match; 
     }); 
    }-*/; 
} 

Uno puede entonces hacer una llamada como ésta:

StringFormatter.format("Greetings {0}, it's {1} o'clock, which is a {2} statement", "Master", 8, false); 

... con el resultado de

Saludos Maestro, son las 8 de la mañana, que es una declaración falsa

Existe un potencial para mejorar aún más en el TODO comentario, p. utilizar NumberFormat. Sugerencias son bienvenidas.

0

Como se mencionó anteriormente, hay formateadores GWT para números y fechas: NumberFormat y DateTimeFormat. Aún así, necesitaba una solución para el conocido caso String.format(...). Terminé con esta solución, no sé si está mal para el rendimiento, pero es visualmente limpio. Me alegraría escuchar cualquier comentario al respecto o sobre otra solución.

Mi formateador de encordado:

public class Strings { 

    public static String format(final String format, final Object... args) { 
     String retVal = format; 
     for (final Object current : args) { 
      retVal = retVal.replaceFirst("[%][s]", current.toString()); 
     } 
     return retVal; 
    } 

} 

y la JUTest si se desea volver a utilizar este:

public class StringsTest { 

    @Test 
    public final void testFormat() { 
     this.assertFormat("Some test here %s.", 54); 
     this.assertFormat("Some test here %s and there %s, and test [%s]. sfsfs !!!", 54, 59, "HAHA"); 

    } 

    private void assertFormat(final String format, final Object... args) { 
     Assert.assertEquals("Formatting is not working", String.format(format, args), Strings.format(format, args)); 
    } 

} 
1

Una extensión a la solución Daniels: También es compatible con escapar usando 'y lanza si un número no se puede analizar (como la versión de JVM hace):

private static final char OPEN = '{'; 
private static final char CLOSE = '}'; 
private static final char ESCAPE = '\''; 

@Override 
public String format(String pattern, Object... arguments) { 
    if (pattern == null || pattern.isEmpty()) 
     return ""; 

    // Approximate the result length: format string + 16 character args 
    StringBuilder sb = new StringBuilder(pattern.length() + (arguments.length * 16)); 

    int cur = 0; 
    int len = pattern.length(); 
    // if escaped, then its >= 0 
    int escapedAtIndex = -1; 

    while (cur < len) { 
     char currentChar = pattern.charAt(cur); 
     switch (currentChar) { 
      case OPEN: 
       if (escapedAtIndex >= 0) { 
        // currently escaped 
        sb.append(currentChar); 
       } else { 
        // find close 
        int close = pattern.indexOf(CLOSE, cur + 1); 
        switch (close) { 
         case -1: 
          // Missing close. Actually an error. But just ignore 
          sb.append(currentChar); 
          break; 
         default: 
          // Ok, we have a close 
          final String nStr = pattern.substring(cur + 1, close); 
          try { 
           // Append the corresponding argument value 
           sb.append(arguments[Integer.parseInt(nStr)]); 
          } catch (Exception e) { 
           if (e instanceof NumberFormatException) { 
            throw new IllegalArgumentException(nStr + 
              " is not a number."); 
           } 
           // Append the curlies and the original delimited value 
           sb.append(OPEN).append(nStr).append(CLOSE); 
          } 
          // Continue after the close 
          cur = close; 
          break; 
        } 
       } 
       cur++; 
       break; 
      case ESCAPE: 
       // Special case: two '' are just converted to ' 
       boolean nextIsEscapeToo = (cur + 1 < len) && pattern.charAt(cur + 1) == ESCAPE; 
       if (nextIsEscapeToo) { 
        sb.append(ESCAPE); 
        cur = cur + 2; 
       } else { 
        if (escapedAtIndex >= 0) { 
         // Escape end. 
         escapedAtIndex = -1; 
        } else { 
         // Escape start. 
         escapedAtIndex = cur; 
        } 
        cur++; 
       } 
       break; 
      default: 
       // 90% case: Nothing special, just a normal character 
       sb.append(currentChar); 
       cur++; 
       break; 
     } 
    } 
    return sb.toString(); 
} 

Esta aplicación y la JVM-Versi en tanto pasar esos exámenes:

// Replace: 0 items 
    assertFormat("Nothing to replace", "Nothing to replace"); 
    // Replace: 1 item 
    assertFormat("{0} apples", "15 apples", 15); 
    assertFormat("number of apples: {0}", "number of apples: zero", "zero"); 
    assertFormat("you ate {0} apples", "you ate some apples", "some"); 
    // Replace 2 items 
    assertFormat("{1} text {0}", "second text first", "first", "second"); 
    assertFormat("X {1} text {0}", "X second text first", "first", "second"); 
    assertFormat("{0} text {1} X", "first text second X", "first", "second"); 

Escapar-Pruebas:

// Escaping with no replacement 
    assertFormat("It's the world", "Its the world"); 
    assertFormat("It''s the world", "It's the world"); 
    assertFormat("Open ' and now a second ' (closes)", "Open and now a second (closes)"); 
    assertFormat("It'''s the world", "It's the world"); 
    assertFormat("'{0}' {1} {2}", "{0} one two", "zero", "one", "two"); 
    // Stays escaped (if end escape is missing) 
    assertFormat("'{0} {1} {2}", "{0} {1} {2}", "zero", "one", "two"); 
    assertFormat("'{0} {1}' {2}", "{0} {1} two", "zero", "one", "two"); 
    // No matter where we escape, stays escaped 
    assertFormat("It's a {0} world", "Its a {0} world", "blue"); 
    // But we can end escape everywhere 
    assertFormat("It's a {0} world, but not '{1}", 
      "Its a {0} world, but not always", "blue", "always"); 
    // I think we want this 
    assertFormat("It''s a {0} world, but not {1}", 
      "It's a blue world, but not always", "blue", "always"); 
    // Triple 
    assertFormat("' '' '", " ' "); 
    // From oracle docs 
    assertFormat("'{''}'", "{'}"); 
    // Missing argument (just stays 0) 
    assertFormat("begin {0} end", "begin {0} end"); 
    // Throws 
    try { 
     assertFormat("begin {not_a_number} end", "begin {not_a_number} end"); 
     throw new AssertionError("Should not get here"); 
    } catch (IllegalArgumentException iae) { 
     // OK 
    } 
Cuestiones relacionadas