java tutorial String Formatter dans GWT




gwt vs angular (10)

Voir la page officielle sur la date et le formatage du numéro GWT.

Ils suggèrent ce qui suit:

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

Il est préférable d'utiliser leurs méthodes optimisées et prises en charge, plutôt que de créer votre propre méthode non optimale. Leur compilateur les optimisera tous à peu près la même chose à la fin.

Comment formater ma chaîne dans GWT?

J'ai fait une méthode

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

Mais il se plaint en disant

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?

Est-ce que Formatter n'est pas inclus?


Un remplacement très simple de String.format () dans 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();
}

Comme mentionné ci-dessus, il existe des formateurs GWT pour les nombres et les dates: NumberFormat et DateTimeFormat . Pourtant, j'avais besoin d'une solution pour le célèbre cas String.format(...) . Je finis avec cette solution, je ne sais pas si c'est mauvais pour la performance, mais c'est visuellement propre. Je serais heureux d'entendre tout commentaire à ce sujet, ou sur d'autres solutions.

Mon formateur String:

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

}

et le JUTest si l'on veut réutiliser ceci:

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

}

Je ne tiens pas à abuser de la manipulation de chaînes pour faire le travail de regexps, mais, basé sur la solution de bodrin, vous pouvez coder:

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

MISE À JOUR: S'il vous plaît voir (et voter) le post de Joseph Lust ci-dessous avant de regarder plus loin cette réponse.

On dirait que le formateur n'est pas inclus selon ce post . Cependant, ils suggèrent des alternatives.


Une autre suggestion qui utilise JSNI et une bonne fonction de format JavaScript à partir d' un autre message :

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;
        });
    }-*/;
}

On peut alors faire un appel comme celui-ci:

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

... avec le résultat étant

Salutations Maître, il est 8 heures, ce qui est une fausse déclaration

Il est possible d'améliorer encore le commentaire TODO , par exemple utiliser NumberFormat. Les suggestions sont les bienvenues.


Peut-être que la façon la plus simple de faire quelque chose comme String.format, peut être de le faire avec un String.replace, par exemple;

au lieu de faire String.format("Hello %s", "Daniel"); ==> "Hello %s".replace("%s", "Daniel") ,

les deux nous donnent le même résultat, mais seulement la seconde fonctionne dans le côté client GWT


Ou encore plus simple, ne pas utiliser RegExp, et en utilisant uniquement des chaînes:

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

un autre remplacement très simple pour 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();
}

Une extension à la solution Daniels: Supporte également l'échappement en utilisant 'et renvoie si un nombre ne peut pas être analysé (comme le fait la version JVM):

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

Cette implémentation et la version JVM passent tous deux ces tests:

    // 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");

Échapper-Tests:

    // 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
    }




gwt