numericshaper.java

来自「JAVA基本类源代码,大家可以学习学习!」· Java 代码 · 共 925 行 · 第 1/2 页

JAVA
925
字号
	'\u115a', '\u115f',	'\u11a3', '\u11a8',	'\u11fa', '\u1200',	'\u1207', '\u1208',	'\u1247', '\u1248',	'\u1249', '\u124a',	'\u124e', '\u1250',	'\u1257', '\u1258',	'\u1259', '\u125a',	'\u125e', '\u1260',	'\u1287', '\u1288',	'\u1289', '\u128a',	'\u128e', '\u1290',	'\u12af', '\u12b0',	'\u12b1', '\u12b2',	'\u12b6', '\u12b8',	'\u12bf', '\u12c0',	'\u12c1', '\u12c2',	'\u12c6', '\u12c8',	'\u12cf', '\u12d0',	'\u12d7', '\u12d8',	'\u12ef', '\u12f0',	'\u130f', '\u1310',	'\u1311', '\u1312',	'\u1316', '\u1318',	'\u131f', '\u1320',	'\u1347', '\u1348',	'\u135b', '\u1361',	'\u137d', '\u13a0',	'\u13f5', '\u1401',	'\u1677', '\u1681',	'\u169b', '\u16a0',	'\u16f1', '\u1780',	'\u17b7', '\u17be',	'\u17c6', '\u17c7',	'\u17c9', '\u17d4',	'\u17db', '\u17dc',	'\u17dd', '\u17e0',	'\u17ea', '\u1810',	'\u181a', '\u1820',	'\u1878', '\u1880',	'\u18a9', '\u1e00',	'\u1e9c', '\u1ea0',	'\u1efa', '\u1f00',	'\u1f16', '\u1f18',	'\u1f1e', '\u1f20',	'\u1f46', '\u1f48',	'\u1f4e', '\u1f50',	'\u1f58', '\u1f59',	'\u1f5a', '\u1f5b',	'\u1f5c', '\u1f5d',	'\u1f5e', '\u1f5f',	'\u1f7e', '\u1f80',	'\u1fb5', '\u1fb6',	'\u1fbd', '\u1fbe',	'\u1fbf', '\u1fc2',	'\u1fc5', '\u1fc6',	'\u1fcd', '\u1fd0',	'\u1fd4', '\u1fd6',	'\u1fdc', '\u1fe0',	'\u1fed', '\u1ff2',	'\u1ff5', '\u1ff6',	'\u1ffd', '\u200e',	'\u2010', '\u207f',	'\u2080', '\u2102',	'\u2103', '\u2107',	'\u2108', '\u210a',	'\u2114', '\u2115',	'\u2116', '\u2119',	'\u211e', '\u2124',	'\u2125', '\u2126',	'\u2127', '\u2128',	'\u2129', '\u212a',	'\u212e', '\u212f',	'\u2132', '\u2133',	'\u213a', '\u2160',	'\u2184', '\u2336',	'\u237b', '\u2395',	'\u2396', '\u249c',	'\u24ea', '\u3005',	'\u3008', '\u3021',	'\u302a', '\u3031',	'\u3036', '\u3038',	'\u303b', '\u3041',	'\u3095', '\u309d',	'\u309f', '\u30a1',	'\u30fb', '\u30fc',	'\u30ff', '\u3105',	'\u312d', '\u3131',	'\u318f', '\u3190',	'\u31b8', '\u3200',	'\u321d', '\u3220',	'\u3244', '\u3260',	'\u327c', '\u327f',	'\u32b1', '\u32c0',	'\u32cc', '\u32d0',	'\u32ff', '\u3300',	'\u3377', '\u337b',	'\u33de', '\u33e0',	'\u33ff', '\u3400',	'\u4db6', '\u4e00',	'\u9fa6', '\ua000',	'\ua48d', '\uac00',	'\ud7a4', '\uf900',	'\ufa2e', '\ufb00',	'\ufb07', '\ufb13',	'\ufb18', '\ufb1d',	'\ufb1e', '\ufb1f',	'\ufb29', '\ufb2a',	'\ufb37', '\ufb38',	'\ufb3d', '\ufb3e',	'\ufb3f', '\ufb40',	'\ufb42', '\ufb43',	'\ufb45', '\ufb46',	'\ufbb2', '\ufbd3',	'\ufd3e', '\ufd50',	'\ufd90', '\ufd92',	'\ufdc8', '\ufdf0',	'\ufdfc', '\ufe70',	'\ufe73', '\ufe74',	'\ufe75', '\ufe76',	'\ufefd', '\uff21',	'\uff3b', '\uff41',	'\uff5b', '\uff66',	'\uffbf', '\uffc2',	'\uffc8', '\uffca',	'\uffd0', '\uffd2',	'\uffd8', '\uffda',	'\uffdd', '\uffff' // last entry is sentinel, actually never checked    };    // use a binary search with a cache    private static int stCache = 0;    // warning, synchronize access to this as it modifies state    private static boolean isStrongDirectional(char c) {	if (c < strongTable[stCache]) {	    stCache = search(c, strongTable, 0, stCache);	} else if (c >= strongTable[stCache + 1]) {	    stCache = search(c, strongTable, stCache + 1, strongTable.length - stCache - 1);	}	return (stCache & 0x1) == 1;    }    static private int getKeyFromMask(int mask) {	int key = 0;	while (key < NUM_KEYS && ((mask & (1<<key)) == 0)) {	    ++key;	}	if (key == NUM_KEYS || ((mask & ~(1<<key)) != 0)) {	    throw new IllegalArgumentException("invalid shaper: " + Integer.toHexString(mask));	}	return key;    }    /**     * Returns a shaper for the provided unicode range.  All      * Latin-1 (EUROPEAN) digits are converted      * to the corresponding decimal unicode digits.     * @param singleRange the specified Unicode range     * @return a non-contextual numeric shaper      * @throws IllegalArgumentException if the range is not a single range     */    static public NumericShaper getShaper(int singleRange) {	int key = getKeyFromMask(singleRange);	return new NumericShaper(key, singleRange);    }        /**     * Returns a contextual shaper for the provided unicode range(s).       * Latin-1 (EUROPEAN) digits are converted to the decimal digits      * corresponding to the range of the preceeding text, if the     * range is one of the provided ranges.  Multiple ranges are      * represented by or-ing the values together, such as,      * <code>NumericShaper.ARABIC | NumericShaper.THAI</code>.  The     * shaper assumes EUROPEAN as the starting context, that is, if      * EUROPEAN digits are encountered before any strong directional      * text in the string, the context is presumed to be EUROPEAN, and      * so the digits will not shape.     * @param ranges the specified Unicode ranges     * @return a shaper for the specified ranges     */    static public NumericShaper getContextualShaper(int ranges) {	ranges |= CONTEXTUAL_MASK;	return new NumericShaper(EUROPEAN_KEY, ranges);    }    /**     * Returns a contextual shaper for the provided unicode range(s).       * Latin-1 (EUROPEAN) digits will be converted to the decimal digits      * corresponding to the range of the preceeding text, if the     * range is one of the provided ranges.  Multiple ranges are      * represented by or-ing the values together, for example,      * <code>NumericShaper.ARABIC | NumericShaper.THAI</code>.  The     * shaper uses defaultContext as the starting context.     * @param ranges the specified Unicode ranges     * @param defaultContext the starting context, such as      * <code>NumericShaper.EUROPEAN</code>     * @return a shaper for the specified Unicode ranges.     */    static public NumericShaper getContextualShaper(int ranges, int defaultContext) {	int key = getKeyFromMask(defaultContext);	ranges |= CONTEXTUAL_MASK;	return new NumericShaper(key, ranges);    }    /**     * Private constructor.     */    private NumericShaper(int key, int mask) {	this.key = key;	this.mask = mask;    }    /**     * Converts the digits in the text that occur between start and      * start + count.     * @param text an array of characters to convert     * @param start the index into <code>text</code> to start      *        converting     * @param count the number of characters in <code>text</code>     *        to convert     */    public void shape(char[] text, int start, int count) {	if (isContextual()) {	    shapeContextually(text, start, count, key);	} else {	    shapeNonContextually(text, start, count);	}    }    /**     * Converts the digits in the text that occur between start and      * start + count, using the provided context.     * Context is ignored if the shaper is not a contextual shaper.     * @param text an array of characters     * @param start the index into <code>text</code> to start     *        converting     * @param count the number of characters in <code>text</code>     *        to convert     * @param context the context to which to convert the      *        characters, such as <code>NumericShaper.EUROPEAN</code>     */    public void shape(char[] text, int start, int count, int context) {	if (isContextual()) {	    int ctxKey = getKeyFromMask(context);	    shapeContextually(text, start, count, ctxKey);	} else {	    shapeNonContextually(text, start, count);	}    }    /**     * Returns a <code>boolean</code> indicating whether or not     * this shaper shapes contextually.     * @return <code>true</code> if this shaper is contextual;      *         <code>false</code> otherwise.     */    public boolean isContextual() {	return (mask & CONTEXTUAL_MASK) != 0;    }    /**     * Returns an <code>int</code> that ORs together the values for     * all the ranges that will be shaped.     * <p>     * For example, to check if a shaper shapes to Arabic, you would use the      * following:     * <blockquote>     *   <code>if ((shaper.getRanges() & shaper.ARABIC) != 0) { ... </code>     * </blockquote>     * @return the values for all the ranges to be shaped.     */    public int getRanges() {	return mask & ~CONTEXTUAL_MASK;    }    /**     * Perform non-contextual shaping.     */    private void shapeNonContextually(char[] text, int start, int count) {	int base = bases[key];	char minDigit = key == TAMIL_KEY ? '\u0031' : '\u0030'; // Tamil doesn't use decimal zero	for (int i = start, e = start + count; i < e; ++i) {	    char c = text[i];	    if (c >= minDigit && c <= '\u0039') {		text[i] = (char)(c + base);	    }	}    }    /**     * Perform contextual shaping.     * Synchronized to protect caches used in getContextKey and isStrongDirectional.     */    private synchronized void shapeContextually(char[] text, int start, int count, int ctxKey) {	// if we don't support this context, then don't shape	if ((mask & (1<<ctxKey)) == 0) {	    ctxKey = EUROPEAN_KEY;	}	int lastkey = ctxKey;	int base = bases[ctxKey];	char minDigit = ctxKey == TAMIL_KEY ? '\u0031' : '\u0030'; // Tamil doesn't use decimal zero	for (int i = start, e = start + count; i < e; ++i) {	    char c = text[i];	    if (c >= minDigit && c <= '\u0039') {		text[i] = (char)(c + base);	    }	    if (isStrongDirectional(c)) {		int newkey = getContextKey(c);		if (newkey != lastkey) {		    lastkey = newkey;		    ctxKey = newkey;		    if (((mask & EASTERN_ARABIC) != 0) && (ctxKey == ARABIC_KEY || ctxKey == EASTERN_ARABIC_KEY)) {			ctxKey = EASTERN_ARABIC_KEY;		    } else if ((mask & (1<<ctxKey)) == 0) { 			ctxKey = EUROPEAN_KEY;		    }		    base = bases[ctxKey];		    minDigit = ctxKey == TAMIL_KEY ? '\u0031' : '\u0030'; // Tamil doesn't use decimal zero		}	    }	}    }    /**     * Returns a hash code for this shaper.     * @return this shaper's hash code.     * @see java.lang.Object#hashCode     */    public int hashCode() {	return mask;    }    /**     * Returns true if the specified object is an instance of      * <code>NumericShaper</code> and shapes identically to this one.     * @param o the specified object to compare to this     *          <code>NumericShaper</code>     * @return <code>true</code> if <code>o</code> is an instance     *         of <code>NumericShaper</code> and shapes in the same way;     *         <code>false</code> otherwise.     * @see java.lang.Object#equals(java.lang.Object)     */    public boolean equals(Object o) {	if (o != null) {	    try {		NumericShaper rhs = (NumericShaper)o;		return rhs.mask == mask && rhs.key == key;	    }	    catch (ClassCastException e) {	    }	}	return false;    }    /**     * Returns a <code>String</code> that describes this shaper. This method      * is used for debugging purposes only.     * @return a <code>String</code> describing this shaper.     */    public String toString() {	StringBuffer buf = new StringBuffer(super.toString());	buf.append("[contextual:" + isContextual());	if (isContextual()) {	    buf.append(", context:" + keyNames[key]);	}	buf.append(", range(s): ");	boolean first = true;	for (int i = 0; i < NUM_KEYS; ++i) {	    if ((mask & (1 << i)) != 0) {		if (first) {		    first = false;		} else {		    buf.append(", ");		}		buf.append(keyNames[i]);	    }	}	buf.append(']');	return buf.toString();    }    /**     * Returns the index of the high bit in value (assuming le, actually      * power of 2 >= value). value must be positive.     */    private static int getHighBit(int value) { 	if (value <= 0) {	    return -32; 	}	int bit = 0;	if (value >= 1 << 16) {	    value >>= 16;	    bit += 16;	}	if (value >= 1 << 8) {	    value >>= 8;	    bit += 8;	}	if (value >= 1 << 4) {	    value >>= 4;	    bit += 4;	}	if (value >= 1 << 2) {	    value >>= 2;	    bit += 2;	}	if (value >= 1 << 1) {	    value >>= 1;	    bit += 1;	}		return bit;    }    /**     * fast binary search over subrange of array.     */    private static int search(char value, char[] array, int start, int length)     {	int power = 1 << getHighBit(length);	int extra = length - power;	int probe = power;	int index = start;	if (value >= array[index + extra]) {	    index += extra;	}	while (probe > 1) {	    probe >>= 1;	    if (value >= array[index + probe]) {		index += probe;	    }	}	return index;    }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?