2008/12/02

多语言 字符串排序 JAVA
最近做项目的国际化,碰到非asc字符的排序,比如西班牙语,中文,这些排序需要特殊的规则,我在网上找到一篇文章使用Collator(引用) 字符串排序 本文是Sun官方以Blog形式发布的Java核心技术窍门(JavaCoreTechTip)中的一个。我之前尚未关注过java.text.Collator类,看过Sorting Strings这个tip之后觉得有些意义,故翻译在了此处,也希望对其它朋友有所助益。(2008.04.07最后更新) 使用Java平台进行字符串排序被认为是一件简单的工作,但为国际市场开发程序时,则需要有更多的考虑。如果你陷入只关注英语的心态中,并认为你的程序会工作的很好,因为它所显示的字符串从今往后都是一样的,你可能认为一切都很正常。但一旦你有一位西班牙用户,他希望能够正常地对mañana进行排序,但如果你都是使用String类中缺省的compare方法去做排序,字符ñ将会跟在字符z之后,而在正常的西班牙语排序中,ñ应该在字符n和o之间。这就是java.text包的类Collator发挥作用的地方了。 想像这样的一组词 * first * mañana * man * many * maxi * next 使用String类的默认排序机制,即它的compare()方法,排序的结果将会是: * first * man * many * maxi * mañana * next 此处,mañana出现在maxi与next之间。而在西班牙语世界中,mañana应该出现在many和maxi之间,因为在字母表中,字符ñ(读作eñe)跟在n之后。当来了一个德语用户,想用他们自己的变音符时,你就可以写一个自己的定制排序规则来处理ñ,否则一组使用façade的设计模式将会怎样呢?你是否想让façade出现在factory之前或之后呢?(关键是如同对c或其它字符那样去处理ç的小写变音符。) 这就是类Collator能派上用场的地方了。类Collator用于对语言敏感的排序问题,并不会只基于它们的ASCII/Unicode字符去尝试排序。使用Collator要求你在完全应用它的特性之前要理解一个额外的属性,即称之为强度(Strength)的属性。Collator的强度设置决定了在排序时如何使用强(或弱)匹配。该属性有4个可能的值:PRIMARY,SECONDARY,TERTIARY和IDENTICAL。具体是哪个强度在产生作用取决于语言环境。典型地,会有如下的情况。按从后往前的顺序,IDENTICAL强度表示能够被进行相同的处理的字符必须是一致的。TERTIARY通常用于忽略大小写差异。SECONDARY用于忽略变音符,如n和ñ。 PRIMARY与IDENTICAL相似也是基于字母之间差异,但是当处理控制字符和发音时还是有所不同。查看Collator的javadoc,以获取更多关于这些强度之间的差异及分解(Decomposition)模式规则的信息。 为了使用Collator,你需要先得到它的一个实例。你既可以调用getInstance方法以得到一个针对默认语言环境的Collator对象,也可以传递一个指定的Locale对象给getInstance方法以得到一个针对特定语言环境的Collator对象。例如,为了获得针对一个西班牙语的 Collator对象,你应使用new Locale("es")去创建一个西班牙语的Locale对象,然后将它传入getInstance方法中: Collator esCollator = Collator.getInstance(new Locale("es")); 假设针对该语言环境的默认Collator强度,针对西班牙语的默认强度是SECONDARY已经足够了。然后你将这个Collator对象如任一Comparator对象那样传入Collections类的sort方法的比较规则参数中,以得到排序后的List对象。 Collections.sort(list, esCollator); 操作之前的单词列表,你现在就会得到一个基于西班牙语字母表的恰当排序结果: * first * man * many * mañana * maxi * next 如果你在上述Collator中换用US的Locale对象,由于ñ并不是US中本有的字母,所以mañana将会出现在man和many之间。 这儿有一个简洁的例子以显示这些差异。 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); } } 最后还有一点儿关于语言排序规则的信息。通过调用getInstance方法而得到的Collator对象通常是支持特定语言的RuleBasedCollator实例。你可使用RuleBasedCollator去定义你自己的排序顺序。该类的Javadoc更完整地描述了这种规则的语法,但还是让我们先假设你有一个4字符字母表,并希望字母的顺序是CAFE,而不是ACEF,你的规则看起来就像这样: String rule = "< collator =" new" rule ="< c, C < a, A < f, F < e, E" collator =" new" list =" Arrays.asList(words);"> javac Rule.java > java Rule [cafe, ace, face, ef] 请以后阅读Javadoc中更多的关于规则语法的信息,再尝试扩展字母表并处理不同的变音符。 现在,当你为全世界开发程序时,你的程序就能做出更好的准备以去适应本地用户了。也要确保字符串在资源包中,如之前的一个窍门所展示的那样:Earlier tip。(译注:原文并没有提供这个Earlier tip的正确链接地址。) 原文地址:http://www.blogjava.net/jiangshachina/archive/2008/04/07/190912.html

0 评论 :