字符串排序
本文是Sun官方以Blog形式發(fā)布的Java核心技術竅門(JavaCoreTechTip)中的一個。我之前尚未關注過java.text.Collator類,看過Sorting Strings這個tip之后覺得有些意義,故翻譯在了此處,也希望對其它朋友有所助益。(2008.04.07最后更新)使用Java平臺進行字符串排序被認為是一件簡單的工作,但為國際市場開發(fā)程序時,則需要有更多的考慮。如果你陷入只關注英語的心態(tài)中,并認為你的程序會工作的很好,因為它所顯示的字符串從今往后都是一樣的,你可能認為一切都很正常。但一旦你有一位西班牙用戶,他希望能夠正常地對mañana進行排序,但如果你都是使用String類中缺省的compare方法去做排序,字符ñ將會跟在字符z之后,而在正常的西班牙語排序中,ñ應該在字符n和o之間。這就是java.text包的類Collator發(fā)揮作用的地方了。
想像這樣的一組詞
- first
- mañana
- man
- many
- maxi
- next
- first
- man
- many
- maxi
- mañana
- next
這就是類Collator能派上用場的地方了。類Collator用于對語言敏感的排序問題,并不會只基于它們的ASCII/Unicode字符去嘗試排序。 使用Collator要求你在完全應用它的特性之前要理解一個額外的屬性,即稱之為強度(Strength)的屬性。Collator的強度設置決定了在排序時如何使用強(或弱)匹配。 該屬性有4個可能的值:PRIMARY,SECONDARY,TERTIARY和IDENTICAL。具體是哪個強度在產生作用取決于語言環(huán)境。 典型地,會有如下的情況。按從后往前的順序,IDENTICAL強度表示能夠被進行相同的處理的字符必須是一致的。TERTIARY通常用于忽略大小寫差異。SECONDARY用于忽略變音符,如n和ñ。 PRIMARY與IDENTICAL相似也是基于字母之間差異,但是當處理控制字符和發(fā)音時還是有所不同。查看
Collator
的javadoc,
以獲取更多關于這些強度之間的差異及分解(Decomposition)模式規(guī)則的信息。
為了使用Collator,你需要先得到它的一個實例。你既可以調用getInstance方法以得到一個針對默認語言環(huán)境的Collator對象, 也可以傳遞一個指定的Locale對象給getInstance方法以得到一個針對特定語言環(huán)境的Collator對象。例如,為了獲得針對一個西班牙語的 Collator對象,你應使用new Locale("es")去創(chuàng)建一個西班牙語的Locale對象,然后將它傳入getInstance方法中:
Collator esCollator =
Collator.getInstance(new Locale("es"));
假設針對該語言環(huán)境的默認Collator強度,針對西班牙語的默認強度是SECONDARY已經足夠了。然后你將這個Collator對象如任一Comparator對象
那樣傳入Collections類的sort方法的比較規(guī)則參數中,以得到排序后的List對象。Collator.getInstance(new Locale("es"));
Collections.sort(list, esCollator);
操作之前的單詞列表,你現在就會得到一個基于西班牙語字母表的恰當排序結果:
- first
- man
- many
- mañana
- maxi
- next
這兒有一個簡潔的例子以顯示這些差異。 import java.awt.*;
import java.text.*;
import java.util.*;
import java.util.List; // Explicit import required
import javax.swing.*;
public class Sort {
public static void main(String args[]) {
Runnable runner = new Runnable() {
public void run() {
String words[] = {"first", "mañana", "man",
"many", "maxi", "next"};
List list = Arrays.asList(words);
JFrame frame = new JFrame("Sorting");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
Box box = Box.createVerticalBox();
frame.setContentPane(box);
JLabel label = new JLabel("Word List:");
box.add(label);
JTextArea textArea = new JTextArea( list.toString());
box.add(textArea);
Collections.sort(list);
label = new JLabel("Sorted Word List:");
box.add(label);
textArea = new JTextArea(list.toString ());
box.add(textArea);
Collator esCollator = Collator.getInstance(new Locale("es"));
Collections.sort(list, esCollator);
label = new JLabel("Collated Word List:");
box.add(label);
textArea = new JTextArea(list.toString());
box.add(textArea);
frame.setSize(400, 200);
frame.setVisible(true);
}
};
EventQueue.invokeLater (runner);
}
}
import java.util.*;
import java.util.List; // Explicit import required
import javax.swing.*;
public class Sort {
public static void main(String args[]) {
Runnable runner = new Runnable() {
public void run() {
String words[] = {"first", "mañana", "man",
"many", "maxi", "next"};
List list = Arrays.asList(words);
JFrame frame = new JFrame("Sorting");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
Box box = Box.createVerticalBox();
frame.setContentPane(box);
JLabel label = new JLabel("Word List:");
box.add(label);
JTextArea textArea = new JTextArea( list.toString());
box.add(textArea);
Collections.sort(list);
label = new JLabel("Sorted Word List:");
box.add(label);
textArea = new JTextArea(list.toString ());
box.add(textArea);
Collator esCollator = Collator.getInstance(new Locale("es"));
Collections.sort(list, esCollator);
label = new JLabel("Collated Word List:");
box.add(label);
textArea = new JTextArea(list.toString());
box.add(textArea);
frame.setSize(400, 200);
frame.setVisible(true);
}
};
EventQueue.invokeLater (runner);
}
}

String rule =
"< c, C < a, A < f, F < e, E";
RuleBasedCollator collator = new RuleBasedCollator(rule);
上述規(guī)則通過展示不同字母的大小寫定義了特定的字母順序為cafe。現在對單詞列表ace,cafe,ef和face使用新的規(guī)則進行排序,
排序結果的順序為cafe,ace,face和ef:"< c, C < a, A < f, F < e, E";
RuleBasedCollator collator = new RuleBasedCollator(rule);
import java.text.*;
import java.util.*;
public class Rule {
public static void main(String args[]) throws ParseException {
String words[] = {"ace", "cafe", "ef", "face"};
String rule ="< c, C < a, A < f, F < e, E";
RuleBasedCollator collator = new RuleBasedCollator(rule);
List list = Arrays.asList(words);
Collections.sort(list, collator);
System.out.println(list);
}
}
在對上述代碼編譯并運行之后,你將看到使用新規(guī)則排序后的單詞:import java.util.*;
public class Rule {
public static void main(String args[]) throws ParseException {
String words[] = {"ace", "cafe", "ef", "face"};
String rule ="< c, C < a, A < f, F < e, E";
RuleBasedCollator collator = new RuleBasedCollator(rule);
List list = Arrays.asList(words);
Collections.sort(list, collator);
System.out.println(list);
}
}
> javac Rule.java
> java Rule
[cafe, ace, face, ef]
請以后閱讀Javadoc中更多的關于
規(guī)則語法的信息,再嘗試擴展字母表并處理不同的變音符。> java Rule
[cafe, ace, face, ef]
現在,當你為全世界開發(fā) 程序時,你的程序就能做出更好的準備以去適應本地用戶了。也要確保字符串在資源包中,如之前的一個竅門所展示的那樣:Earlier tip。(譯注:原文并沒有提供這個Earlier tip的正確鏈接地址。)