# 语言标记过滤和查找

> 原文： [https://docs.oracle.com/javase/tutorial/i18n/locale/matching.html](https://docs.oracle.com/javase/tutorial/i18n/locale/matching.html)

Java 编程语言包含对语言标记，语言标记过滤和语言标记查找的国际化支持。这些功能由 [IETF BCP 47](http://tools.ietf.org/html/bcp47) 指定，其中包含 [RFC 5646“识别语言标签”](http://tools.ietf.org/html/rfc5646)和 [RFC 4647“语言标签匹配”。](http://tools.ietf.org/html/rfc4647) 本课程介绍如何在 JDK 中提供此支持。

语言标签是特殊格式的字符串，提供有关特定语言的信息。语言标签可能是简单的（例如英语中的“en”），复杂的东西（例如中文中使用的“zh-cmn-Hans-CN”，普通话，简体中文），或介于两者之间的东西（例如“sr-Latn”，塞尔维亚语用拉丁文写成）。语言标签由连字符分隔的“子标签”组成;在整个 API 文档中使用此术语。

[`java.util.Locale`](https://docs.oracle.com/javase/8/docs/api/java/util/Locale.html) 类为语言标签提供支持。 `Locale`包含几个不同的字段：语言（例如英语的“en”或日语的“ja”），脚本（例如拉丁语的“Latn”或西里尔语的“Cyrl”），国家（例如“US”） “对于美国或法国的”FR“），变体（表示某种语言环境的变体）和扩展（它提供单个字符键到`String`值的映射，表示除语言识别之外的扩展）。要从语言标签`String`创建`Locale`对象，请调用 [`Locale.forLanguageTag(String)`](https://docs.oracle.com/javase/8/docs/api/java/util/Locale.html#forLanguageTag-java.lang.String-) ，将语言标记作为唯一参数传递。这样做会创建并返回一个新的`Locale`对象，以便在您的应用程序中使用。

例 1：

```
package languagetagdemo;

import java.util.Locale;

public class LanguageTagDemo {
     public static void main(String[] args) {
         Locale l = Locale.forLanguageTag("en-US");
     }
}

```

请注意，Locale API 仅要求您的语言标记在语法上格式良好。它不执行任何额外验证（例如检查标签是否在 IANA 语言子标签注册表中注册）。

语言范围（由类 [`java.util.Locale.LanguageRange`](https://docs.oracle.com/javase/8/docs/api/java/util/Locale.LanguageRange.html) 表示）标识共享特定属性的语言标记集。语言范围分为基本或扩展，与语言标签类似，因为它们由连字符分隔的子标签组成。基本语言范围的示例包括“en”（英语），“ja-JP”（日语，日本）和“*”（与任何语言标签匹配的特殊语言范围）。扩展语言范围的示例包括“* -CH”（任何语言，瑞士），“es- *”（西班牙语，任何地区）和“zh-Hant- *”（繁体中文，任何地区）。

此外，语言范围可以存储在语言优先级列表中，这使得用户能够在加权列表中优先考虑他们的语言偏好。语言优先级列表通过将`LanguageRange`对象放入 [`java.util.List`](https://docs.oracle.com/javase/8/docs/api/java/util/List.html) 来表示，然后可以将其传递给接受`LanguageRange` `LanguageRange`对象的`List`的`Locale`方法。

[`Locale.LanguageRange`](https://docs.oracle.com/javase/8/docs/api/java/util/Locale.LanguageRange.html) 类提供了两种不同的构造函数来创建语言范围：

*   `public Locale.LanguageRange(String range)`
*   `public Locale.LanguageRange(String range, double weight)`

它们之间的唯一区别是第二个版本允许指定权重;如果将范围放入语言优先级列表，则将考虑此权重。

`Locale.LanguageRange`还指定了一些与这些构造函数一起使用的常量：

*   `public static final double MAX_WEIGHT`
*   `public static final double MIN_WEIGHT`

`MAX_WEIGHT`常量保持值 1.0，表示它非常适合用户。 `MIN_WEIGHT`常量保持值 0.0，表示不是。

例 2：

```
package languagetagdemo;

import java.util.Locale;

public class LanguageTagDemo {

     public static void main(String[] args) {
         // Create Locale
         Locale l = Locale.forLanguageTag("en-US");

         // Define Some LanguageRange Objects
         Locale.LanguageRange range1 = new Locale.LanguageRange("en-US",Locale.LanguageRange.MAX_WEIGHT);
         Locale.LanguageRange range2 = new Locale.LanguageRange("en-GB*",0.5);
         Locale.LanguageRange range3 = new Locale.LanguageRange("fr-FR",Locale.LanguageRange.MIN_WEIGHT);
     }
}

```

示例 2 创建了三种语言范围：英语（美国），英语（英国）和法语（法国）。按照从最优选到最不优选的顺序对这些范围进行加权以表示用户的偏好。

您可以使用 [`LanguageRange.parse(String)`](https://docs.oracle.com/javase/8/docs/api/java/util/Locale.LanguageRange.html#parse-java.lang.String-) 方法从语言范围列表中创建语言优先级列表。此方法接受逗号分隔语言范围列表，对给定范围内的每个语言范围执行语法检查，然后返回新创建的语言优先级列表。

有关“范围”参数所需格式的详细信息，请参阅此方法的 API 规范。

例 3：

```
package languagetagdemo;

import java.util.Locale;

import java.util.List;

public class LanguageTagDemo {

    public static void main(String[] args) {

        // Create Locale

        Locale l = Locale.forLanguageTag("en-US");

        // Create a Language Priority List

        String ranges = "en-US;q=1.0,en-GB;q=0.5,fr-FR;q=0.0";

        List<Locale.LanguageRange> languageRanges = Locale.LanguageRange.parse(ranges)

    }
}

```

示例 3 创建与示例 2 相同的三种语言范围，但将它们存储在`String`对象中，该对象将传递给`parse(String)`方法。 `LanguageRange`对象的返回`List`是语言优先级列表。

语言标记过滤是将一组语言标记与用户的语言优先级列表进行匹配的过程。过滤结果将是所有匹配结果的完整列表。 `Locale`类定义了两个返回`Locale`对象列表的过滤器方法。他们的签名如下：

*   [`public static List&lt;Locale&gt; filter (List&lt;Locale.LanguageRange&gt; priorityList, Collection&lt;Locale&gt; locales)`](https://docs.oracle.com/javase/8/docs/api/java/util/Locale.html#filter-java.util.List-java.util.Collection-)
*   [`public static List&lt;Locale&gt; filter (List&lt;Locale.LanguageRange&gt; priorityList, Collection&lt;Locale&gt; locales, Locale.FilteringMode mode)`](https://docs.oracle.com/javase/8/docs/api/java/util/Locale.html#filter-java.util.List-java.util.Collection-java.util.Locale.FilteringMode-)

在这两种方法中，第一个参数指定用户的语言优先级列表，如上一节中所述。

第二个参数指定要匹配的`Locale`对象的`Collection`。匹配本身将根据 RFC 4647 指定的规则进行。

第三个参数（如果提供）指定要使用的“过滤模式”。 [`Locale.FilteringMode`](https://docs.oracle.com/javase/8/docs/api/java/util/Locale.FilteringMode.html) 枚举提供了许多不同的值可供选择，例如`AUTOSELECT_FILTERING`（用于基本语言范围过滤）或`EXTENDED_FILTERING`（用于扩展语言范围过滤）。

示例 4 提供了语言标记过滤的演示。

例 4：

```
package languagetagdemo;

import java.util.Locale;
import java.util.Collection;
import java.util.List;
import java.util.ArrayList;

public class LanguageTagDemo {

    public static void main(String[] args) {

        // Create a collection of Locale objects to filter
        Collection<Locale> locales = new ArrayList<>();
        locales.add(Locale.forLanguageTag("en-GB"));
        locales.add(Locale.forLanguageTag("ja"));
        locales.add(Locale.forLanguageTag("zh-cmn-Hans-CN"));
        locales.add(Locale.forLanguageTag("en-US"));

        // Express the user's preferences with a Language Priority List
        String ranges = "en-US;q=1.0,en-GB;q=0.5,fr-FR;q=0.0";
        List<Locale.LanguageRange> languageRanges = Locale.LanguageRange.parse(ranges);

        // Now filter the Locale objects, returning any matches
        List<Locale> results = Locale.filter(languageRanges,locales);

        // Print out the matches
        for(Locale l : results){
        System.out.println(l.toString());
        }
    }
}

```

该程序的输出是：

en_US
en_GB

此返回列表根据用户的语言优先级列表中指定的权重进行排序。

`Locale`类还定义了用于将语言标签过滤为`String`对象的`filterTags`方法。

方法签名如下：

*   [`public static List&lt;String&gt; filterTags (List&lt;Locale.LanguageRange&gt; priorityList, Collection&lt;String&gt; tags)`](https://docs.oracle.com/javase/8/docs/api/java/util/Locale.html#filterTags-java.util.List-java.util.Collection-)
*   [`public static List&lt;String&gt; filterTags (List&lt;Locale.LanguageRange&gt; priorityList, Collection&lt;String&gt; tags, Locale.FilteringMode mode)`](https://docs.oracle.com/javase/8/docs/api/java/util/Locale.html#filterTags-java.util.List-java.util.Collection-java.util.Locale.FilteringMode-)

示例 5 提供与示例 4 相同的搜索，但使用`String`对象而不是`Locale`对象。

例 5：

```
package languagetagdemo;

import java.util.Locale;
import java.util.Collection;
import java.util.List;
import java.util.ArrayList;

public class LanguageTagDemo {

    public static void main(String[] args) {

        // Create a collection of String objects to match against
        Collection<String> tags = new ArrayList<>();
        tags.add("en-GB");
        tags.add("ja");
        tags.add("zh-cmn-Hans-CN");
        tags.add("en-US");

        // Express user's preferences with a Language Priority List
        String ranges = "en-US;q=1.0,en-GB;q=0.5,fr-FR;q=0.0";
        List<Locale.LanguageRange> languageRanges = Locale.LanguageRange.parse(ranges);

        // Now search the locales for the best match
        List<String> results = Locale.filterTags(languageRanges,tags);

        // Print out the matches
        for(String s : results){
            System.out.println(s);
        }
    }
} 

```

和以前一样，搜索将匹配并返回“en-US”和“en-GB”（按此顺序）。

与语言标记过滤相反，语言标记查找是将语言范围与语言标记集匹配并返回与该范围最匹配的一种语言标记的过程。 RFC4647 声明：“Lookup 从可用标记列表中生成最符合用户首选项的单个结果，因此在需要单个项目（并且只能返回单个项目）的情况下，它非常有用。”例如，如果一个进程要将一个人类可读的错误消息插入到协议头中，它可能会根据用户的语言优先级列表选择文本。由于该进程只能返回一个项目，因此它被强制选择一个项目，它必须返回一些项目，即使内容的语言标签都没有与用户提供的语言优先级列表相匹配。“

例 6：

```
package languagetagdemo;

import java.util.Locale;
import java.util.Collection;
import java.util.List;
import java.util.ArrayList;

public class LanguageTagDemo {

    public static void main(String[] args) {

        // Create a collection of Locale objects to search
        Collection<Locale> locales = new ArrayList<>();
        locales.add(Locale.forLanguageTag("en-GB"));
        locales.add(Locale.forLanguageTag("ja"));
        locales.add(Locale.forLanguageTag("zh-cmn-Hans-CN"));
        locales.add(Locale.forLanguageTag("en-US"));

        // Express the user's preferences with a Language Priority List
        String ranges = "en-US;q=1.0,en-GB;q=0.5,fr-FR;q=0.0";
        List<Locale.LanguageRange> languageRanges = Locale.LanguageRange.parse(ranges);

        // Find the BEST match, and return just one result
        Locale result = Locale.lookup(languageRanges,locales);
        System.out.println(result.toString());
    }
}

```

与过滤示例相反，示例 6 中的查找演示返回最匹配的一个对象（在这种情况下为`en-US`）。对于 completenes，示例 7 显示了如何使用`String`对象执行相同的查找。

例 7：

```
package languagetagdemo;

import java.util.Locale;
import java.util.Collection;
import java.util.List;
import java.util.ArrayList;

public class LanguageTagDemo {

    public static void main(String[] args) {
        // Create a collection of String objects to match against
        Collection<String> tags = new ArrayList<>();
        tags.add("en-GB");
        tags.add("ja");
        tags.add("zh-cmn-Hans-CN");
        tags.add("en-US");

        // Express user's preferences with a Language Priority List
        String ranges = "en-US;q=1.0,en-GB;q=0.5,fr-FR;q=0.0";
        List<Locale.LanguageRange> languageRanges = Locale.LanguageRange.parse(ranges);

        // Find the BEST match, and return just one result
        String result = Locale.lookupTag(languageRanges, tags);
        System.out.println(result);
    }
} 

```

此示例返回与用户的语言优先级列表最匹配的单个对象。