Wie erhalte ich das Gebietsschema aus seiner String-Darstellung in Java?

109

Gibt es eine gute Möglichkeit, eine Locale- Instanz aus ihrem von Locale zurückgegebenen "programmatischen Namen" zu ermitteln?toString() Methode zurückgegeben wird? Eine offensichtliche und hässliche Lösung wäre, den String zu analysieren und dann eine neue Locale-Instanz danach zu erstellen, aber vielleicht gibt es dafür einen besseren Weg / eine bessere Lösung?

Die Notwendigkeit besteht darin, dass ich einige länderspezifische Einstellungen in einer SQL-Datenbank speichern möchte, einschließlich der Gebietsschemas selbst, aber es wäre hässlich, dort serialisierte Gebietsschemaobjekte abzulegen. Ich würde lieber ihre String-Darstellungen speichern, die im Detail völlig angemessen erscheinen.

Joonas Pulakka
quelle

Antworten:

34

Siehe Locale.getLanguage(), Locale.getCountry()... Speichern Sie diese Kombination in der Datenbank anstelle von "programatic name"...
Wenn Sie das Gebietsschema zurückbauen möchten, verwenden Siepublic Locale(String language, String country)

Hier ist ein Beispielcode :)

// May contain simple syntax error, I don't have java right now to test..
// but this is a bigger picture for your algo...
public String localeToString(Locale l) {
    return l.getLanguage() + "," + l.getCountry();
}

public Locale stringToLocale(String s) {
    StringTokenizer tempStringTokenizer = new StringTokenizer(s,",");
    if(tempStringTokenizer.hasMoreTokens())
    String l = tempStringTokenizer.nextElement();
    if(tempStringTokenizer.hasMoreTokens())
    String c = tempStringTokenizer.nextElement();
    return new Locale(l,c);
}
Raj
quelle
3
Dies würde nicht einmal kompilieren.
Adrian
1
@raj warum Tokenizer verwenden, wenn Java Ihnen fertige Methoden bietet? zB toLocale (String str). Bitte sehen Sie Beispiele in der Antwort
VdeX
9
Sie sollten Locale.forLanguageTag (String)
Rian
126

In der commons-lang-Bibliothek ist eine Methode vorhanden, die das Gebietsschema von der Zeichenfolge zurückgibt: LocaleUtils.toLocale(localeAsString)

Yurilo
quelle
2
LocaleUtils.toLocale unterstützt keine Zeichenfolgen wie 'zh-Hans', 'pt-PT' usw.
Hans van Dodewaard
10
Wenn Sie einen Bindestrich -zwischen Gebietsschema-Teilen haben, haben Sie es mit einem IETF BCP 47-Tag zu tun. Wenn Sie Java 7 verwenden, können Sie verwendenLocale.forLanguageTag
Jaime Hablutzel
59

Seit Java 7 gibt es eine Factory-Methode Locale.forLanguageTagund eine Instanzmethode, Locale.toLanguageTagdie IETF-Sprach-Tags verwenden .

nilskp
quelle
8
Ich möchte nur betonen, dass Locale.forLanguageTagIETF-Gebietsschema-Zeichenfolgen (dh en-US) funktionieren und nicht mit ISO-Gebietsschema-Zeichenfolgen (dh en_US) funktionieren
Fabian
33
  1. Java bietet viele Dinge mit der richtigen Implementierung. Viel Komplexität kann vermieden werden. Dies gibt ms_MY zurück .

    String key = "ms-MY";
    Locale locale = new Locale.Builder().setLanguageTag(key).build();
  2. Apache Commons muss LocaleUtilsdabei helfen, eine Zeichenfolgendarstellung zu analysieren. Dies gibt en_US zurück

    String str = "en-US";
    Locale locale =  LocaleUtils.toLocale(str);
    System.out.println(locale.toString());
  3. Sie können auch Gebietsschemakonstruktoren verwenden.

    // Construct a locale from a language code.(eg: en)
    new Locale(String language)
    // Construct a locale from language and country.(eg: en and US)
    new Locale(String language, String country)
    // Construct a locale from language, country and variant.
    new Locale(String language, String country, String variant)

Bitte überprüfen Sie diese LocaleUtils und dieses Gebietsschema , um weitere Methoden zu erkunden.

VdeX
quelle
1
LocaleUtils.toLocale (localeStringRepresentation) erledigt den Job ordentlich. Auch wenn Sie die Implementierung dieser Methode sehen, ist sie ziemlich umfassend!
Gericht
15

Option 1 :

org.apache.commons.lang3.LocaleUtils.toLocale("en_US")

Option 2 :

Locale.forLanguageTag("en-US")

Bitte beachten Sie, dass Option 1 zwischen Sprache und Land "unterstreicht" und Option 2 "Bindestrich" ist.

junjun
quelle
Aufruf erfordert API-Level 21 (aktuelle min ist 17): java.util.Locale # forLanguageTag
Vlad
12

Diese Antwort mag etwas spät sein, aber es stellt sich heraus, dass das Parsen der Zeichenfolge nicht so hässlich ist, wie das OP angenommen hat. Ich fand es ganz einfach und prägnant:

public static Locale fromString(String locale) {
    String parts[] = locale.split("_", -1);
    if (parts.length == 1) return new Locale(parts[0]);
    else if (parts.length == 2
            || (parts.length == 3 && parts[2].startsWith("#")))
        return new Locale(parts[0], parts[1]);
    else return new Locale(parts[0], parts[1], parts[2]);
}

Ich habe dies (unter Java 7) mit allen Beispielen getestet, die in der Dokumentation zu Locale.toString () angegeben sind: "en", "de_DE", "_GB", "en_US_WIN", "de__POSIX", "zh_CN_ # Hans", "zh_TW_" # Hant-x-java "und" th_TH_TH_ # u-nu-thai ".

WICHTIGES UPDATE : Dies wird laut Dokumentation für die Verwendung in Java 7+ nicht empfohlen :

Insbesondere Clients, die die Ausgabe von toString in Sprach-, Länder- und Variantenfelder analysieren, können dies weiterhin tun (obwohl davon dringend abgeraten wird ), obwohl das Variantenfeld zusätzliche Informationen enthält, wenn Skripte oder Erweiterungen vorhanden sind.

Verwenden Sie stattdessen Locale.forLanguageTag und Locale.toLanguageTag oder, falls erforderlich, Locale.Builder.

Andy
quelle
5
Java 7 Locale.forLanguageTaggilt nur für Sprachtags , wie in IETF BCP 47, mit einem Bindestrich (angegeben codiert -), nicht ein Unterstrich ( _) , wie in der Rückkehr von Locale‚s toStringVerfahren
Jaime Hablützel
1
Du hast recht. Es muss noch eine Möglichkeit geben, die vorhandenen Gebietsschemadarstellungen in das BCP47-Format zu konvertieren. Meine Absicht war es vorzuschlagen, dass Locales in Zukunft nicht in ihrer toStringForm gespeichert werden sollten , sondern in ihrer toLanguageTagForm, die Localeeinfacher und genauer wieder in eine konvertierbar ist .
andy
Hätte diese Methode nicht eine Reihe von Randfällen, die dazu führen könnten, dass der Index außerhalb der Grenzen liegt?
user2524908
@ user2524908: Ich glaube nicht, da er immer die Array-Länge testet, bevor er auf seine Elemente zugreift. Die Lösung hat möglicherweise viele
Randfälle, in
9

Wenn Sie Spring Framework in Ihrem Projekt verwenden, können Sie auch Folgendes verwenden:

org.springframework.util.StringUtils.parseLocaleString("en_US");

Dokumentation :

Analysieren Sie die angegebene String-Darstellung in ein Gebietsschema

Javad Alimohammadi
quelle
Die Dokumente dazu sagen, dass es speziell das Gegenteil von Locale#toString()- perfekt ist! :)
jocull
3

Es scheint keine statische valueOfMethode dafür zu geben, was ein bisschen überraschend ist.

Ein ziemlich hässlicher, aber einfacher Weg wäre, zu iterieren Locale.getAvailableLocales()und ihre toStringWerte mit Ihrem Wert zu vergleichen.

Nicht sehr schön, aber kein String-Parsing erforderlich. Sie können eine MapZeichenfolge in Gebietsschemas vorab ausfüllen und Ihre Datenbankzeichenfolge in dieser Zuordnung nachschlagen.

Skaffman
quelle
Ah, die Iteration könnte eine vernünftige Lösung sein. In der Tat ist es überraschend, dass Locale keine statische Methode dafür hat.
Joonas Pulakka
Die vordefinierten LocaleInstanzen stellen nur eine sehr kleine Teilmenge gültiger Gebietsschemas dar. Es ist keineswegs vollständig.
BetaRide
3

Sie können dies auf Android verwenden. Funktioniert gut für mich.

private static final Pattern localeMatcher = Pattern.compile
        ("^([^_]*)(_([^_]*)(_#(.*))?)?$");

public static Locale parseLocale(String value) {
    Matcher matcher = localeMatcher.matcher(value.replace('-', '_'));
    return matcher.find()
            ? TextUtils.isEmpty(matcher.group(5))
                ? TextUtils.isEmpty(matcher.group(3))
                    ? TextUtils.isEmpty(matcher.group(1))
                        ? null
                        : new Locale(matcher.group(1))
                    : new Locale(matcher.group(1), matcher.group(3))
                : new Locale(matcher.group(1), matcher.group(3),
                             matcher.group(5))
            : null;
}
Mein Gott
quelle
1

Nun, ich würde speichern , anstatt eine Zeichenfolge Verkettung Locale.getISO3Language(), getISO3Country()und getVariant () als Schlüssel, der mich zu letzteren Anruf erlauben würde Locale(String language, String country, String variant)Konstruktor.

Wenn Sie sich auf displayLanguage verlassen, müssen Sie für die Anzeige die Sprache des Gebietsschemas verwenden, wodurch das Gebietsschema im Gegensatz zum ISO-Sprachcode abhängig wird.

Als Beispiel wäre ein Gebietsschema-Schlüssel als speicherbar

en_EN
en_US

und so weiter ...

Riduidel
quelle
1

Weil ich es gerade implementiert habe:

In Groovy/ Grailses wäre:

def locale = Locale.getAvailableLocales().find { availableLocale ->
      return availableLocale.toString().equals(searchedLocale)
}
Martin L.
quelle