2010-06-27 12 views
36

Jak sformatować ciąg znaków w GWT?Formatowanie ciągów w GWT

zrobiłem metodę

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

Ale narzeka mówiąc

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? 

formater nie jest wliczone w cenę?

+0

nie u importować java.util.Formatter w pliku MasterMind.java? –

Odpowiedz

21

AKTUALIZACJA: Proszę przejrzeć (i zagłosować) post Josepha Lust'a poniżej, zanim przejrzysz dalej tę odpowiedź.

Wygląda na to, że formater nie został uwzględniony zgodnie z this post. Sugerują jednak kilka alternatyw.

+5

Warto również wspomnieć o "NumberFormat" i "DateTimeFormat". –

+0

Moje IDE skarży się, że NumberFormat nie występuje w emulacji JRE, ale wydaje się działać ... – dhardy

+0

To był prawdziwy, legalny [rozwiązanie GWT] (http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsFormatting.html# numberformat) dla mnie. [zgodnie z odpowiedzią @Josepha Lust poniżej, która moim zdaniem powinna być prawdziwą akceptowaną odpowiedzią.] – cellepo

21

Bardzo prostym zamiennikiem dla string.Format() w 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

Jako alternatywę można wykorzystać klasę NumberFormat:

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

innym bardzo prosty zamiennik 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

Lub jeszcze prostsze, nie używając RegE XP i przy użyciu tylko ciągi:

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' w pętli' for'? Naprawdę? –

+1

+1 za niewykorzystanie pakietu google. Ma to problem, jeśli format kończy się na '% s'. Po prostu dodaj 'if (args.length == split.długość) \t \t msg.append (args [args.length - 1]); 'przed powrotem, aby to naprawić. –

+0

z wyjątkiem podziału na struny nie jest dostępny w gwt – NimChimpsky

1

Ten jest dość szybki i ignoruje złe wartości kręcone rozdzielany:

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

Zobacz official page na bieżąco GWT i formatowania liczb.

Sugerują one następujące:

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

Najlepiej jest wykorzystać swoje obsługiwane, zoptymalizowane metody, niż gotować własną non-optymalnej metody. Ich kompilator i tak zoptymalizuje wszystkie do prawie tego samego w końcu.

0

Być może najprostszy sposób na zrobienie czegoś podobnego do String.format, można to zrobić za pomocą ciągu.wymienić, na przykład;

zamiast robić String.format("Hello %s", "Daniel"); ==>"Hello %s".replace("%s", "Daniel"),

zarówno nam dać taki sam efekt, ale tylko drugi sposób działa po stronie klienta GWT

+1

Jeśli zamierzasz używać formatowania, prawdopodobnie będziesz potrzebować więcej niż jednego parametru, więc ślepa zamiana "% s" w rzeczywistości nie jest rozwiązaniem. –

1

nie jestem zależało na nadużywanie manipulacji ciąg do wykonywania wyrażeń regularnych 'praca, ale w oparciu o rozwiązania bodrin użytkownika, można kodować:

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

Coś mnie przeraża, modyfikując parametr w Twojej metodzie. –

+0

@RyanShillington String jest niezmienny. – NateS

3

Kolejna propozycja, która korzysta z JSNI i ładnym formacie funkcji JavaScript z 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; 
     }); 
    }-*/; 
} 

Można wtedy wykonać połączenie tak:

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

... z rezultatem jest

Pozdrowienia Mistrzu, to godzina ósma, które jest fałszywe oświadczenie

Istnieje potencjał do dalszej poprawy na TODO komentarz, np. wykorzystaj NumberFormat. Sugestie są mile widziane.

0

Jak wspomniano powyżej, istnieją formatery GWT dla liczb i dat: NumberFormat i DateTimeFormat. Nadal potrzebowałem rozwiązania dla dobrze znanej obudowy String.format(...). Skończyło się na tym rozwiązaniu, nie wiem, czy to nie działa, ale jest wizualnie czyste. Byłbym zadowolony usłyszawszy jakikolwiek komentarz na ten temat lub o innym rozwiązaniu.

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

} 

i JUTest jeśli ktoś chce to ponownie użyć:

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

rozszerzeniem rozwiązania Daniels: obsługuje także ucieczce za pomocą "i rzuca Jeśli numer nie można przeanalizować (tak jak wersja 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(); 
} 

Ta implementacja i JVM-Versi na oba te przechodzą testy:

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

Ucieczki-testy:

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