利用正则表达式验证当地化数据
副标题#e#
本文接头将正则表达式与 Java ResourceBundle 相团结的一种数据验证技能 。Java 语言对正则表达式的支持可以大大简化数据验证。您可以将数据与正则 表达式举办较量,假如它们匹配,则知道数据是有效的。另一方面,Java ResourceBundle 包括翻译好的字符串,用于匹配用户呆板上的当前语言和国度 配置。ResourceBundle 中的字符勾凡是是呈此刻应用措施中的文本,可是也可 以是特定于某个地域的任何对象。
您将实践一个示例应用措施,该应用措施从 ResourceBundles 得到正则表达 式,并将它们用于数据验证(请拜见 下载 小节)。通过这种要领,就可以用一 块代码来验证许多差异范例的数据。更妙的是,跟着更多 ResourceBundle 的添 加,还可以验证更多范例的数据,而且不消变动这段代码中的任何一行。
本文的示例应用措施是在 Eclipse 顶用 Visual Editor 构建的。Visual Editor 是一种用于构建图形化界面的开放源码东西。为了构建本身的应用措施 ,您需要在计较机上安装 Eclipse 和 Visual Editor 包(请参阅 参考资料) 。这个示例应用措施只是举例说明白验证数据的一种能力,所以这种要领可用于 任何 Java 应用措施。
示例应用措施
我不想花太多的时间接头这个示例应用措施的所有细节,我只存眷个中的数 据验证方面的能力。这个应用措施验证输入到输入域中的邮政编码。您大概知道 ,活着界的差异处所,邮政编码千差万别。有的是数字,有的则包括字母。纵然 同是由数字构成的邮政编码,在差异处所其长度也不尽沟通。有的国度以特定的 模式分列字母和数字,而别的一些国度则回收更自由的名目。所有这些名目都可 以用正则表达式来描写。譬喻,在美国邮政编码是一个五位数,后头还大概跟有 一个破折号加一个四位数。清单 1 展示了描写这种名目标正则表达式:
清单 1. 用于美国邮政编码的正则表达式
[0-9]{5}(-[0-9]{4})?
除了名目差异外,邮政编码并不老是被称为邮政编码。譬喻,美国将邮政编 码称为 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 视图将一个工具的配景颜 色设为绿色,那么可视化图像和源代码也会自动更新。
#p#副标题#e#
运行初始的示例应用措施
首先来看一个已经建设好的应用措施(拜见 下载 小节)。图 2 展示了这个 应用措施的运行界面:
图 2. 输入有效数据时的示例应用措施
在图 2 中,用户输入了有效的数据,并单击了 Validate 按钮。假如数据无 效,那么将呈现图 3 所示的界面:
图 3. 输入无效数据时的示例应用措施
清单 2 展示了如何利用 清单 1 中的正则表达式来验证数据:
清单 2. 利用正则表达式
#p#分页标题#e#
Pattern pc = Pattern.compile("[0-9]{5}(-[0-9]{4})? ");
Matcher m = pc.matcher(postalCode.getText());
if (m.matches())
{
validLabel.setText("Your postal code is valid.");
validLabel.setForeground(Color.BLUE);
}
else
{
validLabel.setText("Your postal code is not valid.");
validLabel.setForeground(Color.RED);
}
清单 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
public class Messages {
private static final String BUNDLE_NAME =
"com.ibm.developerworks.messages"; //$NON-NLS-1$
private static final ResourceBundle RESOURCE_BUNDLE =
ResourceBundle.getBundle(BUNDLE_NAME);
稍后我将更具体地谈到如何建设 ResourceBundle。
所有字符串的值都在 messages.properties 文件中,如清单 4 所示:
清单 4. messages.properties 文件
LocalizedValidator.1=News Gothic
LocalizedValidator.2=Validate
LocalizedValidator.3=[0-9]{5}(-[0-9]{4})?
LocalizedValidator.4=Your postal code is valid.
LocalizedValidator.5=Your postal code is not valid.
LocalizedValidator.6=Exit
LocalizedValidator.7=Localized Data Validator
LocalizedValidator.8=Enter your postal code, then click Validate:
从技能上说,该文件是 com/ibm/developerworks/messages.properties,但 是您不必体贴这个细节。生成的代码可以正确无误地找到该文件。
利用 ResourceBundle 来验证数据
当利用 Eclipse Externalize Strings 成果建设 .properties 文件时,它 修改了应用措施,以便同时获取正则表达式和措施中所有其他可翻译的文本,如 清单 5 所示:
清单 5. 通过 ResourceBundle 利用正则表达式
Pattern pc = Pattern.compile(Messages.getString ("LocalizedValidator.3"));
//$NON-NLS-1$
Matcher m = pc.matcher(postalCode.getText());
if (m.matches())
{
validLabel.setText(Messages.getString ("LocalizedValidator.4"));
//$NON-NLS-1$
validLabel.setForeground(Color.BLUE);
}
else
{
validLabel.setText(Messages.getString ("LocalizedValidator.5"));
//$NON-NLS-1$
validLabel.setForeground(Color.RED);
}
留意,Pattern.compile() 要领利用 Messages.getString() 要领来得到正 则表达式的值。当需要验证数据时,代码首先得到字符串 LocalizedValidator.3,然后利用它来验证邮政编码。反馈动静也是从 properties 文件得到的。
如何装载 .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
#p#分页标题#e#
当 ResourceBundle 收集翻译好的字符串时,在 messages_en_US.properties 中发明的任何字符串都具有比 messages_en.properties 和 messages.properties 中具有沟通名称的字符串更 高的优先级。假如运行时没有发明任何特定于地域的文件,那么它将利用 messages.properties 中的字符串。
记着,建设 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(美国)地域特有的值
LocalizedValidator.4=Your ZIP Code is valid.
LocalizedValidator.5=Your ZIP Code is not valid.
LocalizedValidator.8=Enter your ZIP Code, then click Validate:
这里惟一的变革是利用 "ZIP Code" 取代 "postal code"。可用默认的正则表达式验证该数据。
英国的邮政编码有六种差异的名目,尚有一个非凡的值 GIR 0AA,如清单 7 所示。(为了便于阅读,清单 7 中的正则表达式被分成两行,实际上只有一行 。)
清单 7. en_GB(英国)地域特有的值
LocalizedValidator.3=
[A-Z]([0-9]|[0-9]{2}|[A-Z][0-9]|[A-Z][0-9]{2}|[0-9][A-Z]
|[A-Z][0-9][A-Z]) [0-9][A-Z]{2}|GIR 0AA
LocalizedValidator.8=Enter your postcode, then click Validate:
用于澳大利亚的正则表达式包罗州或地域的简称,需要的空格(一个或两个 ),以及一个四位数,如清单 8 所示:
清单 8. en_AU(澳大利亚)地域特有的值
LocalizedValidator.3=(ACT|NSW|NT|QLD|SA|TAS|VIC|WA)( | )[0- 9]{4}
LocalizedValidator.8=Enter your Australian postal code, then click Validate:
加拿大的邮政编码名目是字母、数字、字母、一个空格、数字、字母、数字 ,如清单 9 所示:
清单 9. en_CA(加拿大)地域特有的值
LocalizedValidator.3=[A-Z][0-9][A-Z] [0-9][A-Z][0-9]
LocalizedValidator.8=Enter your Canadian postal code, then click Validate:
清单 10 展示了德国地域特有的值。德国的邮政编码是一个五位数:
清单 10. de(德国)地域特有的值
LocalizedValidator.2=Validieren
LocalizedValidator.3=[0-9]{5}
LocalizedValidator.4=Ihre Postleitzahl ist gÜltig
LocalizedValidator.5=Ihre Postleitzahl ist ungÜltig!
LocalizedValidator.6=Beenden
LocalizedValidator.7=NLS Datenvalidatung
LocalizedValidator.8=Geben Sie Ihre Postleitzahl ein
在运行时配置地域
此刻您已经界说了 .properties 文件,接下来应该用两种要领中的一种来测 试这些文件。第一种要领是在运行应用措施的时候配置 user.language 和 user.country 这两个系统属性。在 Eclipse 情况中,可以右键单击一个类名, 然后选择 Run… 菜单,如图 6 所示:
图 6. Run… 菜单
在 Run 对话框中,可以配置 Java VM 选项,以改变默认的语言和地域,如 图 7 所示:
图 7. 在 Run 对话框中配置 Java VM 参数
-D 选项用于界说系统属性。您可以在呼吁行中利用沟通的语法,譬喻:
java -Duser.language=en -Duser.country=AU com.ibm.developerworks.LocalizedValidator
#p#分页标题#e#
第二种要领是在应用措施中配置地域。通过 Locale.setDefault() 要领可以 在代码中配置默认的地域。清单 11 展示了如何改变 LocalizedValidator 类的 main() 要领:
清单 11. 在应用措施中配置默认的地域
public static void main(String[] args) {
String language = "";
String country = "";
if (args.length > 0)
language = args[0];
if (args.length > 1)
country = args[1];
Locale.setDefault(new Locale(language, country));
LocalizedValidator nv = new LocalizedValidator();
nv.show();
}
假如在呼吁行没有指定参数,则利用用户计较机的默认地域。假如没有呼吁 行参数,则代码 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 得到掩码字符串就是本能力的一个很好的用途。(请参阅 参考 资料,以找到关于扩展 JFormattedTextField 类的行为的文章。)
本文配套源码