Подтвердить что ты не робот

String Formatter в GWT

Как мне форматировать мою строку в GWT?

Я сделал метод

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

Но он жалуется, говоря

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?

Не включен ли Formatter?

4b9b3361

Ответ 1

ОБНОВЛЕНИЕ: Пожалуйста, смотрите (и проголосуйте) за сообщение Джозефа Люста ниже, прежде чем смотреть дальше на этот ответ.

Похоже, что форматирование не включается в соответствии с этот пост. Однако они предлагают несколько альтернатив.

Ответ 2

См. официальную страницу в формате даты и номера GWT.

Они предлагают следующее:

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

Лучше всего использовать их поддерживаемые оптимизированные методы, чем готовить свой собственный неоптимальный метод. Их компилятор будет оптимизировать их всех почти так же, как и в конце концов.

Ответ 3

Очень простая замена для String.format() в 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();
}

Ответ 4

Или даже проще, не используя RegExp, и используя только строки:

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

Ответ 5

Другое предложение, в котором используется JSNI и хорошая функция формата JavaScript из другого сообщение:

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

Затем можно сделать вызов следующим образом:

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

... с результатом

Приветствие Мастер, это 8 часов, что является ложным утверждением

Существует потенциал для дальнейшего улучшения в комментарии TODO, например. используйте NumberFormat. Предложения приветствуются.

Ответ 6

Это довольно быстро и игнорирует плохие значения, зависящие от курсива:

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

Ответ 7

Я не хочу злоупотреблять строковыми манипуляциями для выполнения задания регулярных выражений, но, основываясь на решении bodrin, вы можете закодировать:

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

Ответ 8

Расширение для решения Daniels: также поддерживает экранирование с помощью 'и throws, если число не может быть проанализировано (например, версия 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();
}

Эта реализация и JVM-версия проходят эти тесты:

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

Escaping-тесты:

    // Escaping with no replacement
    assertFormat("It the world", "Its the world");
    assertFormat("It' the world", "It the world");
    assertFormat("Open ' and now a second ' (closes)", "Open  and now a second  (closes)");
    assertFormat("It'' the world", "It 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 a {0} world", "Its a {0} world", "blue");
    // But we can end escape everywhere
    assertFormat("It a {0} world, but not '{1}",
            "Its a {0} world, but not always", "blue", "always");
    // I think we want this
    assertFormat("It' a {0} world, but not {1}",
            "It 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
    }

Ответ 9

В качестве альтернативы вы можете использовать класс NumberFormat:

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

Ответ 10

другая очень простая замена для 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();
}

Ответ 11

Возможно, самый простой способ сделать что-то вроде String.format можно, например, с помощью String.replace;

вместо do String.format("Hello %s", "Daniel"); == > "Hello %s".replace("%s", "Daniel"),

оба дают нам тот же результат, но только второй способ работает на стороне клиента GWT

Ответ 12

Как упоминалось выше, существуют форматы GWT для чисел и дат: NumberFormat и DateTimeFormat. Тем не менее, мне понадобилось решение для хорошо известного случая String.format(...). Я в конечном итоге с этим решением, я не знаю, если это неправильно для производительности, но он визуально чист. Я был бы рад услышать какие-либо комментарии по этому поводу или о другом решении.

My String formatter:

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

}

и JUTest, если вы хотите повторно использовать это:

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

}