Java中使用正則表達式驗證本地化數據
數據驗證是編寫任何用戶界面時經常要處理的一項雜務。Java? 語言的正則表達式支持可以使數據驗證變得更容易。您可以定義一個正則表達式,用于描述有效數據,然后讓 Java 運行時檢查它是否匹配。但是有些類型的數據在不同地區有不同的格式。而 ResourceBundle 類讓您可以以一種優雅的方式使用特定于地區的數據。本文展示如何結合這兩種技術來解決常見的數據輸入問題。
本文討論將正則表達式與 Java ResourceBundle 相結合的一種數據驗證技術。Java 語言對正則表達式的支持可以大大簡化數據驗證。您可以將數據與正則表達式進行比較,如果它們匹配,則知道數據是有效的。另一方面,Java ResourceBundle 包含翻譯好的字符串,用于匹配用戶機器上的當前語言和國家設置。ResourceBundle 中的字符串通常是出現在應用程序中的文本,但是也可以是特定于某個地區的任何東西。
您將實踐一個示例應用程序,該應用程序從 ResourceBundles 獲得正則表達式,并將它們用于數據驗證。通過這種方法,就可以用一塊代碼來驗證很多不同類型的數據。更妙的是,隨著更多 ResourceBundle 的添加,還可以驗證更多類型的數據,并且不用更改這段代碼中的任何一行。
本文的示例應用程序是在 Eclipse 中用 Visual Editor 構建的。Visual Editor 是一種用于構建圖形化界面的開放源碼工具。為了構建自己的應用程序,您需要在計算機上安裝 Eclipse 和 Visual Editor 包。這個示例應用程序只是舉例說明了驗證數據的一種技巧,所以這種方法可用于任何 Java 應用程序。
示例應用程序
我不想花太多的時間討論這個示例應用程序的所有細節,我只關注其中的數據驗證方面的技巧。這個應用程序驗證輸入到輸入域中的郵政編碼。您可能知道,在世界的不同地方,郵政編碼千差萬別。有的是數字,有的則包含字母。即使同是由數字組成的郵政編碼,在不同地方其長度也不盡相同。有的國家以特定的模式排列字母和數字,而另外一些國家則采用更自由的格式。所有這些格式都可以用正則表達式來描述。例如,在美國郵政編碼是一個五位數,后面還可能跟有一個破折號加一個四位數。清單 1 展示了描述這種格式的正則表達式:
清單 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. 輸入有效數據時的示例應用程序

在圖 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 標準定義的。地區代碼還有一個不常用的變種部分,用于更精確地指定特定的地區。下面是一些例子:
記住,創建 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 獲得掩碼字符串就是本技巧的一個很好的用途。
本文討論將正則表達式與 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 視圖將一個對象的背景顏色設為綠色,那么可視化圖像和源代碼也會自動更新。
運行初始的示例應用程序
首先來看一個已經創建好的應用程序。圖 2 展示了這個應用程序的運行界面:
圖 2. 輸入有效數據時的示例應用程序

在圖 2 中,用戶輸入了有效的數據,并單擊了 Validate 按鈕。如果數據無效,那么將出現圖 3 所示的界面:
圖 3. 輸入無效數據時的示例應用程序

清單 2 展示了如何使用 清單 1 中的正則表達式來驗證數據:
清單 2. 使用正則表達式
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 變種。至于該變種的意義及其用法,是由應用程序的編寫者定義的。
- messages_en_US.properties
- messages_en.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 |
第二種方法是在應用程序中設置地區。通過 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 獲得掩碼字符串就是本技巧的一個很好的用途。