Java中使用正则表达式验证本地化数据
|
数据验证是编写任何用户界面时经常要处理的一项杂务。Java? 语言的正则表达式支持可以使数据验证变得更容易。您可以定义一个正则表达式,用于描述有效数据,然后让 Java 运行时检查它是否匹配。但是有些类型的数据在不同地区有不同的格式。而 ResourceBundle 类让您可以以一种优雅的方式使用特定于地区的数据。本文展示如何结合这两种技术来解决常见的数据输入问题。
除了格式不同外,邮政编码并不总是被称为邮政编码。例如,美国将邮政编码称为 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. 输入有效数据时的示例应用程序 ![]() 在图 2 中,用户输入了有效的数据,并单击了 Validate 按钮。如果数据无效,那么将出现图 3 所示的界面: 图 3. 输入无效数据时的示例应用程序 ![]() 清单 2 展示了如何使用 清单 1 中的正则表达式来验证数据: 清单 2. 使用正则表达式
清单 2 中的两条反馈消息通常会被翻译成其他语言。您还将通过使用这里展示的技巧来 “翻译” 正则表达式。与一般的翻译不同,将正则表达式转换成国际化版本是数据格式专家的工作,而不是语言专家的工作。 具体化字符串 Eclipse 为代码的国际化提供了一个方便的特性。首先单击 Source > Externalize Strings...,如图 4 所示: 图 4. Externalize Strings... 主菜单 ![]() Eclipse 查看 Java 代码,以发现应该放入到 ResourceBundle 中的字符串。您将看到类似图 5 所示的对话框: 图 5. Externalize Strings 对话框 ![]() 在图 5 中列出的所有字符串中,对话框顶部的空白字符串不需要翻译。(反馈消息的初始值是一个空白字符串。)取消对第一个字符串的选择,然后单击 Next 和 Finish。Eclipse 创建一个新的名为 com.ibm.developerworks.Messages 的类,这个类从 messages.properties 文件获取字符串。 处理国际化代码 具体化代码之后,Eclipse 修改初始的类,将字符串移入 messages.properties 文件,并创建一个名为 Messages 的新类。Messages 类有一个名为 getString() 的静态方法,应用程序将使用该方法来获得字符串的值。 Messages 类在内部使用 ResourceBundle。清单 3 展示了生成的用于创建 ResourceBundle 的代码: 清单 3. 创建 ResourceBundle
稍后我将更详细地谈到如何创建 ResourceBundle。 所有字符串的值都在 messages.properties 文件中,如清单 4 所示: 清单 4. messages.properties 文件
从技术上说,该文件是 com/ibm/developerworks/messages.properties,但是您不必关心这个细节。生成的代码可以正确无误地找到该文件。 使用 ResourceBundle 来验证数据 当使用 Eclipse Externalize Strings 功能创建 .properties 文件时,它修改了应用程序,以便同时获取正则表达式和程序中所有其他可翻译的文本,如清单 5 所示: 清单 5. 通过 ResourceBundle 使用正则表达式
注意,Pattern.compile() 方法使用 Messages.getString() 方法来获得正则表达式的值。当需要验证数据时,代码首先获得字符串 LocalizedValidator.3,然后使用它来验证邮政编码。反馈消息也是从 properties 文件获得的。 如何装载 .properties 文件 至此,主应用程序已经可以使用 “翻译” 好的正则表达式了。所有字符串的值都来自 messages.properties 文件,那么,如何装载这些字符串的不同版本呢?答案取决于 ResourceBundle 是如何创建的。 无论何时运行一个 Java 程序,它都有一个特定的地区。地区由两个字母的语言代码和两个字母的国家代码来指定,这些代码是由 ISO 标准定义的。地区代码还有一个不常用的变种部分,用于更精确地指定特定的地区。下面是一些例子:
[list=1] 记住,创建 ResourceBundle 的代码指定了文件名 messages.properties。该文件名不会随着地区的改变而改变,这意味着您的代码也不需要做出更改。您只需指定这个文件名,Java 运行时可以自动得出应该装载哪个特定于地区的文件。 特定于地区的 .properties 文件 一个特定于地区的 .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 文件所特有的一些行: 清单 6. en_US(美国)地区特有的值
这里惟一的变化是使用 "ZIP Code" 代替 "postal code"。可用默认的正则表达式验证该数据。 英国的邮政编码有六种不同的格式,还有一个特殊的值 GIR 0AA,如清单 7 所示。(为了便于阅读,清单 7 中的正则表达式被分成两行,实际上只有一行。) 清单 7. en_GB(英国)地区特有的值
用于澳大利亚的正则表达式包括州或地区的简称,需要的空格(一个或两个),以及一个四位数,如清单 8 所示: 清单 8. en_AU(澳大利亚)地区特有的值
加拿大的邮政编码格式是字母、数字、字母、一个空格、数字、字母、数字,如清单 9 所示: 清单 9. en_CA(加拿大)地区特有的值
清单 10 展示了德国地区特有的值。德国的邮政编码是一个五位数: 清单 10. de(德国)地区特有的值
在运行时设置地区 现在您已经定义了 .properties 文件,接下来应该用两种方法中的一种来测试这些文件。第一种方法是在运行应用程序的时候设置 user.language 和 user.country 这两个系统属性。在 Eclipse 环境中,可以右键单击一个类名,然后选择 Run... 菜单,如图 6 所示: 图 6. Run... 菜单 ![]() 在 Run 对话框中,可以设置 Java VM 选项,以改变默认的语言和地区,如图 7 所示: 图 7. 在 Run 对话框中设置 Java VM 参数 ![]() -D 选项用于定义系统属性。您可以在命令行中使用相同的语法,例如:
第二种方法是在应用程序中设置地区。通过 Locale.setDefault() 方法可以在代码中设置默认的地区。清单 11 展示了如何改变 LocalizedValidator 类的 main() 方法: 清单 11. 在应用程序中设置默认的地区
如果在命令行没有指定参数,则使用用户计算机的默认地区。如果没有命令行参数,则代码 new Locale("", "") 只是创建默认的地区。 也可以在 Run 对话框中设置命令行参数,如图 8 所示: 图 8. 在 Run 对话框中设置命令行参数 ![]() 图 9 展示了指定了参数 en AU 的情况下应用程序的界面: 图 9. 用于澳大利亚地区(en_AU)的示例应用程序 ![]() 用参数 de 运行示例应用程序时,将得到如图 10 所示的界面: 图 10. 用于德国地区(de)的示例应用程序 ![]() 结束语 本文展示了如何将正则表达式与 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 获得掩码字符串就是本技巧的一个很好的用途。 Tags:
JAVA
|










一共有 0 条评论