如何在Java中以编程方式识别哪个Unicode版本支持?

时间:2011-08-04 12:15:15

标签: unicode jvm java java-7

由于Java代码可以在任何Java VM中运行,我想知道如何以编程方式识别支持哪种Unicode版本?

6 个答案:

答案 0 :(得分:7)

最简单的方法,但我能想到的最糟糕的方法是选择一个对每个Unicode版本都不熟悉的代码点,并检查它的Character属性。或者您可以使用正则表达式检查其常规类别。以下是一些选定的代码点:

  • Unicode 6.0.0:

    Ꞡ  U+A7A0 GC=Lu SC=Latin    LATIN CAPITAL LETTER G WITH OBLIQUE STROKE
    ₹  U+20B9 GC=Sc SC=Common   INDIAN RUPEE SIGN
    ₜ  U+209C GC=Lm SC=Latin    LATIN SUBSCRIPT SMALL LETTER T
    
  • Unicode 5.2:

    Ɒ  U+2C70 GC=Lu SC=Latin    LATIN CAPITAL LETTER TURNED ALPHA
    ‭⅐ U+2150 GC=No SC=Common   VULGAR FRACTION ONE SEVENTH
    ⸱  U+2E31 GC=Po SC=Common   WORD SEPARATOR MIDDLE DOT
    
  • Unicode 5.1:

    ‭ꝺ  U+A77A GC=Ll SC=Latin    LATIN SMALL LETTER INSULAR D
    Ᵹ  U+A77D GC=Lu SC=Latin    LATIN CAPITAL LETTER INSULAR 
    ⚼  U+26BC GC=So SC=Common    SESQUIQUADRATE
    
  • Unicode 5.0:

    Ⱶ  U+2C75 GC=Lu SC=Latin    LATIN CAPITAL LETTER HALF H
    ɂ  U+0242 GC=Ll SC=Latin    LATIN SMALL LETTER GLOTTAL STOP
    ⬔  U+2B14 GC=So SC=Common  SQUARE WITH UPPER RIGHT DIAGONAL HALF BLACK
    

我已经包含了常规类别和脚本属性,但您只能检查JDK7中的脚本,这是第一个支持该脚本的Java版本。

我通过命令行运行这样的命令来找到这些代码点:

% unichars -gs '\p{Age=5.1}'
% unichars -gs '\p{Lu}' '\p{Age=5.0}'

那是unichars计划。它只会在您运行的Perl版本支持的任何UCD版本中找到Unicode字符数据库中支持的属性。

我也喜欢我的输出排序,所以我倾向于运行

 % unichars -gs '\p{Alphabetic}' '\p{Age=6.0}' | ucsort | less -r

这是ucsort程序,它根据Unicode归类算法对文本进行排序。

然而,在Perl中,与Java不同,这很容易找到。例如,如果你 从命令行运行它(是的,也有程序员API),你会发现:

$ corelist -a Unicode
    v5.6.2     3.0.1     
    v5.8.0     3.2.0     
    v5.8.1     4.0.0 
    v5.8.8     4.1.0
    v5.10.0    5.0.0     
    v5.10.1    5.1.0 
    v5.12.0    5.2.0 
    v5.14.0    6.0.0

这表明Perl版本5.14.0是第一个支持Unicode 6.0.0的版本。对于Java,我相信没有直接为您提供此信息的API,因此您必须对映射Java版本和Unicode版本的表进行硬编码,或者使用测试代码点的经验方法来获取属性。根据经验,我的意思相当于这类事情:

% ruby -le 'print "\u2C75" =~ /\p{Lu}/ ? "pass 5.2" : "fail 5.2"'
pass 5.2
% ruby -le 'print "\uA7A0" =~ /\p{Lu}/ ? "pass 6.0" : "fail 6.0"'
fail 6.0
% ruby -v
ruby 1.9.2p0 (2010-08-18 revision 29036) [i386-darwin9.8.0]

% perl -le 'print "\x{2C75}" =~ /\p{Lu}/ ? "pass 5.2" : "fail 5.2"'
pass 5.2
% perl -le 'print "\x{A7A0}" =~ /\p{Lu}/ ? "pass 6.0" : "fail 6.0"'
pass 6.0
% perl -v
This is perl 5, version 14, subversion 0 (v5.14.0) built for darwin-2level

要找出特定代码点的年龄,请在其上运行uniprops -a

% uniprops -a 10424
U+10424 ‹› \N{DESERET CAPITAL LETTER EN}
 \w \pL \p{LC} \p{L_} \p{L&} \p{Lu}
 All Any Alnum Alpha Alphabetic Assigned InDeseret Cased Cased_Letter LC Changes_When_Casefolded CWCF Changes_When_Casemapped CWCM Changes_When_Lowercased CWL Changes_When_NFKC_Casefolded CWKCF Deseret Dsrt Lu L Gr_Base Grapheme_Base Graph GrBase ID_Continue IDC ID_Start IDS Letter L_ Uppercase_Letter Print Upper Uppercase Word XID_Continue XIDC XID_Start XIDS X_POSIX_Alnum X_POSIX_Alpha X_POSIX_Graph X_POSIX_Print X_POSIX_Upper X_POSIX_Word
 Age=3.1 Bidi_Class=L Bidi_Class=Left_To_Right BC=L Block=Deseret Canonical_Combining_Class=0 Canonical_Combining_Class=Not_Reordered CCC=NR Canonical_Combining_Class=NR Decomposition_Type=None DT=None Script=Deseret East_Asian_Width=Neutral Grapheme_Cluster_Break=Other GCB=XX Grapheme_Cluster_Break=XX Hangul_Syllable_Type=NA Hangul_Syllable_Type=Not_Applicable HST=NA Joining_Group=No_Joining_Group JG=NoJoiningGroup Joining_Type=Non_Joining JT=U Joining_Type=U Line_Break=AL Line_Break=Alphabetic LB=AL Numeric_Type=None NT=None Numeric_Value=NaN NV=NaN Present_In=3.1 IN=3.1 Present_In=3.2 IN=3.2 Present_In=4.0 IN=4.0 Present_In=4.1 IN=4.1 Present_In=5.0 IN=5.0 Present_In=5.1 IN=5.1 Present_In=5.2 IN=5.2 Present_In=6.0 IN=6.0 SC=Dsrt Script=Dsrt Sentence_Break=UP Sentence_Break=Upper SB=UP Word_Break=ALetter WB=LE Word_Break=LE _X_Begin

Unicode::Tussle捆绑包中提供了我的所有Unicode工具,包括unicharsuninamesuniquoteucsort等等。

Java 1.7改进

JDK7在使一些Unicode事物变得更容易方面走了很长的路。我在OSCON Unicode支持Shootout演讲结束时谈到了这一点。我曾想过将一个语言集合在一起,这些语言支持哪些版本的Unicode在哪些版本的语言版本中,但最终废弃它以告诉人们只获取每种语言的最新版本。例如,我知道Java 1.7,Perl 5.14和Python 2.7或3.2支持Unicode 6.0.0。

JDK7包含支持Unicode 6.0.0的类CharacterStringPattern的更新。这包括对Unicode脚本属性的支持,以及Pattern的一些增强功能,以使其满足Unicode UTS#18 Regular Expressions的1级​​支持要求。其中包括

  • isupperislower方法现在正确对应于Unicode大写和小写属性;以前他们只是误用了字母,这是不对的,因为它分别错过Other_UppercaseOther_Lowercase代码点。例如,这些是一些小写的代码点,它们不是 GC=Ll(小写字母),仅选择样本:

    % unichars -gs '\p{lowercase}' '\P{LL}'
    ◌ͅ  U+0345 GC=Mn SC=Inherited    COMBINING GREEK YPOGEGRAMMENI
    ͺ  U+037A GC=Lm SC=Greek        GREEK YPOGEGRAMMENI
    ˢ  U+02E2 GC=Lm SC=Latin        MODIFIER LETTER SMALL S
    ˣ  U+02E3 GC=Lm SC=Latin        MODIFIER LETTER SMALL X
    ᴬ  U+1D2C GC=Lm SC=Latin        MODIFIER LETTER CAPITAL A
    ᴮ  U+1D2E GC=Lm SC=Latin        MODIFIER LETTER CAPITAL B
    ᵂ  U+1D42 GC=Lm SC=Latin        MODIFIER LETTER CAPITAL W
    ᵃ  U+1D43 GC=Lm SC=Latin        MODIFIER LETTER SMALL A
    ᵇ  U+1D47 GC=Lm SC=Latin        MODIFIER LETTER SMALL B
    ₐ  U+2090 GC=Lm SC=Latin        LATIN SUBSCRIPT SMALL LETTER A
    ₑ  U+2091 GC=Lm SC=Latin        LATIN SUBSCRIPT SMALL LETTER E
    ⅰ  U+2170 GC=Nl SC=Latin        SMALL ROMAN NUMERAL ONE
    ⅱ  U+2171 GC=Nl SC=Latin        SMALL ROMAN NUMERAL TWO
    ⅲ  U+2172 GC=Nl SC=Latin        SMALL ROMAN NUMERAL THREE
    ⓐ  U+24D0 GC=So SC=Common       CIRCLED LATIN SMALL LETTER A
    ⓑ  U+24D1 GC=So SC=Common       CIRCLED LATIN SMALL LETTER B
    ⓒ  U+24D2 GC=So SC=Common       CIRCLED LATIN SMALL LETTER C
    
  • 字母测试现在正确,因为它们使用Other_Alphabetic。他们在1.7之前做错了,这是一个问题。

  • \x{HHHHH}模式转义,因此您可以满足RL1.1;这允许您将[-](由于UTF-16诅咒而失败)重写为[\x{1D49C}-\x{1D4B5}] JDK7是第一个完全/正确支持非BMP字符的Java版本。令人惊讶但真实。

  • RL1.2的更多属性,其中脚本属性是最重要的。这使您可以编写\p{script=Greek},例如缩写为\p{Greek}

  • 新的UNICODE_CHARACTER_CLASSES模式编译标志和相应的模式嵌入标志"(?U)",以满足RL1.2a的兼容性属性。

我当然可以确定您为什么要确保运行支持Unicode 6.0.0的Java,因为这也带来了所有其他好处。

答案 1 :(得分:6)

如果您正在寻找一个可以向您提供此信息的课程,这不是一件轻而易举的事。

通常,Java支持的Unicode版本会从一个主要规范更改为另一个主要规范,并且此信息记录在Java API文档的Character类中(源自Java语言规范)。但是,您不能像每个major version of Java need not have its own version of the Java Language Specification那样依赖Java语言规范。

因此,您应该在JVM支持的Java版本和支持的Unicode版本之间进行音译:

String specVersion = System.getProperty("java.specification.version");
if(specVersion.equals("1.7"))
    return "6.0";
else if(specVersion.equals("1.6"))
    return "4.0";
else if(specVersion.equals("1.5"))
    return "4.0";
else if(specVersion.equals("1.4"))
    return "3.0";
... and so on

支持的版本的详细信息可以从Java语言规范中获得。引自JSR 901这是Java 7的语言规范:

  

Java SE平台随着它的发展跟踪Unicode规范。   给定版本使用的Unicode的精确版本在中指定   类字符的文档。

     

Java的版本   1.1之前的编程语言使用Unicode版本1.1.5。升级   在JDK 1.1中发生了更新版本的Unicode标准   Unicode 2.0),JDK 1.1.7(到Unicode 2.1),Java SE 1.4(到Unicode   3.0)和Java SE 5.0(到Unicode 4.0)。

答案 2 :(得分:3)

Unicode版本在Java Language Specification §3.1中定义。由于支持J2SE 5.0 Unicode 4.0。

答案 3 :(得分:3)

我不认为它可以通过公共API获得。但这不会经常发生变化,因此您可以获得规范版本:

System.getProperties().getProperty("java.specification.version")

在此基础上,找出unicode版本。

java 1.0 -> Unicode 1.1
java 1.1 -> Unicode 2.0
java 1.2 -> Unicode 2.0
java 1.3 -> Unicode 2.0
java 1.4 -> Unicode 3.0
java 1.5 -> Unicode 4.0
java 1.6 -> Unicode 4.0
java 1.7 -> Unicode 6.0

要验证它,您可以看到Character类的JavaDoc。

答案 4 :(得分:2)

这是我使用的方法,它应与所有版本的Java> = 1.1兼容。它的未来版本仅限于Unicode 11.0,但可以通过引用Unicode“DerivedAge.txt”文件轻松扩展(请参阅代码注释中的URL)。

早在我可以测试的时候,它同意MichałŠrajer编译的表,并且它发现Java 8支持Unicode 6.2,而Java 9支持Unicode 8.0(这两个结果都与它们各自的文档一致{ {1}}类)。

Character

永远不会达到检测2.0之前的Unicode版本的代码(考虑到Java 1.1或更高版本的要求),并且仅为了完整性而存在。

答案 5 :(得分:1)

由于支持的unicode版本是由Java版本定义的,因此您可以使用该信息并根据System.getProperty("java.version")返回的内容推断unicode版本。

我假设您只想支持特定的unicode版本或至少支持一些最小版本。我不是unicode专家,但由于版本似乎是向后兼容的,你可能会将unicode版本定义为至少4.0,这意味着支持的Java版本将至少为5.0