Doug Tidwell , 高级程序员, IBM 大学合作部
2006 年 1 月 04 日
本文讨论将正则表达式与 Java ResourceBundle
相结合的一种数据验证技术。Java 语言对正则表达式的支持可以大大简化数据验证。您可以将数据与正则表达式进行比较,如果它们匹配,则知道数据是有效的。另一方面,Java ResourceBundle
包含翻译好的字符串,用于匹配用户机器上的当前语言和国家设置。ResourceBundle
中的字符串通常是出现在应用程序中的文本,但是也可以是特定于某个地区的任何东西。
您将实践一个示例应用程序,该应用程序从 ResourceBundles
获得正则表达式,并将它们用于数据验证(请参见 下载 小节)。通过这种方法,就可以用一块代码来验证很多不同类型的数据。更妙的是,随着更多 ResourceBundle
的添加,还可以验证更多类型的数据,并且不用更改这段代码中的任何一行。
本文的示例应用程序是在 Eclipse 中用 Visual Editor 构建的。Visual Editor 是一种用于构建图形化界面的开放源码工具。为了构建自己的应用程序,您需要在计算机上安装 Eclipse 和 Visual Editor 包(请参阅 参考资料)。这个示例应用程序只是举例说明了验证数据的一种技巧,所以这种方法可用于任何 Java 应用程序。
我不想花太多的时间讨论这个示例应用程序的所有细节,我只关注其中的数据验证方面的技巧。这个应用程序验证输入到输入域中的邮政编码。您可能知道,在世界的不同地方,邮政编码千差万别。有的是数字,有的则包含字母。即使同是由数字组成的邮政编码,在不同地方其长度也不尽相同。有的国家以特定的模式排列字母和数字,而另外一些国家则采用更自由的格式。所有这些格式都可以用正则表达式来描述。例如,在美国邮政编码是一个五位数,后面还可能跟有一个破折号加一个四位数。清单 1 展示了描述这种格式的正则表达式:
|
除了格式不同外,邮政编码并不总是被称为邮政编码。例如,美国将邮政编码称为 ZIP Code。ResourceBundle
的一种常见用法就是处理这种类型的与地区有关的差异。用于美国的 ResourceBundle
可能包含短语 "Enter your ZIP Code",而在用于加拿大的 ResourceBundle
中,相应的短语可能是 "Enter your postal code"。我在本文中演示的技巧也是从 ResourceBundle
获得用于有效邮政编码的正则表达式。
为了使这个示例简单化,您将创建一个只有一个输入域和一个 Validate 按钮的 Swing 应用程序。用户在输入域中输入文本,然后单击该按钮。如果数据与当前的正则表达式匹配,则应用程序显示一条消息,表明邮政编码有效。因为应用程序使用不同的 ResourceBundle
,所以正则表达式随着有效数据的规则的变化而变化。由于正则表达式是从文本文件中装载的一个字符串,所以当添加对新类型的邮政编码的支持时,不需要更改代码。
您将在 Eclipse 中使用 Eclipse Visual Editor 和 Eclipse Java Development Tool 的一些特性来构建这个应用程序。您可以在几乎所有开发环境中使用这种技巧。这里的代码应该可以在任何基于 Eclipse 的产品中运行,例如 Rational Application Developer(请参阅 参考资料)。
图 1 展示了该应用程序在 Eclipse Visual Editor 中的样子:
图 1. Eclipse Visual Editor 中的示例应用程序
Visual Editor 提供了四种查看应用程序的方式。在屏幕的顶端是应用程序的可视化图像,源代码在底端。Eclipse 还提供了两个视图 —— Properties 视图和 Java Beans 视图 —— 可以通过这两个视图来处理应用程序。所有这些查看应用程序的方式都是由 Eclipse Modeling Framework (EMF) 控制的。由于已经有一些关于 EMF 的完整书籍,所以我不会再谈更多的细节。从程序员的角度来看,重要的一点是,任何视图中的变化都会自动发送到其他视图。例如,如果您使用 Properties 视图将一个对象的背景颜色设为绿色,那么可视化图像和源代码也会自动更新。
首先来看一个已经创建好的应用程序(参见 下载 小节)。图 2 展示了这个应用程序的运行界面:
在图 2 中,用户输入了有效的数据,并单击了 Validate 按钮。如果数据无效,那么将出现图 3 所示的界面:
清单 2 展示了如何使用 清单 1 中的正则表达式来验证数据:
|
清单 2 中的两条反馈消息通常会被翻译成其他语言。您还将通过使用这里展示的技巧来 “翻译” 正则表达式。与一般的翻译不同,将正则表达式转换成国际化版本是数据格式专家的工作,而不是语言专家的工作。
Eclipse 为代码的国际化提供了一个方便的特性。首先单击 Source > Externalize Strings...,如图 4 所示:
图 4. Externalize Strings... 主菜单
Eclipse 查看 Java 代码,以发现应该放入到 ResourceBundle
中的字符串。您将看到类似图 5 所示的对话框:
在图 5 中列出的所有字符串中,对话框顶部的空白字符串不需要翻译。(反馈消息的初始值是一个空白字符串。)取消对第一个字符串的选择,然后单击 Next 和 Finish。Eclipse 创建一个新的名为 com.ibm.developerworks.Messages
的类,这个类从 messages.properties 文件获取字符串。
具体化代码之后,Eclipse 修改初始的类,将字符串移入 messages.properties 文件,并创建一个名为 Messages
的新类。Messages
类有一个名为 getString()
的静态方法,应用程序将使用该方法来获得字符串的值。
Messages
类在内部使用 ResourceBundle
。清单 3 展示了生成的用于创建 ResourceBundle
的代码:
|
稍后我将更详细地谈到如何创建 ResourceBundle
。
所有字符串的值都在 messages.properties 文件中,如清单 4 所示:
|
从技术上说,该文件是 com/ibm/developerworks/messages.properties,但是您不必关心这个细节。生成的代码可以正确无误地找到该文件。
当使用 Eclipse Externalize Strings 功能创建 .properties 文件时,它修改了应用程序,以便同时获取正则表达式和程序中所有其他可翻译的文本,如清单 5 所示:
清单 5. 通过 ResourceBundle 使用正则表达式
|
注意,Pattern.compile()
方法使用 Messages.getString()
方法来获得正则表达式的值。当需要验证数据时,代码首先获得字符串 LocalizedValidator.3
,然后使用它来验证邮政编码。反馈消息也是从 properties 文件获得的。
至此,主应用程序已经可以使用 “翻译” 好的正则表达式了。所有字符串的值都来自 messages.properties 文件,那么,如何装载这些字符串的不同版本呢?答案取决于 ResourceBundle
是如何创建的。
无论何时运行一个 Java 程序,它都有一个特定的地区。地区由两个字母的语言代码和两个字母的国家代码来指定,这些代码是由 ISO 标准定义的。地区代码还有一个不常用的变种部分,用于更精确地指定特定的地区。下面是一些例子:
en_US
是 U.S. English 地区。en_CA
是 Canadian English 地区。fr_CA
是 French Canadian 地区。en
是 English 地区。en_US_UNIX
是 U.S. English 地区的 UNIX 变种。至于该变种的意义及其用法,是由应用程序的编写者定义的。
当创建一个新的 ResourceBundle
时,Java 运行时根据当前的地区查找文件。例如,如果当前地区是 en_US
,那么 Java 运行时依次查找以下文件:
- messages_en_US.properties
- messages_en.properties
- messages.properties
当 ResourceBundle
收集翻译好的字符串时,在 messages_en_US.properties 中发现的任何字符串都具有比 messages_en.properties 和 messages.properties 中具有相同名称的字符串更高的优先级。如果运行时没有发现任何特定于地区的文件,那么它将使用 messages.properties 中的字符串。
记住,创建 ResourceBundle
的代码指定了文件名 messages.properties。该文件名不会随着地区的改变而改变,这意味着您的代码也不需要做出更改。您只需指定这个文件名,Java 运行时可以自动得出应该装载哪个特定于地区的文件。
一个特定于地区的 .properties 文件只包含不同于更通用的 .properties 文件的字符串。例如,如果 messages_en.properties 文件包含 LocalizedValidator.9=What is your favorite color?
这一行,那么 messages_en_GB.properties 文件可能包含 LocalizedValidator.9=What is your favourite colour?
。如果只有这个英国化的字符串是 en_GB
地区所特有的,那么 messages_en_GB.properties 文件只需包含这个字符串。当代码向 ResourceBundle
请求任何其他字符串时,如果 messages_en.properties
中有这样的字符串,就使用其中的字符串。如果 messages_en.properties 文件中没有那样的字符串,则使用 messages.properties 中的版本。如果这一系列的 .properties 文件中都没有被请求的字符串,就会抛出 java.util.MissingResourceException
异常。
清单 6 展示了美国地区的 .properties 文件所特有的一些行:
|
这里惟一的变化是使用 "ZIP Code" 代替 "postal code"。可用默认的正则表达式验证该数据。
英国的邮政编码有六种不同的格式,还有一个特殊的值 GIR 0AA
,如清单 7 所示。(为了便于阅读,清单 7 中的正则表达式被分成两行,实际上只有一行。)
|
用于澳大利亚的正则表达式包括州或地区的简称,需要的空格(一个或两个),以及一个四位数,如清单 8 所示:
|
加拿大的邮政编码格式是字母、数字、字母、一个空格、数字、字母、数字,如清单 9 所示:
|
清单 10 展示了德国地区特有的值。德国的邮政编码是一个五位数:
|
在运行时设置地区
现在您已经定义了 .properties 文件,接下来应该用两种方法中的一种来测试这些文件。第一种方法是在运行应用程序的时候设置 user.language
和 user.country
这两个系统属性。在 Eclipse 环境中,可以右键单击一个类名,然后选择 Run... 菜单,如图 6 所示:
在 Run 对话框中,可以设置 Java VM 选项,以改变默认的语言和地区,如图 7 所示:
-D
选项用于定义系统属性。您可以在命令行中使用相同的语法,例如:
|
第二种方法是在应用程序中设置地区。通过 Locale.setDefault()
方法可以在代码中设置默认的地区。清单 11 展示了如何改变 LocalizedValidator
类的 main()
方法:
|
如果在命令行没有指定参数,则使用用户计算机的默认地区。如果没有命令行参数,则代码 new Locale("", "")
只是创建默认的地区。
也可以在 Run 对话框中设置命令行参数,如图 8 所示:
图 9 展示了指定了参数 en AU
的情况下应用程序的界面:
用参数 de
运行示例应用程序时,将得到如图 10 所示的界面:
本文展示了如何将正则表达式与 Java 语言的国际化支持相结合来验证不同类型的本地化数据。通过这种技巧,您可以支持新的数据类型,而不用更改任何代码。例如示例应用程序,如果您想添加对波兰的邮政编码的支持,那么只需创建一个 messages_pl.properties 文件。这样就在没有更改任何代码的情况下添加了对新数据类型的支持。(如果您想知道的话,那么告诉您,用于波兰的邮政编码的正则表达式是 [0-9]{2}-?[0-9]{3}
。)
示例应用程序原封不动地使用 Eclipse 生成的 Messages
类。这个类能满足这个例子的要求,但是,应用程序启动时会装载 ResourceBundle
,并且直到下次运行应用程序时才能重新装载 ResourceBundle
。如果您想更改代码,以便动态地改变 ResourceBundle
,那么需要修改 Messages
类,使它的字段和方法不是静态的。这做起来不难,但是您还需要修改和维护 Messages.java 文件。就把这个任务作为练习吧。
还应该认识到,Swing 提供了 javax.swing.JFormattedTextField
类。利用这个类可以为文本域定义一个掩码。例如,您可以使用掩码 (###) ###-####
,使用户只能在文本域中输入有效的美国的电话号码。您可以使用与这里相同的技巧来从一个本地化的 ResourceBundle
中获得掩码字符串。
JFormattedTextField
类有明显的优势,因为它可以在用户输入时验证数据,为用户提供直接的反馈。但是掩码字符串不如正则表达式那么灵活。例如,您可以为美国的 ZIP Code 编写掩码 #####
或 #####-####
,但是不能同时使用这两个掩码。如果一个掩码字符串足以处理一组本地化数据类型,那么从 ResourceBundle
获得掩码字符串就是本技巧的一个很好的用途。(请参阅 参考资料,以找到关于扩展 JFormattedTextField
类的行为的文章。)
描述 | 名字 | 大小 | 下载方法 |
---|---|---|---|
The final version of the sample application | j-validating-LocalizedValidator.zip | 14KB | FTP |
The original (nonlocalized) version of the sample | j-Validator.zip | 7KB | FTP |
![]() | ||||
![]() | 关于下载方法的信息 | ![]() | ![]() | 获取 Adobe® Reader® |