Path: blob/master/test/jdk/java/lang/Character/UnicodeSpec.java
41149 views
/*1* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/242526import java.io.BufferedReader;27import java.io.FileReader;28import java.io.FileNotFoundException;29import java.io.IOException;30import java.io.File;31import java.util.regex.Pattern;32import java.util.ArrayList;3334/**35* The UnicodeSpec class provides a way to read in Unicode character36* properties from a Unicode data file. One instance of class UnicodeSpec37* holds a decoded version of one line of the data file. The file may38* be obtained from www.unicode.org. The method readSpecFile returns an array39* of UnicodeSpec objects.40*41* @author Guy Steele42* @author John O'Conner43*/4445public class UnicodeSpec {4647public UnicodeSpec() {48this(0xffff);49}5051public UnicodeSpec(int codePoint) {52this.codePoint = codePoint;53generalCategory = UNASSIGNED;54bidiCategory = DIRECTIONALITY_UNDEFINED;55mirrored = false;56titleMap = 0xFFFF;57upperMap = 0xFFFF;58lowerMap = 0xFFFF;59decimalValue = -1;60digitValue = -1;61numericValue = "";62oldName = null;63comment = null;64name = null;65}6667public String toString() {68StringBuffer result = new StringBuffer(hex6(codePoint));69if (getUpperMap() != 0xffff) {70result.append(", upper=").append(hex6(upperMap));71}72if (getLowerMap() != 0xffff) {73result.append(", lower=").append(hex6(lowerMap));74}75if (getTitleMap() != 0xffff) {76result.append(", title=").append(hex6(titleMap));77}78return result.toString();79}8081static String hex4(int n) {82String q = Long.toHexString(n & 0xFFFF).toUpperCase();83return "0000".substring(Math.min(4, q.length())) + q;84}8586static String hex6(int n) {87String str = Integer.toHexString(n & 0xFFFFFF).toUpperCase();88return "000000".substring(Math.min(6, str.length())) + str;8990}919293/**94* Given one line of a Unicode data file as a String, parse the line95* and return a UnicodeSpec object that contains the same character information.96*97* @param s a line of the Unicode data file to be parsed98* @return a UnicodeSpec object, or null if the parsing process failed for some reason99*/100public static UnicodeSpec parse(String s) {101UnicodeSpec spec = null;102String[] tokens = null;103104try {105tokens = tokenSeparator.split(s, REQUIRED_FIELDS);106spec = new UnicodeSpec();107spec.setCodePoint(parseCodePoint(tokens[FIELD_VALUE]));108spec.setName(parseName(tokens[FIELD_NAME]));109spec.setGeneralCategory(parseGeneralCategory(tokens[FIELD_CATEGORY]));110spec.setBidiCategory(parseBidiCategory(tokens[FIELD_BIDI]));111spec.setCombiningClass(parseCombiningClass(tokens[FIELD_CLASS]));112spec.setDecomposition(parseDecomposition(tokens[FIELD_DECOMPOSITION]));113spec.setDecimalValue(parseDecimalValue(tokens[FIELD_DECIMAL]));114spec.setDigitValue(parseDigitValue(tokens[FIELD_DIGIT]));115spec.setNumericValue(parseNumericValue(tokens[FIELD_NUMERIC]));116spec.setMirrored(parseMirrored(tokens[FIELD_MIRRORED]));117spec.setOldName(parseOldName(tokens[FIELD_OLDNAME]));118spec.setComment(parseComment(tokens[FIELD_COMMENT]));119spec.setUpperMap(parseUpperMap(tokens[FIELD_UPPERCASE]));120spec.setLowerMap(parseLowerMap(tokens[FIELD_LOWERCASE]));121spec.setTitleMap(parseTitleMap(tokens[FIELD_TITLECASE]));122}123catch(Exception e) {124spec = null;125System.out.println("Error parsing spec line.");126}127return spec;128}129130/**131* Parse the codePoint attribute for a Unicode character. If the parse succeeds,132* the codePoint field of this UnicodeSpec object is updated and false is returned.133*134* The codePoint attribute should be a four-digit hexadecimal integer.135*136* @param s the codePoint attribute extracted from a line of the Unicode data file137* @return code point if successful138* @exception NumberFormatException if unable to parse argument139*/140public static int parseCodePoint(String s) throws NumberFormatException {141return Integer.parseInt(s, 16);142}143144public static String parseName(String s) throws Exception {145if (s==null) throw new Exception("Cannot parse name.");146return s;147}148149public static byte parseGeneralCategory(String s) throws Exception {150byte category = GENERAL_CATEGORY_COUNT;151152for (byte x=0; x<generalCategoryList.length; x++) {153if (s.equals(generalCategoryList[x][SHORT])) {154category = x;155break;156}157}158if (category >= GENERAL_CATEGORY_COUNT) {159throw new Exception("Could not parse general category.");160}161return category;162}163164public static byte parseBidiCategory(String s) throws Exception {165byte category = DIRECTIONALITY_CATEGORY_COUNT;166167for (byte x=0; x<bidiCategoryList.length; x++) {168if (s.equals(bidiCategoryList[x][SHORT])) {169category = x;170break;171}172}173if (category >= DIRECTIONALITY_CATEGORY_COUNT) {174throw new Exception("Could not parse bidi category.");175}176return category;177}178179180/**181* Parse the combining attribute for a Unicode character. If there is a combining182* attribute and the parse succeeds, then the hasCombining field is set to true,183* the combining field of this UnicodeSpec object is updated, and false is returned.184* If the combining attribute is an empty string, the parse succeeds but the185* hasCombining field is set to false. (and false is returned).186*187* The combining attribute, if any, should be a nonnegative decimal integer.188*189* @param s the combining attribute extracted from a line of the Unicode data file190* @return the combining class value if any, -1 if property not defined191* @exception Exception if can't parse the combining class192*/193194public static int parseCombiningClass(String s) throws Exception {195int combining = -1;196if (s.length()>0) {197combining = Integer.parseInt(s, 10);198}199return combining;200}201202/**203* Parse the decomposition attribute for a Unicode character. If the parse succeeds,204* the decomposition field of this UnicodeSpec object is updated and false is returned.205*206* The decomposition attribute is complicated; for now, it is treated as a string.207*208* @param s the decomposition attribute extracted from a line of the Unicode data file209* @return true if the parse failed; otherwise false210*/211212public static String parseDecomposition(String s) throws Exception {213if (s==null) throw new Exception("Cannot parse decomposition.");214return s;215}216217218/**219* Parse the decimal value attribute for a Unicode character. If there is a decimal value220* attribute and the parse succeeds, then the hasDecimalValue field is set to true,221* the decimalValue field of this UnicodeSpec object is updated, and false is returned.222* If the decimal value attribute is an empty string, the parse succeeds but the223* hasDecimalValue field is set to false. (and false is returned).224*225* The decimal value attribute, if any, should be a nonnegative decimal integer.226*227* @param s the decimal value attribute extracted from a line of the Unicode data file228* @return the decimal value as an int, -1 if no decimal value defined229* @exception NumberFormatException if the parse fails230*/231public static int parseDecimalValue(String s) throws NumberFormatException {232int value = -1;233234if (s.length() > 0) {235value = Integer.parseInt(s, 10);236}237return value;238}239240/**241* Parse the digit value attribute for a Unicode character. If there is a digit value242* attribute and the parse succeeds, then the hasDigitValue field is set to true,243* the digitValue field of this UnicodeSpec object is updated, and false is returned.244* If the digit value attribute is an empty string, the parse succeeds but the245* hasDigitValue field is set to false. (and false is returned).246*247* The digit value attribute, if any, should be a nonnegative decimal integer.248*249* @param s the digit value attribute extracted from a line of the Unicode data file250* @return the digit value as an non-negative int, or -1 if no digit property defined251* @exception NumberFormatException if the parse fails252*/253public static int parseDigitValue(String s) throws NumberFormatException {254int value = -1;255256if (s.length() > 0) {257value = Integer.parseInt(s, 10);258}259return value;260}261262public static String parseNumericValue(String s) throws Exception {263if (s == null) throw new Exception("Cannot parse numeric value.");264return s;265}266267public static String parseComment(String s) throws Exception {268if (s == null) throw new Exception("Cannot parse comment.");269return s;270}271272public static boolean parseMirrored(String s) throws Exception {273boolean mirrored;274if (s.length() == 1) {275if (s.charAt(0) == 'Y') {mirrored = true;}276else if (s.charAt(0) == 'N') {mirrored = false;}277else {throw new Exception("Cannot parse mirrored property.");}278}279else { throw new Exception("Cannot parse mirrored property.");}280return mirrored;281}282283public static String parseOldName(String s) throws Exception {284if (s == null) throw new Exception("Cannot parse old name");285return s;286}287288/**289* Parse the uppercase mapping attribute for a Unicode character. If there is a uppercase290* mapping attribute and the parse succeeds, then the hasUpperMap field is set to true,291* the upperMap field of this UnicodeSpec object is updated, and false is returned.292* If the uppercase mapping attribute is an empty string, the parse succeeds but the293* hasUpperMap field is set to false. (and false is returned).294*295* The uppercase mapping attribute should be a four-digit hexadecimal integer.296*297* @param s the uppercase mapping attribute extracted from a line of the Unicode data file298* @return uppercase char if defined, \uffff otherwise299* @exception NumberFormatException if parse fails300*/301public static int parseUpperMap(String s) throws NumberFormatException {302int upperCase = 0xFFFF;303304if (s.length() >= 4) {305upperCase = Integer.parseInt(s, 16);306}307else if (s.length() != 0) {308throw new NumberFormatException();309}310return upperCase;311}312313/**314* Parse the lowercase mapping attribute for a Unicode character. If there is a lowercase315* mapping attribute and the parse succeeds, then the hasLowerMap field is set to true,316* the lowerMap field of this UnicodeSpec object is updated, and false is returned.317* If the lowercase mapping attribute is an empty string, the parse succeeds but the318* hasLowerMap field is set to false. (and false is returned).319*320* The lowercase mapping attribute should be a four-digit hexadecimal integer.321*322* @param s the lowercase mapping attribute extracted from a line of the Unicode data file323* @return lowercase char mapping if defined, \uFFFF otherwise324* @exception NumberFormatException if parse fails325*/326public static int parseLowerMap(String s) throws NumberFormatException {327int lowerCase = 0xFFFF;328329if (s.length() >= 4) {330lowerCase = Integer.parseInt(s, 16);331}332else if (s.length() != 0) {333throw new NumberFormatException();334}335return lowerCase;336}337338/**339* Parse the titlecase mapping attribute for a Unicode character. If there is a titlecase340* mapping attribute and the parse succeeds, then the hasTitleMap field is set to true,341* the titleMap field of this UnicodeSpec object is updated, and false is returned.342* If the titlecase mapping attribute is an empty string, the parse succeeds but the343* hasTitleMap field is set to false. (and false is returned).344*345* The titlecase mapping attribute should be a four-digit hexadecimal integer.346*347* @param s the titlecase mapping attribute extracted from a line of the Unicode data file348* @return title case char mapping if defined, \uFFFF otherwise349* @exception NumberFormatException if parse fails350*/351public static int parseTitleMap(String s) throws NumberFormatException {352int titleCase = 0xFFFF;353354if (s.length() >= 4) {355titleCase = Integer.parseInt(s, 16);356}357else if (s.length() != 0) {358throw new NumberFormatException();359}360return titleCase;361}362363/**364* Read and parse a Unicode data file.365*366* @param file a file specifying the Unicode data file to be read367* @return an array of UnicodeSpec objects, one for each line of the368* Unicode data file that could be successfully parsed as369* specifying Unicode character attributes370*/371372public static UnicodeSpec[] readSpecFile(File file, int plane) throws FileNotFoundException {373ArrayList<UnicodeSpec> list = new ArrayList<>(3000);374UnicodeSpec[] result = null;375int count = 0;376BufferedReader f = new BufferedReader(new FileReader(file));377String line = null;378loop:379while(true) {380try {381line = f.readLine();382}383catch (IOException e) {384break loop;385}386if (line == null) break loop;387UnicodeSpec item = parse(line.trim());388int specPlane = item.getCodePoint() >>> 16;389if (specPlane < plane) continue;390if (specPlane > plane) break;391392if (item != null) {393list.add(item);394}395}396result = new UnicodeSpec[list.size()];397list.toArray(result);398return result;399}400401void setCodePoint(int value) {402codePoint = value;403}404405/**406* Return the code point in this Unicode specification407* @return the char code point representing by the specification408*/409public int getCodePoint() {410return codePoint;411}412413void setName(String name) {414this.name = name;415}416417public String getName() {418return name;419}420421void setGeneralCategory(byte category) {422generalCategory = category;423}424425public byte getGeneralCategory() {426return generalCategory;427}428429void setBidiCategory(byte category) {430bidiCategory = category;431}432433public byte getBidiCategory() {434return bidiCategory;435}436437void setCombiningClass(int combiningClass) {438this.combiningClass = combiningClass;439}440441public int getCombiningClass() {442return combiningClass;443}444445void setDecomposition(String decomposition) {446this.decomposition = decomposition;447}448449public String getDecomposition() {450return decomposition;451}452453void setDecimalValue(int value) {454decimalValue = value;455}456457public int getDecimalValue() {458return decimalValue;459}460461public boolean isDecimalValue() {462return decimalValue != -1;463}464465void setDigitValue(int value) {466digitValue = value;467}468469public int getDigitValue() {470return digitValue;471}472473public boolean isDigitValue() {474return digitValue != -1;475}476477void setNumericValue(String value) {478numericValue = value;479}480481public String getNumericValue() {482return numericValue;483}484485public boolean isNumericValue() {486return numericValue.length() > 0;487}488489void setMirrored(boolean value) {490mirrored = value;491}492493public boolean isMirrored() {494return mirrored;495}496497void setOldName(String name) {498oldName = name;499}500501public String getOldName() {502return oldName;503}504505void setComment(String comment) {506this.comment = comment;507}508509public String getComment() {510return comment;511}512513void setUpperMap(int ch) {514upperMap = ch;515};516517public int getUpperMap() {518return upperMap;519}520521public boolean hasUpperMap() {522return upperMap != 0xffff;523}524525void setLowerMap(int ch) {526lowerMap = ch;527}528529public int getLowerMap() {530return lowerMap;531}532533public boolean hasLowerMap() {534return lowerMap != 0xffff;535}536537void setTitleMap(int ch) {538titleMap = ch;539}540541public int getTitleMap() {542return titleMap;543}544545public boolean hasTitleMap() {546return titleMap != 0xffff;547}548549int codePoint; // the characters UTF-32 code value550String name; // the ASCII name551byte generalCategory; // general category, available via Characte.getType()552byte bidiCategory; // available via Character.getBidiType()553int combiningClass; // not used in Character554String decomposition; // not used in Character555int decimalValue; // decimal digit value556int digitValue; // not all digits are decimal557String numericValue; // numeric value if digit or non-digit558boolean mirrored; //559String oldName;560String comment;561int upperMap;562int lowerMap;563int titleMap;564565// this is the number of fields in one line of the UnicodeData.txt file566// each field is separated by a semicolon (a token)567static final int REQUIRED_FIELDS = 15;568569/**570* General category types571* To preserve compatibility, these values cannot be changed572*/573public static final byte574UNASSIGNED = 0, // Cn normative575UPPERCASE_LETTER = 1, // Lu normative576LOWERCASE_LETTER = 2, // Ll normative577TITLECASE_LETTER = 3, // Lt normative578MODIFIER_LETTER = 4, // Lm normative579OTHER_LETTER = 5, // Lo normative580NON_SPACING_MARK = 6, // Mn informative581ENCLOSING_MARK = 7, // Me informative582COMBINING_SPACING_MARK = 8, // Mc normative583DECIMAL_DIGIT_NUMBER = 9, // Nd normative584LETTER_NUMBER = 10, // Nl normative585OTHER_NUMBER = 11, // No normative586SPACE_SEPARATOR = 12, // Zs normative587LINE_SEPARATOR = 13, // Zl normative588PARAGRAPH_SEPARATOR = 14, // Zp normative589CONTROL = 15, // Cc normative590FORMAT = 16, // Cf normative591// 17 is unused for no apparent reason,592// but must preserve forward compatibility593PRIVATE_USE = 18, // Co normative594SURROGATE = 19, // Cs normative595DASH_PUNCTUATION = 20, // Pd informative596START_PUNCTUATION = 21, // Ps informative597END_PUNCTUATION = 22, // Pe informative598CONNECTOR_PUNCTUATION = 23, // Pc informative599OTHER_PUNCTUATION = 24, // Po informative600MATH_SYMBOL = 25, // Sm informative601CURRENCY_SYMBOL = 26, // Sc informative602MODIFIER_SYMBOL = 27, // Sk informative603OTHER_SYMBOL = 28, // So informative604INITIAL_QUOTE_PUNCTUATION = 29, // Pi informative605FINAL_QUOTE_PUNCTUATION = 30, // Pf informative606607// this value is only used in the character generation tool608// it can change to accommodate the addition of new categories.609GENERAL_CATEGORY_COUNT = 31; // sentinel value610611static final byte SHORT = 0, LONG = 1;612// general category type strings613// NOTE: The order of this category array is dependent on the assignment of614// category constants above. We want to access this array using constants above.615// [][SHORT] is the SHORT name, [][LONG] is the LONG name616static final String[][] generalCategoryList = {617{"Cn", "UNASSIGNED"},618{"Lu", "UPPERCASE_LETTER"},619{"Ll", "LOWERCASE_LETTER"},620{"Lt", "TITLECASE_LETTER"},621{"Lm", "MODIFIER_LETTER"},622{"Lo", "OTHER_LETTER"},623{"Mn", "NON_SPACING_MARK"},624{"Me", "ENCLOSING_MARK"},625{"Mc", "COMBINING_SPACING_MARK"},626{"Nd", "DECIMAL_DIGIT_NUMBER"},627{"Nl", "LETTER_NUMBER"},628{"No", "OTHER_NUMBER"},629{"Zs", "SPACE_SEPARATOR"},630{"Zl", "LINE_SEPARATOR"},631{"Zp", "PARAGRAPH_SEPARATOR"},632{"Cc", "CONTROL"},633{"Cf", "FORMAT"},634{"xx", "unused"},635{"Co", "PRIVATE_USE"},636{"Cs", "SURROGATE"},637{"Pd", "DASH_PUNCTUATION"},638{"Ps", "START_PUNCTUATION"},639{"Pe", "END_PUNCTUATION"},640{"Pc", "CONNECTOR_PUNCTUATION"},641{"Po", "OTHER_PUNCTUATION"},642{"Sm", "MATH_SYMBOL"},643{"Sc", "CURRENCY_SYMBOL"},644{"Sk", "MODIFIER_SYMBOL"},645{"So", "OTHER_SYMBOL"},646{"Pi", "INITIAL_QUOTE_PUNCTUATION"},647{"Pf", "FINAL_QUOTE_PUNCTUATION"}648};649650/**651* Bidirectional categories652*/653public static final byte654DIRECTIONALITY_UNDEFINED = -1,655// Strong category656DIRECTIONALITY_LEFT_TO_RIGHT = 0, // L657DIRECTIONALITY_RIGHT_TO_LEFT = 1, // R658DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC = 2, // AL659// Weak category660DIRECTIONALITY_EUROPEAN_NUMBER = 3, // EN661DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR = 4, // ES662DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR = 5, // ET663DIRECTIONALITY_ARABIC_NUMBER = 6, // AN664DIRECTIONALITY_COMMON_NUMBER_SEPARATOR = 7, // CS665DIRECTIONALITY_NONSPACING_MARK = 8, // NSM666DIRECTIONALITY_BOUNDARY_NEUTRAL = 9, // BN667// Neutral category668DIRECTIONALITY_PARAGRAPH_SEPARATOR = 10, // B669DIRECTIONALITY_SEGMENT_SEPARATOR = 11, // S670DIRECTIONALITY_WHITESPACE = 12, // WS671DIRECTIONALITY_OTHER_NEUTRALS = 13, // ON672673DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING = 14, // LRE674DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE = 15, // LRO675DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING = 16, // RLE676DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE = 17, // RLO677DIRECTIONALITY_POP_DIRECTIONAL_FORMAT = 18, // PDF678679DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE = 19, // LRI680DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE = 20, // RLI681DIRECTIONALITY_FIRST_STRONG_ISOLATE = 21, // FSI682DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE = 22, // PDI683684DIRECTIONALITY_CATEGORY_COUNT = 23; // sentinel value685686// If changes are made to the above bidi category assignments, this687// list of bidi category names must be changed to keep their order in synch.688// Access this list using the bidi category constants above.689static final String[][] bidiCategoryList = {690{"L", "DIRECTIONALITY_LEFT_TO_RIGHT"},691{"R", "DIRECTIONALITY_RIGHT_TO_LEFT"},692{"AL", "DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC"},693{"EN", "DIRECTIONALITY_EUROPEAN_NUMBER"},694{"ES", "DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR"},695{"ET", "DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR"},696{"AN", "DIRECTIONALITY_ARABIC_NUMBER"},697{"CS", "DIRECTIONALITY_COMMON_NUMBER_SEPARATOR"},698{"NSM", "DIRECTIONALITY_NONSPACING_MARK"},699{"BN", "DIRECTIONALITY_BOUNDARY_NEUTRAL"},700{"B", "DIRECTIONALITY_PARAGRAPH_SEPARATOR"},701{"S", "DIRECTIONALITY_SEGMENT_SEPARATOR"},702{"WS", "DIRECTIONALITY_WHITESPACE"},703{"ON", "DIRECTIONALITY_OTHER_NEUTRALS"},704{"LRE", "DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING"},705{"LRO", "DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE"},706{"RLE", "DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING"},707{"RLO", "DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE"},708{"PDF", "DIRECTIONALITY_POP_DIRECTIONAL_FORMAT"},709{"LRI", "DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE"},710{"RLI", "DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE"},711{"FSI", "DIRECTIONALITY_FIRST_STRONG_ISOLATE"},712{"PDI", "DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE"},713714};715716// Unicode specification lines have fields in this order.717static final byte718FIELD_VALUE = 0,719FIELD_NAME = 1,720FIELD_CATEGORY = 2,721FIELD_CLASS = 3,722FIELD_BIDI = 4,723FIELD_DECOMPOSITION = 5,724FIELD_DECIMAL = 6,725FIELD_DIGIT = 7,726FIELD_NUMERIC = 8,727FIELD_MIRRORED = 9,728FIELD_OLDNAME = 10,729FIELD_COMMENT = 11,730FIELD_UPPERCASE = 12,731FIELD_LOWERCASE = 13,732FIELD_TITLECASE = 14;733734static final Pattern tokenSeparator = Pattern.compile(";");735736public static void main(String[] args) {737UnicodeSpec[] spec = null;738if (args.length == 2 ) {739try {740File file = new File(args[0]);741int plane = Integer.parseInt(args[1]);742spec = UnicodeSpec.readSpecFile(file, plane);743System.out.println("UnicodeSpec[" + spec.length + "]:");744for (int x=0; x<spec.length; x++) {745System.out.println(spec[x].toString());746}747}748catch(Exception e) {749e.printStackTrace();750}751}752753}754755}756757758