feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
89
jdkSrc/jdk8/java/text/Annotation.java
Normal file
89
jdkSrc/jdk8/java/text/Annotation.java
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
/**
|
||||
* An Annotation object is used as a wrapper for a text attribute value if
|
||||
* the attribute has annotation characteristics. These characteristics are:
|
||||
* <ul>
|
||||
* <li>The text range that the attribute is applied to is critical to the
|
||||
* semantics of the range. That means, the attribute cannot be applied to subranges
|
||||
* of the text range that it applies to, and, if two adjacent text ranges have
|
||||
* the same value for this attribute, the attribute still cannot be applied to
|
||||
* the combined range as a whole with this value.
|
||||
* <li>The attribute or its value usually do no longer apply if the underlying text is
|
||||
* changed.
|
||||
* </ul>
|
||||
*
|
||||
* An example is grammatical information attached to a sentence:
|
||||
* For the previous sentence, you can say that "an example"
|
||||
* is the subject, but you cannot say the same about "an", "example", or "exam".
|
||||
* When the text is changed, the grammatical information typically becomes invalid.
|
||||
* Another example is Japanese reading information (yomi).
|
||||
*
|
||||
* <p>
|
||||
* Wrapping the attribute value into an Annotation object guarantees that
|
||||
* adjacent text runs don't get merged even if the attribute values are equal,
|
||||
* and indicates to text containers that the attribute should be discarded if
|
||||
* the underlying text is modified.
|
||||
*
|
||||
* @see AttributedCharacterIterator
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
public class Annotation {
|
||||
|
||||
/**
|
||||
* Constructs an annotation record with the given value, which
|
||||
* may be null.
|
||||
*
|
||||
* @param value the value of the attribute
|
||||
*/
|
||||
public Annotation(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the attribute, which may be null.
|
||||
*
|
||||
* @return the value of the attribute
|
||||
*/
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the String representation of this Annotation.
|
||||
*
|
||||
* @return the {@code String} representation of this {@code Annotation}
|
||||
*/
|
||||
public String toString() {
|
||||
return getClass().getName() + "[value=" + value + "]";
|
||||
}
|
||||
|
||||
private Object value;
|
||||
|
||||
};
|
||||
286
jdkSrc/jdk8/java/text/AttributedCharacterIterator.java
Normal file
286
jdkSrc/jdk8/java/text/AttributedCharacterIterator.java
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* An {@code AttributedCharacterIterator} allows iteration through both text and
|
||||
* related attribute information.
|
||||
*
|
||||
* <p>
|
||||
* An attribute is a key/value pair, identified by the key. No two
|
||||
* attributes on a given character can have the same key.
|
||||
*
|
||||
* <p>The values for an attribute are immutable, or must not be mutated
|
||||
* by clients or storage. They are always passed by reference, and not
|
||||
* cloned.
|
||||
*
|
||||
* <p>A <em>run with respect to an attribute</em> is a maximum text range for
|
||||
* which:
|
||||
* <ul>
|
||||
* <li>the attribute is undefined or {@code null} for the entire range, or
|
||||
* <li>the attribute value is defined and has the same non-{@code null} value for the
|
||||
* entire range.
|
||||
* </ul>
|
||||
*
|
||||
* <p>A <em>run with respect to a set of attributes</em> is a maximum text range for
|
||||
* which this condition is met for each member attribute.
|
||||
*
|
||||
* <p>When getting a run with no explicit attributes specified (i.e.,
|
||||
* calling {@link #getRunStart()} and {@link #getRunLimit()}), any
|
||||
* contiguous text segments having the same attributes (the same set
|
||||
* of attribute/value pairs) are treated as separate runs if the
|
||||
* attributes have been given to those text segments separately.
|
||||
*
|
||||
* <p>The returned indexes are limited to the range of the iterator.
|
||||
*
|
||||
* <p>The returned attribute information is limited to runs that contain
|
||||
* the current character.
|
||||
*
|
||||
* <p>
|
||||
* Attribute keys are instances of {@link AttributedCharacterIterator.Attribute} and its
|
||||
* subclasses, such as {@link java.awt.font.TextAttribute}.
|
||||
*
|
||||
* @see AttributedCharacterIterator.Attribute
|
||||
* @see java.awt.font.TextAttribute
|
||||
* @see AttributedString
|
||||
* @see Annotation
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
public interface AttributedCharacterIterator extends CharacterIterator {
|
||||
|
||||
/**
|
||||
* Defines attribute keys that are used to identify text attributes. These
|
||||
* keys are used in {@code AttributedCharacterIterator} and {@code AttributedString}.
|
||||
* @see AttributedCharacterIterator
|
||||
* @see AttributedString
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
public static class Attribute implements Serializable {
|
||||
|
||||
/**
|
||||
* The name of this {@code Attribute}. The name is used primarily by {@code readResolve}
|
||||
* to look up the corresponding predefined instance when deserializing
|
||||
* an instance.
|
||||
* @serial
|
||||
*/
|
||||
private String name;
|
||||
|
||||
// table of all instances in this class, used by readResolve
|
||||
private static final Map<String, Attribute> instanceMap = new HashMap<>(7);
|
||||
|
||||
/**
|
||||
* Constructs an {@code Attribute} with the given name.
|
||||
*
|
||||
* @param name the name of {@code Attribute}
|
||||
*/
|
||||
protected Attribute(String name) {
|
||||
this.name = name;
|
||||
if (this.getClass() == Attribute.class) {
|
||||
instanceMap.put(name, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two objects for equality. This version only returns true
|
||||
* for {@code x.equals(y)} if {@code x} and {@code y} refer
|
||||
* to the same object, and guarantees this for all subclasses.
|
||||
*/
|
||||
public final boolean equals(Object obj) {
|
||||
return super.equals(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code value for the object. This version is identical to
|
||||
* the one in {@code Object}, but is also final.
|
||||
*/
|
||||
public final int hashCode() {
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the object. This version returns the
|
||||
* concatenation of class name, {@code "("}, a name identifying the attribute
|
||||
* and {@code ")"}.
|
||||
*/
|
||||
public String toString() {
|
||||
return getClass().getName() + "(" + name + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the attribute.
|
||||
*
|
||||
* @return the name of {@code Attribute}
|
||||
*/
|
||||
protected String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves instances being deserialized to the predefined constants.
|
||||
*
|
||||
* @return the resolved {@code Attribute} object
|
||||
* @throws InvalidObjectException if the object to resolve is not
|
||||
* an instance of {@code Attribute}
|
||||
*/
|
||||
protected Object readResolve() throws InvalidObjectException {
|
||||
if (this.getClass() != Attribute.class) {
|
||||
throw new InvalidObjectException("subclass didn't correctly implement readResolve");
|
||||
}
|
||||
|
||||
Attribute instance = instanceMap.get(getName());
|
||||
if (instance != null) {
|
||||
return instance;
|
||||
} else {
|
||||
throw new InvalidObjectException("unknown attribute name");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute key for the language of some text.
|
||||
* <p> Values are instances of {@link java.util.Locale Locale}.
|
||||
* @see java.util.Locale
|
||||
*/
|
||||
public static final Attribute LANGUAGE = new Attribute("language");
|
||||
|
||||
/**
|
||||
* Attribute key for the reading of some text. In languages where the written form
|
||||
* and the pronunciation of a word are only loosely related (such as Japanese),
|
||||
* it is often necessary to store the reading (pronunciation) along with the
|
||||
* written form.
|
||||
* <p>Values are instances of {@link Annotation} holding instances of {@link String}.
|
||||
*
|
||||
* @see Annotation
|
||||
* @see java.lang.String
|
||||
*/
|
||||
public static final Attribute READING = new Attribute("reading");
|
||||
|
||||
/**
|
||||
* Attribute key for input method segments. Input methods often break
|
||||
* up text into segments, which usually correspond to words.
|
||||
* <p>Values are instances of {@link Annotation} holding a {@code null} reference.
|
||||
* @see Annotation
|
||||
*/
|
||||
public static final Attribute INPUT_METHOD_SEGMENT = new Attribute("input_method_segment");
|
||||
|
||||
// make sure the serial version doesn't change between compiler versions
|
||||
private static final long serialVersionUID = -9142742483513960612L;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the index of the first character of the run
|
||||
* with respect to all attributes containing the current character.
|
||||
*
|
||||
* <p>Any contiguous text segments having the same attributes (the
|
||||
* same set of attribute/value pairs) are treated as separate runs
|
||||
* if the attributes have been given to those text segments separately.
|
||||
*
|
||||
* @return the index of the first character of the run
|
||||
*/
|
||||
public int getRunStart();
|
||||
|
||||
/**
|
||||
* Returns the index of the first character of the run
|
||||
* with respect to the given {@code attribute} containing the current character.
|
||||
*
|
||||
* @param attribute the desired attribute.
|
||||
* @return the index of the first character of the run
|
||||
*/
|
||||
public int getRunStart(Attribute attribute);
|
||||
|
||||
/**
|
||||
* Returns the index of the first character of the run
|
||||
* with respect to the given {@code attributes} containing the current character.
|
||||
*
|
||||
* @param attributes a set of the desired attributes.
|
||||
* @return the index of the first character of the run
|
||||
*/
|
||||
public int getRunStart(Set<? extends Attribute> attributes);
|
||||
|
||||
/**
|
||||
* Returns the index of the first character following the run
|
||||
* with respect to all attributes containing the current character.
|
||||
*
|
||||
* <p>Any contiguous text segments having the same attributes (the
|
||||
* same set of attribute/value pairs) are treated as separate runs
|
||||
* if the attributes have been given to those text segments separately.
|
||||
*
|
||||
* @return the index of the first character following the run
|
||||
*/
|
||||
public int getRunLimit();
|
||||
|
||||
/**
|
||||
* Returns the index of the first character following the run
|
||||
* with respect to the given {@code attribute} containing the current character.
|
||||
*
|
||||
* @param attribute the desired attribute
|
||||
* @return the index of the first character following the run
|
||||
*/
|
||||
public int getRunLimit(Attribute attribute);
|
||||
|
||||
/**
|
||||
* Returns the index of the first character following the run
|
||||
* with respect to the given {@code attributes} containing the current character.
|
||||
*
|
||||
* @param attributes a set of the desired attributes
|
||||
* @return the index of the first character following the run
|
||||
*/
|
||||
public int getRunLimit(Set<? extends Attribute> attributes);
|
||||
|
||||
/**
|
||||
* Returns a map with the attributes defined on the current
|
||||
* character.
|
||||
*
|
||||
* @return a map with the attributes defined on the current character
|
||||
*/
|
||||
public Map<Attribute,Object> getAttributes();
|
||||
|
||||
/**
|
||||
* Returns the value of the named {@code attribute} for the current character.
|
||||
* Returns {@code null} if the {@code attribute} is not defined.
|
||||
*
|
||||
* @param attribute the desired attribute
|
||||
* @return the value of the named {@code attribute} or {@code null}
|
||||
*/
|
||||
public Object getAttribute(Attribute attribute);
|
||||
|
||||
/**
|
||||
* Returns the keys of all attributes defined on the
|
||||
* iterator's text range. The set is empty if no
|
||||
* attributes are defined.
|
||||
*
|
||||
* @return the keys of all attributes
|
||||
*/
|
||||
public Set<Attribute> getAllAttributeKeys();
|
||||
};
|
||||
1133
jdkSrc/jdk8/java/text/AttributedString.java
Normal file
1133
jdkSrc/jdk8/java/text/AttributedString.java
Normal file
File diff suppressed because it is too large
Load Diff
334
jdkSrc/jdk8/java/text/Bidi.java
Normal file
334
jdkSrc/jdk8/java/text/Bidi.java
Normal file
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright IBM Corp. 1999-2003 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is
|
||||
* copyrighted and owned by IBM. These materials are provided
|
||||
* under terms of a License Agreement between IBM and Sun.
|
||||
* This technology is protected by multiple US and International
|
||||
* patents. This notice and attribution to IBM may not be removed.
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
import sun.text.bidi.BidiBase;
|
||||
|
||||
/**
|
||||
* This class implements the Unicode Bidirectional Algorithm.
|
||||
* <p>
|
||||
* A Bidi object provides information on the bidirectional reordering of the text
|
||||
* used to create it. This is required, for example, to properly display Arabic
|
||||
* or Hebrew text. These languages are inherently mixed directional, as they order
|
||||
* numbers from left-to-right while ordering most other text from right-to-left.
|
||||
* <p>
|
||||
* Once created, a Bidi object can be queried to see if the text it represents is
|
||||
* all left-to-right or all right-to-left. Such objects are very lightweight and
|
||||
* this text is relatively easy to process.
|
||||
* <p>
|
||||
* If there are multiple runs of text, information about the runs can be accessed
|
||||
* by indexing to get the start, limit, and level of a run. The level represents
|
||||
* both the direction and the 'nesting level' of a directional run. Odd levels
|
||||
* are right-to-left, while even levels are left-to-right. So for example level
|
||||
* 0 represents left-to-right text, while level 1 represents right-to-left text, and
|
||||
* level 2 represents left-to-right text embedded in a right-to-left run.
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
public final class Bidi {
|
||||
|
||||
/** Constant indicating base direction is left-to-right. */
|
||||
public static final int DIRECTION_LEFT_TO_RIGHT = 0;
|
||||
|
||||
/** Constant indicating base direction is right-to-left. */
|
||||
public static final int DIRECTION_RIGHT_TO_LEFT = 1;
|
||||
|
||||
/**
|
||||
* Constant indicating that the base direction depends on the first strong
|
||||
* directional character in the text according to the Unicode
|
||||
* Bidirectional Algorithm. If no strong directional character is present,
|
||||
* the base direction is left-to-right.
|
||||
*/
|
||||
public static final int DIRECTION_DEFAULT_LEFT_TO_RIGHT = -2;
|
||||
|
||||
/**
|
||||
* Constant indicating that the base direction depends on the first strong
|
||||
* directional character in the text according to the Unicode
|
||||
* Bidirectional Algorithm. If no strong directional character is present,
|
||||
* the base direction is right-to-left.
|
||||
*/
|
||||
public static final int DIRECTION_DEFAULT_RIGHT_TO_LEFT = -1;
|
||||
|
||||
private BidiBase bidiBase;
|
||||
|
||||
/**
|
||||
* Create Bidi from the given paragraph of text and base direction.
|
||||
* @param paragraph a paragraph of text
|
||||
* @param flags a collection of flags that control the algorithm. The
|
||||
* algorithm understands the flags DIRECTION_LEFT_TO_RIGHT, DIRECTION_RIGHT_TO_LEFT,
|
||||
* DIRECTION_DEFAULT_LEFT_TO_RIGHT, and DIRECTION_DEFAULT_RIGHT_TO_LEFT.
|
||||
* Other values are reserved.
|
||||
*/
|
||||
public Bidi(String paragraph, int flags) {
|
||||
if (paragraph == null) {
|
||||
throw new IllegalArgumentException("paragraph is null");
|
||||
}
|
||||
|
||||
bidiBase = new BidiBase(paragraph.toCharArray(), 0, null, 0, paragraph.length(), flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Bidi from the given paragraph of text.
|
||||
* <p>
|
||||
* The RUN_DIRECTION attribute in the text, if present, determines the base
|
||||
* direction (left-to-right or right-to-left). If not present, the base
|
||||
* direction is computes using the Unicode Bidirectional Algorithm, defaulting to left-to-right
|
||||
* if there are no strong directional characters in the text. This attribute, if
|
||||
* present, must be applied to all the text in the paragraph.
|
||||
* <p>
|
||||
* The BIDI_EMBEDDING attribute in the text, if present, represents embedding level
|
||||
* information. Negative values from -1 to -62 indicate overrides at the absolute value
|
||||
* of the level. Positive values from 1 to 62 indicate embeddings. Where values are
|
||||
* zero or not defined, the base embedding level as determined by the base direction
|
||||
* is assumed.
|
||||
* <p>
|
||||
* The NUMERIC_SHAPING attribute in the text, if present, converts European digits to
|
||||
* other decimal digits before running the bidi algorithm. This attribute, if present,
|
||||
* must be applied to all the text in the paragraph.
|
||||
*
|
||||
* @param paragraph a paragraph of text with optional character and paragraph attribute information
|
||||
*
|
||||
* @see java.awt.font.TextAttribute#BIDI_EMBEDDING
|
||||
* @see java.awt.font.TextAttribute#NUMERIC_SHAPING
|
||||
* @see java.awt.font.TextAttribute#RUN_DIRECTION
|
||||
*/
|
||||
public Bidi(AttributedCharacterIterator paragraph) {
|
||||
if (paragraph == null) {
|
||||
throw new IllegalArgumentException("paragraph is null");
|
||||
}
|
||||
|
||||
bidiBase = new BidiBase(0, 0);
|
||||
bidiBase.setPara(paragraph);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Bidi from the given text, embedding, and direction information.
|
||||
* The embeddings array may be null. If present, the values represent embedding level
|
||||
* information. Negative values from -1 to -61 indicate overrides at the absolute value
|
||||
* of the level. Positive values from 1 to 61 indicate embeddings. Where values are
|
||||
* zero, the base embedding level as determined by the base direction is assumed.
|
||||
* @param text an array containing the paragraph of text to process.
|
||||
* @param textStart the index into the text array of the start of the paragraph.
|
||||
* @param embeddings an array containing embedding values for each character in the paragraph.
|
||||
* This can be null, in which case it is assumed that there is no external embedding information.
|
||||
* @param embStart the index into the embedding array of the start of the paragraph.
|
||||
* @param paragraphLength the length of the paragraph in the text and embeddings arrays.
|
||||
* @param flags a collection of flags that control the algorithm. The
|
||||
* algorithm understands the flags DIRECTION_LEFT_TO_RIGHT, DIRECTION_RIGHT_TO_LEFT,
|
||||
* DIRECTION_DEFAULT_LEFT_TO_RIGHT, and DIRECTION_DEFAULT_RIGHT_TO_LEFT.
|
||||
* Other values are reserved.
|
||||
*/
|
||||
public Bidi(char[] text, int textStart, byte[] embeddings, int embStart, int paragraphLength, int flags) {
|
||||
if (text == null) {
|
||||
throw new IllegalArgumentException("text is null");
|
||||
}
|
||||
if (paragraphLength < 0) {
|
||||
throw new IllegalArgumentException("bad length: " + paragraphLength);
|
||||
}
|
||||
if (textStart < 0 || paragraphLength > text.length - textStart) {
|
||||
throw new IllegalArgumentException("bad range: " + textStart +
|
||||
" length: " + paragraphLength +
|
||||
" for text of length: " + text.length);
|
||||
}
|
||||
if (embeddings != null && (embStart < 0 || paragraphLength > embeddings.length - embStart)) {
|
||||
throw new IllegalArgumentException("bad range: " + embStart +
|
||||
" length: " + paragraphLength +
|
||||
" for embeddings of length: " + text.length);
|
||||
}
|
||||
|
||||
bidiBase = new BidiBase(text, textStart, embeddings, embStart, paragraphLength, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bidi object representing the bidi information on a line of text within
|
||||
* the paragraph represented by the current Bidi. This call is not required if the
|
||||
* entire paragraph fits on one line.
|
||||
*
|
||||
* @param lineStart the offset from the start of the paragraph to the start of the line.
|
||||
* @param lineLimit the offset from the start of the paragraph to the limit of the line.
|
||||
* @return a {@code Bidi} object
|
||||
*/
|
||||
public Bidi createLineBidi(int lineStart, int lineLimit) {
|
||||
AttributedString astr = new AttributedString("");
|
||||
Bidi newBidi = new Bidi(astr.getIterator());
|
||||
|
||||
return bidiBase.setLine(this, bidiBase, newBidi, newBidi.bidiBase,lineStart, lineLimit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the line is not left-to-right or right-to-left. This means it either has mixed runs of left-to-right
|
||||
* and right-to-left text, or the base direction differs from the direction of the only run of text.
|
||||
*
|
||||
* @return true if the line is not left-to-right or right-to-left.
|
||||
*/
|
||||
public boolean isMixed() {
|
||||
return bidiBase.isMixed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the line is all left-to-right text and the base direction is left-to-right.
|
||||
*
|
||||
* @return true if the line is all left-to-right text and the base direction is left-to-right
|
||||
*/
|
||||
public boolean isLeftToRight() {
|
||||
return bidiBase.isLeftToRight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the line is all right-to-left text, and the base direction is right-to-left.
|
||||
* @return true if the line is all right-to-left text, and the base direction is right-to-left
|
||||
*/
|
||||
public boolean isRightToLeft() {
|
||||
return bidiBase.isRightToLeft();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the length of text in the line.
|
||||
* @return the length of text in the line
|
||||
*/
|
||||
public int getLength() {
|
||||
return bidiBase.getLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the base direction is left-to-right.
|
||||
* @return true if the base direction is left-to-right
|
||||
*/
|
||||
public boolean baseIsLeftToRight() {
|
||||
return bidiBase.baseIsLeftToRight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the base level (0 if left-to-right, 1 if right-to-left).
|
||||
* @return the base level
|
||||
*/
|
||||
public int getBaseLevel() {
|
||||
return bidiBase.getParaLevel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resolved level of the character at offset. If offset is
|
||||
* {@literal <} 0 or ≥ the length of the line, return the base direction
|
||||
* level.
|
||||
*
|
||||
* @param offset the index of the character for which to return the level
|
||||
* @return the resolved level of the character at offset
|
||||
*/
|
||||
public int getLevelAt(int offset) {
|
||||
return bidiBase.getLevelAt(offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of level runs.
|
||||
* @return the number of level runs
|
||||
*/
|
||||
public int getRunCount() {
|
||||
return bidiBase.countRuns();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the level of the nth logical run in this line.
|
||||
* @param run the index of the run, between 0 and <code>getRunCount()</code>
|
||||
* @return the level of the run
|
||||
*/
|
||||
public int getRunLevel(int run) {
|
||||
return bidiBase.getRunLevel(run);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index of the character at the start of the nth logical run in this line, as
|
||||
* an offset from the start of the line.
|
||||
* @param run the index of the run, between 0 and <code>getRunCount()</code>
|
||||
* @return the start of the run
|
||||
*/
|
||||
public int getRunStart(int run) {
|
||||
return bidiBase.getRunStart(run);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index of the character past the end of the nth logical run in this line, as
|
||||
* an offset from the start of the line. For example, this will return the length
|
||||
* of the line for the last run on the line.
|
||||
* @param run the index of the run, between 0 and <code>getRunCount()</code>
|
||||
* @return limit the limit of the run
|
||||
*/
|
||||
public int getRunLimit(int run) {
|
||||
return bidiBase.getRunLimit(run);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the specified text requires bidi analysis. If this returns false,
|
||||
* the text will display left-to-right. Clients can then avoid constructing a Bidi object.
|
||||
* Text in the Arabic Presentation Forms area of Unicode is presumed to already be shaped
|
||||
* and ordered for display, and so will not cause this function to return true.
|
||||
*
|
||||
* @param text the text containing the characters to test
|
||||
* @param start the start of the range of characters to test
|
||||
* @param limit the limit of the range of characters to test
|
||||
* @return true if the range of characters requires bidi analysis
|
||||
*/
|
||||
public static boolean requiresBidi(char[] text, int start, int limit) {
|
||||
return BidiBase.requiresBidi(text, start, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder the objects in the array into visual order based on their levels.
|
||||
* This is a utility function to use when you have a collection of objects
|
||||
* representing runs of text in logical order, each run containing text
|
||||
* at a single level. The elements at <code>index</code> from
|
||||
* <code>objectStart</code> up to <code>objectStart + count</code>
|
||||
* in the objects array will be reordered into visual order assuming
|
||||
* each run of text has the level indicated by the corresponding element
|
||||
* in the levels array (at <code>index - objectStart + levelStart</code>).
|
||||
*
|
||||
* @param levels an array representing the bidi level of each object
|
||||
* @param levelStart the start position in the levels array
|
||||
* @param objects the array of objects to be reordered into visual order
|
||||
* @param objectStart the start position in the objects array
|
||||
* @param count the number of objects to reorder
|
||||
*/
|
||||
public static void reorderVisually(byte[] levels, int levelStart, Object[] objects, int objectStart, int count) {
|
||||
BidiBase.reorderVisually(levels, levelStart, objects, objectStart, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the bidi internal state, used in debugging.
|
||||
*/
|
||||
public String toString() {
|
||||
return bidiBase.toString();
|
||||
}
|
||||
|
||||
}
|
||||
618
jdkSrc/jdk8/java/text/BreakIterator.java
Normal file
618
jdkSrc/jdk8/java/text/BreakIterator.java
Normal file
@@ -0,0 +1,618 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation
|
||||
* is copyrighted and owned by Taligent, Inc., a wholly-owned
|
||||
* subsidiary of IBM. These materials are provided under terms
|
||||
* of a License Agreement between Taligent and Sun. This technology
|
||||
* is protected by multiple US and International patents.
|
||||
*
|
||||
* This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.text.spi.BreakIteratorProvider;
|
||||
import java.util.Locale;
|
||||
import sun.util.locale.provider.LocaleProviderAdapter;
|
||||
import sun.util.locale.provider.LocaleServiceProviderPool;
|
||||
|
||||
|
||||
/**
|
||||
* The <code>BreakIterator</code> class implements methods for finding
|
||||
* the location of boundaries in text. Instances of <code>BreakIterator</code>
|
||||
* maintain a current position and scan over text
|
||||
* returning the index of characters where boundaries occur.
|
||||
* Internally, <code>BreakIterator</code> scans text using a
|
||||
* <code>CharacterIterator</code>, and is thus able to scan text held
|
||||
* by any object implementing that protocol. A <code>StringCharacterIterator</code>
|
||||
* is used to scan <code>String</code> objects passed to <code>setText</code>.
|
||||
*
|
||||
* <p>
|
||||
* You use the factory methods provided by this class to create
|
||||
* instances of various types of break iterators. In particular,
|
||||
* use <code>getWordInstance</code>, <code>getLineInstance</code>,
|
||||
* <code>getSentenceInstance</code>, and <code>getCharacterInstance</code>
|
||||
* to create <code>BreakIterator</code>s that perform
|
||||
* word, line, sentence, and character boundary analysis respectively.
|
||||
* A single <code>BreakIterator</code> can work only on one unit
|
||||
* (word, line, sentence, and so on). You must use a different iterator
|
||||
* for each unit boundary analysis you wish to perform.
|
||||
*
|
||||
* <p><a name="line"></a>
|
||||
* Line boundary analysis determines where a text string can be
|
||||
* broken when line-wrapping. The mechanism correctly handles
|
||||
* punctuation and hyphenated words. Actual line breaking needs
|
||||
* to also consider the available line width and is handled by
|
||||
* higher-level software.
|
||||
*
|
||||
* <p><a name="sentence"></a>
|
||||
* Sentence boundary analysis allows selection with correct interpretation
|
||||
* of periods within numbers and abbreviations, and trailing punctuation
|
||||
* marks such as quotation marks and parentheses.
|
||||
*
|
||||
* <p><a name="word"></a>
|
||||
* Word boundary analysis is used by search and replace functions, as
|
||||
* well as within text editing applications that allow the user to
|
||||
* select words with a double click. Word selection provides correct
|
||||
* interpretation of punctuation marks within and following
|
||||
* words. Characters that are not part of a word, such as symbols
|
||||
* or punctuation marks, have word-breaks on both sides.
|
||||
*
|
||||
* <p><a name="character"></a>
|
||||
* Character boundary analysis allows users to interact with characters
|
||||
* as they expect to, for example, when moving the cursor through a text
|
||||
* string. Character boundary analysis provides correct navigation
|
||||
* through character strings, regardless of how the character is stored.
|
||||
* The boundaries returned may be those of supplementary characters,
|
||||
* combining character sequences, or ligature clusters.
|
||||
* For example, an accented character might be stored as a base character
|
||||
* and a diacritical mark. What users consider to be a character can
|
||||
* differ between languages.
|
||||
*
|
||||
* <p>
|
||||
* The <code>BreakIterator</code> instances returned by the factory methods
|
||||
* of this class are intended for use with natural languages only, not for
|
||||
* programming language text. It is however possible to define subclasses
|
||||
* that tokenize a programming language.
|
||||
*
|
||||
* <P>
|
||||
* <strong>Examples</strong>:<P>
|
||||
* Creating and using text boundaries:
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* public static void main(String args[]) {
|
||||
* if (args.length == 1) {
|
||||
* String stringToExamine = args[0];
|
||||
* //print each word in order
|
||||
* BreakIterator boundary = BreakIterator.getWordInstance();
|
||||
* boundary.setText(stringToExamine);
|
||||
* printEachForward(boundary, stringToExamine);
|
||||
* //print each sentence in reverse order
|
||||
* boundary = BreakIterator.getSentenceInstance(Locale.US);
|
||||
* boundary.setText(stringToExamine);
|
||||
* printEachBackward(boundary, stringToExamine);
|
||||
* printFirst(boundary, stringToExamine);
|
||||
* printLast(boundary, stringToExamine);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* Print each element in order:
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* public static void printEachForward(BreakIterator boundary, String source) {
|
||||
* int start = boundary.first();
|
||||
* for (int end = boundary.next();
|
||||
* end != BreakIterator.DONE;
|
||||
* start = end, end = boundary.next()) {
|
||||
* System.out.println(source.substring(start,end));
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* Print each element in reverse order:
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* public static void printEachBackward(BreakIterator boundary, String source) {
|
||||
* int end = boundary.last();
|
||||
* for (int start = boundary.previous();
|
||||
* start != BreakIterator.DONE;
|
||||
* end = start, start = boundary.previous()) {
|
||||
* System.out.println(source.substring(start,end));
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* Print first element:
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* public static void printFirst(BreakIterator boundary, String source) {
|
||||
* int start = boundary.first();
|
||||
* int end = boundary.next();
|
||||
* System.out.println(source.substring(start,end));
|
||||
* }
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* Print last element:
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* public static void printLast(BreakIterator boundary, String source) {
|
||||
* int end = boundary.last();
|
||||
* int start = boundary.previous();
|
||||
* System.out.println(source.substring(start,end));
|
||||
* }
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* Print the element at a specified position:
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* public static void printAt(BreakIterator boundary, int pos, String source) {
|
||||
* int end = boundary.following(pos);
|
||||
* int start = boundary.previous();
|
||||
* System.out.println(source.substring(start,end));
|
||||
* }
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* Find the next word:
|
||||
* <blockquote>
|
||||
* <pre>{@code
|
||||
* public static int nextWordStartAfter(int pos, String text) {
|
||||
* BreakIterator wb = BreakIterator.getWordInstance();
|
||||
* wb.setText(text);
|
||||
* int last = wb.following(pos);
|
||||
* int current = wb.next();
|
||||
* while (current != BreakIterator.DONE) {
|
||||
* for (int p = last; p < current; p++) {
|
||||
* if (Character.isLetter(text.codePointAt(p)))
|
||||
* return last;
|
||||
* }
|
||||
* last = current;
|
||||
* current = wb.next();
|
||||
* }
|
||||
* return BreakIterator.DONE;
|
||||
* }
|
||||
* }</pre>
|
||||
* (The iterator returned by BreakIterator.getWordInstance() is unique in that
|
||||
* the break positions it returns don't represent both the start and end of the
|
||||
* thing being iterated over. That is, a sentence-break iterator returns breaks
|
||||
* that each represent the end of one sentence and the beginning of the next.
|
||||
* With the word-break iterator, the characters between two boundaries might be a
|
||||
* word, or they might be the punctuation or whitespace between two words. The
|
||||
* above code uses a simple heuristic to determine which boundary is the beginning
|
||||
* of a word: If the characters between this boundary and the next boundary
|
||||
* include at least one letter (this can be an alphabetical letter, a CJK ideograph,
|
||||
* a Hangul syllable, a Kana character, etc.), then the text between this boundary
|
||||
* and the next is a word; otherwise, it's the material between words.)
|
||||
* </blockquote>
|
||||
*
|
||||
* @see CharacterIterator
|
||||
*
|
||||
*/
|
||||
|
||||
public abstract class BreakIterator implements Cloneable
|
||||
{
|
||||
/**
|
||||
* Constructor. BreakIterator is stateless and has no default behavior.
|
||||
*/
|
||||
protected BreakIterator()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of this iterator
|
||||
* @return A copy of this
|
||||
*/
|
||||
@Override
|
||||
public Object clone()
|
||||
{
|
||||
try {
|
||||
return super.clone();
|
||||
}
|
||||
catch (CloneNotSupportedException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DONE is returned by previous(), next(), next(int), preceding(int)
|
||||
* and following(int) when either the first or last text boundary has been
|
||||
* reached.
|
||||
*/
|
||||
public static final int DONE = -1;
|
||||
|
||||
/**
|
||||
* Returns the first boundary. The iterator's current position is set
|
||||
* to the first text boundary.
|
||||
* @return The character index of the first text boundary.
|
||||
*/
|
||||
public abstract int first();
|
||||
|
||||
/**
|
||||
* Returns the last boundary. The iterator's current position is set
|
||||
* to the last text boundary.
|
||||
* @return The character index of the last text boundary.
|
||||
*/
|
||||
public abstract int last();
|
||||
|
||||
/**
|
||||
* Returns the nth boundary from the current boundary. If either
|
||||
* the first or last text boundary has been reached, it returns
|
||||
* <code>BreakIterator.DONE</code> and the current position is set to either
|
||||
* the first or last text boundary depending on which one is reached. Otherwise,
|
||||
* the iterator's current position is set to the new boundary.
|
||||
* For example, if the iterator's current position is the mth text boundary
|
||||
* and three more boundaries exist from the current boundary to the last text
|
||||
* boundary, the next(2) call will return m + 2. The new text position is set
|
||||
* to the (m + 2)th text boundary. A next(4) call would return
|
||||
* <code>BreakIterator.DONE</code> and the last text boundary would become the
|
||||
* new text position.
|
||||
* @param n which boundary to return. A value of 0
|
||||
* does nothing. Negative values move to previous boundaries
|
||||
* and positive values move to later boundaries.
|
||||
* @return The character index of the nth boundary from the current position
|
||||
* or <code>BreakIterator.DONE</code> if either first or last text boundary
|
||||
* has been reached.
|
||||
*/
|
||||
public abstract int next(int n);
|
||||
|
||||
/**
|
||||
* Returns the boundary following the current boundary. If the current boundary
|
||||
* is the last text boundary, it returns <code>BreakIterator.DONE</code> and
|
||||
* the iterator's current position is unchanged. Otherwise, the iterator's
|
||||
* current position is set to the boundary following the current boundary.
|
||||
* @return The character index of the next text boundary or
|
||||
* <code>BreakIterator.DONE</code> if the current boundary is the last text
|
||||
* boundary.
|
||||
* Equivalent to next(1).
|
||||
* @see #next(int)
|
||||
*/
|
||||
public abstract int next();
|
||||
|
||||
/**
|
||||
* Returns the boundary preceding the current boundary. If the current boundary
|
||||
* is the first text boundary, it returns <code>BreakIterator.DONE</code> and
|
||||
* the iterator's current position is unchanged. Otherwise, the iterator's
|
||||
* current position is set to the boundary preceding the current boundary.
|
||||
* @return The character index of the previous text boundary or
|
||||
* <code>BreakIterator.DONE</code> if the current boundary is the first text
|
||||
* boundary.
|
||||
*/
|
||||
public abstract int previous();
|
||||
|
||||
/**
|
||||
* Returns the first boundary following the specified character offset. If the
|
||||
* specified offset equals to the last text boundary, it returns
|
||||
* <code>BreakIterator.DONE</code> and the iterator's current position is unchanged.
|
||||
* Otherwise, the iterator's current position is set to the returned boundary.
|
||||
* The value returned is always greater than the offset or the value
|
||||
* <code>BreakIterator.DONE</code>.
|
||||
* @param offset the character offset to begin scanning.
|
||||
* @return The first boundary after the specified offset or
|
||||
* <code>BreakIterator.DONE</code> if the last text boundary is passed in
|
||||
* as the offset.
|
||||
* @exception IllegalArgumentException if the specified offset is less than
|
||||
* the first text boundary or greater than the last text boundary.
|
||||
*/
|
||||
public abstract int following(int offset);
|
||||
|
||||
/**
|
||||
* Returns the last boundary preceding the specified character offset. If the
|
||||
* specified offset equals to the first text boundary, it returns
|
||||
* <code>BreakIterator.DONE</code> and the iterator's current position is unchanged.
|
||||
* Otherwise, the iterator's current position is set to the returned boundary.
|
||||
* The value returned is always less than the offset or the value
|
||||
* <code>BreakIterator.DONE</code>.
|
||||
* @param offset the character offset to begin scanning.
|
||||
* @return The last boundary before the specified offset or
|
||||
* <code>BreakIterator.DONE</code> if the first text boundary is passed in
|
||||
* as the offset.
|
||||
* @exception IllegalArgumentException if the specified offset is less than
|
||||
* the first text boundary or greater than the last text boundary.
|
||||
* @since 1.2
|
||||
*/
|
||||
public int preceding(int offset) {
|
||||
// NOTE: This implementation is here solely because we can't add new
|
||||
// abstract methods to an existing class. There is almost ALWAYS a
|
||||
// better, faster way to do this.
|
||||
int pos = following(offset);
|
||||
while (pos >= offset && pos != DONE) {
|
||||
pos = previous();
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified character offset is a text boundary.
|
||||
* @param offset the character offset to check.
|
||||
* @return <code>true</code> if "offset" is a boundary position,
|
||||
* <code>false</code> otherwise.
|
||||
* @exception IllegalArgumentException if the specified offset is less than
|
||||
* the first text boundary or greater than the last text boundary.
|
||||
* @since 1.2
|
||||
*/
|
||||
public boolean isBoundary(int offset) {
|
||||
// NOTE: This implementation probably is wrong for most situations
|
||||
// because it fails to take into account the possibility that a
|
||||
// CharacterIterator passed to setText() may not have a begin offset
|
||||
// of 0. But since the abstract BreakIterator doesn't have that
|
||||
// knowledge, it assumes the begin offset is 0. If you subclass
|
||||
// BreakIterator, copy the SimpleTextBoundary implementation of this
|
||||
// function into your subclass. [This should have been abstract at
|
||||
// this level, but it's too late to fix that now.]
|
||||
if (offset == 0) {
|
||||
return true;
|
||||
}
|
||||
int boundary = following(offset - 1);
|
||||
if (boundary == DONE) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return boundary == offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns character index of the text boundary that was most
|
||||
* recently returned by next(), next(int), previous(), first(), last(),
|
||||
* following(int) or preceding(int). If any of these methods returns
|
||||
* <code>BreakIterator.DONE</code> because either first or last text boundary
|
||||
* has been reached, it returns the first or last text boundary depending on
|
||||
* which one is reached.
|
||||
* @return The text boundary returned from the above methods, first or last
|
||||
* text boundary.
|
||||
* @see #next()
|
||||
* @see #next(int)
|
||||
* @see #previous()
|
||||
* @see #first()
|
||||
* @see #last()
|
||||
* @see #following(int)
|
||||
* @see #preceding(int)
|
||||
*/
|
||||
public abstract int current();
|
||||
|
||||
/**
|
||||
* Get the text being scanned
|
||||
* @return the text being scanned
|
||||
*/
|
||||
public abstract CharacterIterator getText();
|
||||
|
||||
/**
|
||||
* Set a new text string to be scanned. The current scan
|
||||
* position is reset to first().
|
||||
* @param newText new text to scan.
|
||||
*/
|
||||
public void setText(String newText)
|
||||
{
|
||||
setText(new StringCharacterIterator(newText));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a new text for scanning. The current scan
|
||||
* position is reset to first().
|
||||
* @param newText new text to scan.
|
||||
*/
|
||||
public abstract void setText(CharacterIterator newText);
|
||||
|
||||
private static final int CHARACTER_INDEX = 0;
|
||||
private static final int WORD_INDEX = 1;
|
||||
private static final int LINE_INDEX = 2;
|
||||
private static final int SENTENCE_INDEX = 3;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final SoftReference<BreakIteratorCache>[] iterCache = (SoftReference<BreakIteratorCache>[]) new SoftReference<?>[4];
|
||||
|
||||
/**
|
||||
* Returns a new <code>BreakIterator</code> instance
|
||||
* for <a href="BreakIterator.html#word">word breaks</a>
|
||||
* for the {@linkplain Locale#getDefault() default locale}.
|
||||
* @return A break iterator for word breaks
|
||||
*/
|
||||
public static BreakIterator getWordInstance()
|
||||
{
|
||||
return getWordInstance(Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new <code>BreakIterator</code> instance
|
||||
* for <a href="BreakIterator.html#word">word breaks</a>
|
||||
* for the given locale.
|
||||
* @param locale the desired locale
|
||||
* @return A break iterator for word breaks
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
*/
|
||||
public static BreakIterator getWordInstance(Locale locale)
|
||||
{
|
||||
return getBreakInstance(locale, WORD_INDEX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new <code>BreakIterator</code> instance
|
||||
* for <a href="BreakIterator.html#line">line breaks</a>
|
||||
* for the {@linkplain Locale#getDefault() default locale}.
|
||||
* @return A break iterator for line breaks
|
||||
*/
|
||||
public static BreakIterator getLineInstance()
|
||||
{
|
||||
return getLineInstance(Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new <code>BreakIterator</code> instance
|
||||
* for <a href="BreakIterator.html#line">line breaks</a>
|
||||
* for the given locale.
|
||||
* @param locale the desired locale
|
||||
* @return A break iterator for line breaks
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
*/
|
||||
public static BreakIterator getLineInstance(Locale locale)
|
||||
{
|
||||
return getBreakInstance(locale, LINE_INDEX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new <code>BreakIterator</code> instance
|
||||
* for <a href="BreakIterator.html#character">character breaks</a>
|
||||
* for the {@linkplain Locale#getDefault() default locale}.
|
||||
* @return A break iterator for character breaks
|
||||
*/
|
||||
public static BreakIterator getCharacterInstance()
|
||||
{
|
||||
return getCharacterInstance(Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new <code>BreakIterator</code> instance
|
||||
* for <a href="BreakIterator.html#character">character breaks</a>
|
||||
* for the given locale.
|
||||
* @param locale the desired locale
|
||||
* @return A break iterator for character breaks
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
*/
|
||||
public static BreakIterator getCharacterInstance(Locale locale)
|
||||
{
|
||||
return getBreakInstance(locale, CHARACTER_INDEX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new <code>BreakIterator</code> instance
|
||||
* for <a href="BreakIterator.html#sentence">sentence breaks</a>
|
||||
* for the {@linkplain Locale#getDefault() default locale}.
|
||||
* @return A break iterator for sentence breaks
|
||||
*/
|
||||
public static BreakIterator getSentenceInstance()
|
||||
{
|
||||
return getSentenceInstance(Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new <code>BreakIterator</code> instance
|
||||
* for <a href="BreakIterator.html#sentence">sentence breaks</a>
|
||||
* for the given locale.
|
||||
* @param locale the desired locale
|
||||
* @return A break iterator for sentence breaks
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
*/
|
||||
public static BreakIterator getSentenceInstance(Locale locale)
|
||||
{
|
||||
return getBreakInstance(locale, SENTENCE_INDEX);
|
||||
}
|
||||
|
||||
private static BreakIterator getBreakInstance(Locale locale, int type) {
|
||||
if (iterCache[type] != null) {
|
||||
BreakIteratorCache cache = iterCache[type].get();
|
||||
if (cache != null) {
|
||||
if (cache.getLocale().equals(locale)) {
|
||||
return cache.createBreakInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BreakIterator result = createBreakInstance(locale, type);
|
||||
BreakIteratorCache cache = new BreakIteratorCache(locale, result);
|
||||
iterCache[type] = new SoftReference<>(cache);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static BreakIterator createBreakInstance(Locale locale,
|
||||
int type) {
|
||||
LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(BreakIteratorProvider.class, locale);
|
||||
BreakIterator iterator = createBreakInstance(adapter, locale, type);
|
||||
if (iterator == null) {
|
||||
iterator = createBreakInstance(LocaleProviderAdapter.forJRE(), locale, type);
|
||||
}
|
||||
return iterator;
|
||||
}
|
||||
|
||||
private static BreakIterator createBreakInstance(LocaleProviderAdapter adapter, Locale locale, int type) {
|
||||
BreakIteratorProvider breakIteratorProvider = adapter.getBreakIteratorProvider();
|
||||
BreakIterator iterator = null;
|
||||
switch (type) {
|
||||
case CHARACTER_INDEX:
|
||||
iterator = breakIteratorProvider.getCharacterInstance(locale);
|
||||
break;
|
||||
case WORD_INDEX:
|
||||
iterator = breakIteratorProvider.getWordInstance(locale);
|
||||
break;
|
||||
case LINE_INDEX:
|
||||
iterator = breakIteratorProvider.getLineInstance(locale);
|
||||
break;
|
||||
case SENTENCE_INDEX:
|
||||
iterator = breakIteratorProvider.getSentenceInstance(locale);
|
||||
break;
|
||||
}
|
||||
return iterator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all locales for which the
|
||||
* <code>get*Instance</code> methods of this class can return
|
||||
* localized instances.
|
||||
* The returned array represents the union of locales supported by the Java
|
||||
* runtime and by installed
|
||||
* {@link java.text.spi.BreakIteratorProvider BreakIteratorProvider} implementations.
|
||||
* It must contain at least a <code>Locale</code>
|
||||
* instance equal to {@link java.util.Locale#US Locale.US}.
|
||||
*
|
||||
* @return An array of locales for which localized
|
||||
* <code>BreakIterator</code> instances are available.
|
||||
*/
|
||||
public static synchronized Locale[] getAvailableLocales()
|
||||
{
|
||||
LocaleServiceProviderPool pool =
|
||||
LocaleServiceProviderPool.getPool(BreakIteratorProvider.class);
|
||||
return pool.getAvailableLocales();
|
||||
}
|
||||
|
||||
private static final class BreakIteratorCache {
|
||||
|
||||
private BreakIterator iter;
|
||||
private Locale locale;
|
||||
|
||||
BreakIteratorCache(Locale locale, BreakIterator iter) {
|
||||
this.locale = locale;
|
||||
this.iter = (BreakIterator) iter.clone();
|
||||
}
|
||||
|
||||
Locale getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
BreakIterator createBreakInstance() {
|
||||
return (BreakIterator) iter.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
179
jdkSrc/jdk8/java/text/CalendarBuilder.java
Normal file
179
jdkSrc/jdk8/java/text/CalendarBuilder.java
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.util.Calendar;
|
||||
import static java.util.GregorianCalendar.*;
|
||||
|
||||
/**
|
||||
* {@code CalendarBuilder} keeps field-value pairs for setting
|
||||
* the calendar fields of the given {@code Calendar}. It has the
|
||||
* {@link Calendar#FIELD_COUNT FIELD_COUNT}-th field for the week year
|
||||
* support. Also {@code ISO_DAY_OF_WEEK} is used to specify
|
||||
* {@code DAY_OF_WEEK} in the ISO day of week numbering.
|
||||
*
|
||||
* <p>{@code CalendarBuilder} retains the semantic of the pseudo
|
||||
* timestamp for fields. {@code CalendarBuilder} uses a single
|
||||
* int array combining fields[] and stamp[] of {@code Calendar}.
|
||||
*
|
||||
* @author Masayoshi Okutsu
|
||||
*/
|
||||
class CalendarBuilder {
|
||||
/*
|
||||
* Pseudo time stamp constants used in java.util.Calendar
|
||||
*/
|
||||
private static final int UNSET = 0;
|
||||
private static final int COMPUTED = 1;
|
||||
private static final int MINIMUM_USER_STAMP = 2;
|
||||
|
||||
private static final int MAX_FIELD = FIELD_COUNT + 1;
|
||||
|
||||
public static final int WEEK_YEAR = FIELD_COUNT;
|
||||
public static final int ISO_DAY_OF_WEEK = 1000; // pseudo field index
|
||||
|
||||
// stamp[] (lower half) and field[] (upper half) combined
|
||||
private final int[] field;
|
||||
private int nextStamp;
|
||||
private int maxFieldIndex;
|
||||
|
||||
CalendarBuilder() {
|
||||
field = new int[MAX_FIELD * 2];
|
||||
nextStamp = MINIMUM_USER_STAMP;
|
||||
maxFieldIndex = -1;
|
||||
}
|
||||
|
||||
CalendarBuilder set(int index, int value) {
|
||||
if (index == ISO_DAY_OF_WEEK) {
|
||||
index = DAY_OF_WEEK;
|
||||
value = toCalendarDayOfWeek(value);
|
||||
}
|
||||
field[index] = nextStamp++;
|
||||
field[MAX_FIELD + index] = value;
|
||||
if (index > maxFieldIndex && index < FIELD_COUNT) {
|
||||
maxFieldIndex = index;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
CalendarBuilder addYear(int value) {
|
||||
field[MAX_FIELD + YEAR] += value;
|
||||
field[MAX_FIELD + WEEK_YEAR] += value;
|
||||
return this;
|
||||
}
|
||||
|
||||
boolean isSet(int index) {
|
||||
if (index == ISO_DAY_OF_WEEK) {
|
||||
index = DAY_OF_WEEK;
|
||||
}
|
||||
return field[index] > UNSET;
|
||||
}
|
||||
|
||||
CalendarBuilder clear(int index) {
|
||||
if (index == ISO_DAY_OF_WEEK) {
|
||||
index = DAY_OF_WEEK;
|
||||
}
|
||||
field[index] = UNSET;
|
||||
field[MAX_FIELD + index] = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
Calendar establish(Calendar cal) {
|
||||
boolean weekDate = isSet(WEEK_YEAR)
|
||||
&& field[WEEK_YEAR] > field[YEAR];
|
||||
if (weekDate && !cal.isWeekDateSupported()) {
|
||||
// Use YEAR instead
|
||||
if (!isSet(YEAR)) {
|
||||
set(YEAR, field[MAX_FIELD + WEEK_YEAR]);
|
||||
}
|
||||
weekDate = false;
|
||||
}
|
||||
|
||||
cal.clear();
|
||||
// Set the fields from the min stamp to the max stamp so that
|
||||
// the field resolution works in the Calendar.
|
||||
for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
|
||||
for (int index = 0; index <= maxFieldIndex; index++) {
|
||||
if (field[index] == stamp) {
|
||||
cal.set(index, field[MAX_FIELD + index]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (weekDate) {
|
||||
int weekOfYear = isSet(WEEK_OF_YEAR) ? field[MAX_FIELD + WEEK_OF_YEAR] : 1;
|
||||
int dayOfWeek = isSet(DAY_OF_WEEK) ?
|
||||
field[MAX_FIELD + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
|
||||
if (!isValidDayOfWeek(dayOfWeek) && cal.isLenient()) {
|
||||
if (dayOfWeek >= 8) {
|
||||
dayOfWeek--;
|
||||
weekOfYear += dayOfWeek / 7;
|
||||
dayOfWeek = (dayOfWeek % 7) + 1;
|
||||
} else {
|
||||
while (dayOfWeek <= 0) {
|
||||
dayOfWeek += 7;
|
||||
weekOfYear--;
|
||||
}
|
||||
}
|
||||
dayOfWeek = toCalendarDayOfWeek(dayOfWeek);
|
||||
}
|
||||
cal.setWeekDate(field[MAX_FIELD + WEEK_YEAR], weekOfYear, dayOfWeek);
|
||||
}
|
||||
return cal;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("CalendarBuilder:[");
|
||||
for (int i = 0; i < field.length; i++) {
|
||||
if (isSet(i)) {
|
||||
sb.append(i).append('=').append(field[MAX_FIELD + i]).append(',');
|
||||
}
|
||||
}
|
||||
int lastIndex = sb.length() - 1;
|
||||
if (sb.charAt(lastIndex) == ',') {
|
||||
sb.setLength(lastIndex);
|
||||
}
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
static int toISODayOfWeek(int calendarDayOfWeek) {
|
||||
return calendarDayOfWeek == SUNDAY ? 7 : calendarDayOfWeek - 1;
|
||||
}
|
||||
|
||||
static int toCalendarDayOfWeek(int isoDayOfWeek) {
|
||||
if (!isValidDayOfWeek(isoDayOfWeek)) {
|
||||
// adjust later for lenient mode
|
||||
return isoDayOfWeek;
|
||||
}
|
||||
return isoDayOfWeek == 7 ? SUNDAY : isoDayOfWeek + 1;
|
||||
}
|
||||
|
||||
static boolean isValidDayOfWeek(int dayOfWeek) {
|
||||
return dayOfWeek > 0 && dayOfWeek <= 7;
|
||||
}
|
||||
}
|
||||
193
jdkSrc/jdk8/java/text/CharacterIterator.java
Normal file
193
jdkSrc/jdk8/java/text/CharacterIterator.java
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation
|
||||
* is copyrighted and owned by Taligent, Inc., a wholly-owned
|
||||
* subsidiary of IBM. These materials are provided under terms
|
||||
* of a License Agreement between Taligent and Sun. This technology
|
||||
* is protected by multiple US and International patents.
|
||||
*
|
||||
* This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
|
||||
/**
|
||||
* This interface defines a protocol for bidirectional iteration over text.
|
||||
* The iterator iterates over a bounded sequence of characters. Characters
|
||||
* are indexed with values beginning with the value returned by getBeginIndex() and
|
||||
* continuing through the value returned by getEndIndex()-1.
|
||||
* <p>
|
||||
* Iterators maintain a current character index, whose valid range is from
|
||||
* getBeginIndex() to getEndIndex(); the value getEndIndex() is included to allow
|
||||
* handling of zero-length text ranges and for historical reasons.
|
||||
* The current index can be retrieved by calling getIndex() and set directly
|
||||
* by calling setIndex(), first(), and last().
|
||||
* <p>
|
||||
* The methods previous() and next() are used for iteration. They return DONE if
|
||||
* they would move outside the range from getBeginIndex() to getEndIndex() -1,
|
||||
* signaling that the iterator has reached the end of the sequence. DONE is
|
||||
* also returned by other methods to indicate that the current index is
|
||||
* outside this range.
|
||||
*
|
||||
* <P>Examples:<P>
|
||||
*
|
||||
* Traverse the text from start to finish
|
||||
* <pre>{@code
|
||||
* public void traverseForward(CharacterIterator iter) {
|
||||
* for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
|
||||
* processChar(c);
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* Traverse the text backwards, from end to start
|
||||
* <pre>{@code
|
||||
* public void traverseBackward(CharacterIterator iter) {
|
||||
* for(char c = iter.last(); c != CharacterIterator.DONE; c = iter.previous()) {
|
||||
* processChar(c);
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* Traverse both forward and backward from a given position in the text.
|
||||
* Calls to notBoundary() in this example represents some
|
||||
* additional stopping criteria.
|
||||
* <pre>{@code
|
||||
* public void traverseOut(CharacterIterator iter, int pos) {
|
||||
* for (char c = iter.setIndex(pos);
|
||||
* c != CharacterIterator.DONE && notBoundary(c);
|
||||
* c = iter.next()) {
|
||||
* }
|
||||
* int end = iter.getIndex();
|
||||
* for (char c = iter.setIndex(pos);
|
||||
* c != CharacterIterator.DONE && notBoundary(c);
|
||||
* c = iter.previous()) {
|
||||
* }
|
||||
* int start = iter.getIndex();
|
||||
* processSection(start, end);
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @see StringCharacterIterator
|
||||
* @see AttributedCharacterIterator
|
||||
*/
|
||||
|
||||
public interface CharacterIterator extends Cloneable
|
||||
{
|
||||
|
||||
/**
|
||||
* Constant that is returned when the iterator has reached either the end
|
||||
* or the beginning of the text. The value is '\\uFFFF', the "not a
|
||||
* character" value which should not occur in any valid Unicode string.
|
||||
*/
|
||||
public static final char DONE = '\uFFFF';
|
||||
|
||||
/**
|
||||
* Sets the position to getBeginIndex() and returns the character at that
|
||||
* position.
|
||||
* @return the first character in the text, or DONE if the text is empty
|
||||
* @see #getBeginIndex()
|
||||
*/
|
||||
public char first();
|
||||
|
||||
/**
|
||||
* Sets the position to getEndIndex()-1 (getEndIndex() if the text is empty)
|
||||
* and returns the character at that position.
|
||||
* @return the last character in the text, or DONE if the text is empty
|
||||
* @see #getEndIndex()
|
||||
*/
|
||||
public char last();
|
||||
|
||||
/**
|
||||
* Gets the character at the current position (as returned by getIndex()).
|
||||
* @return the character at the current position or DONE if the current
|
||||
* position is off the end of the text.
|
||||
* @see #getIndex()
|
||||
*/
|
||||
public char current();
|
||||
|
||||
/**
|
||||
* Increments the iterator's index by one and returns the character
|
||||
* at the new index. If the resulting index is greater or equal
|
||||
* to getEndIndex(), the current index is reset to getEndIndex() and
|
||||
* a value of DONE is returned.
|
||||
* @return the character at the new position or DONE if the new
|
||||
* position is off the end of the text range.
|
||||
*/
|
||||
public char next();
|
||||
|
||||
/**
|
||||
* Decrements the iterator's index by one and returns the character
|
||||
* at the new index. If the current index is getBeginIndex(), the index
|
||||
* remains at getBeginIndex() and a value of DONE is returned.
|
||||
* @return the character at the new position or DONE if the current
|
||||
* position is equal to getBeginIndex().
|
||||
*/
|
||||
public char previous();
|
||||
|
||||
/**
|
||||
* Sets the position to the specified position in the text and returns that
|
||||
* character.
|
||||
* @param position the position within the text. Valid values range from
|
||||
* getBeginIndex() to getEndIndex(). An IllegalArgumentException is thrown
|
||||
* if an invalid value is supplied.
|
||||
* @return the character at the specified position or DONE if the specified position is equal to getEndIndex()
|
||||
*/
|
||||
public char setIndex(int position);
|
||||
|
||||
/**
|
||||
* Returns the start index of the text.
|
||||
* @return the index at which the text begins.
|
||||
*/
|
||||
public int getBeginIndex();
|
||||
|
||||
/**
|
||||
* Returns the end index of the text. This index is the index of the first
|
||||
* character following the end of the text.
|
||||
* @return the index after the last character in the text
|
||||
*/
|
||||
public int getEndIndex();
|
||||
|
||||
/**
|
||||
* Returns the current index.
|
||||
* @return the current index.
|
||||
*/
|
||||
public int getIndex();
|
||||
|
||||
/**
|
||||
* Create a copy of this iterator
|
||||
* @return A copy of this
|
||||
*/
|
||||
public Object clone();
|
||||
|
||||
}
|
||||
124
jdkSrc/jdk8/java/text/CharacterIteratorFieldDelegate.java
Normal file
124
jdkSrc/jdk8/java/text/CharacterIteratorFieldDelegate.java
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package java.text;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* CharacterIteratorFieldDelegate combines the notifications from a Format
|
||||
* into a resulting <code>AttributedCharacterIterator</code>. The resulting
|
||||
* <code>AttributedCharacterIterator</code> can be retrieved by way of
|
||||
* the <code>getIterator</code> method.
|
||||
*
|
||||
*/
|
||||
class CharacterIteratorFieldDelegate implements Format.FieldDelegate {
|
||||
/**
|
||||
* Array of AttributeStrings. Whenever <code>formatted</code> is invoked
|
||||
* for a region > size, a new instance of AttributedString is added to
|
||||
* attributedStrings. Subsequent invocations of <code>formatted</code>
|
||||
* for existing regions result in invoking addAttribute on the existing
|
||||
* AttributedStrings.
|
||||
*/
|
||||
private ArrayList<AttributedString> attributedStrings;
|
||||
/**
|
||||
* Running count of the number of characters that have
|
||||
* been encountered.
|
||||
*/
|
||||
private int size;
|
||||
|
||||
|
||||
CharacterIteratorFieldDelegate() {
|
||||
attributedStrings = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void formatted(Format.Field attr, Object value, int start, int end,
|
||||
StringBuffer buffer) {
|
||||
if (start != end) {
|
||||
if (start < size) {
|
||||
// Adjust attributes of existing runs
|
||||
int index = size;
|
||||
int asIndex = attributedStrings.size() - 1;
|
||||
|
||||
while (start < index) {
|
||||
AttributedString as = attributedStrings.
|
||||
get(asIndex--);
|
||||
int newIndex = index - as.length();
|
||||
int aStart = Math.max(0, start - newIndex);
|
||||
|
||||
as.addAttribute(attr, value, aStart, Math.min(
|
||||
end - start, as.length() - aStart) +
|
||||
aStart);
|
||||
index = newIndex;
|
||||
}
|
||||
}
|
||||
if (size < start) {
|
||||
// Pad attributes
|
||||
attributedStrings.add(new AttributedString(
|
||||
buffer.substring(size, start)));
|
||||
size = start;
|
||||
}
|
||||
if (size < end) {
|
||||
// Add new string
|
||||
int aStart = Math.max(start, size);
|
||||
AttributedString string = new AttributedString(
|
||||
buffer.substring(aStart, end));
|
||||
|
||||
string.addAttribute(attr, value);
|
||||
attributedStrings.add(string);
|
||||
size = end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void formatted(int fieldID, Format.Field attr, Object value,
|
||||
int start, int end, StringBuffer buffer) {
|
||||
formatted(attr, value, start, end, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an <code>AttributedCharacterIterator</code> that can be used
|
||||
* to iterate over the resulting formatted String.
|
||||
*
|
||||
* @pararm string Result of formatting.
|
||||
*/
|
||||
public AttributedCharacterIterator getIterator(String string) {
|
||||
// Add the last AttributedCharacterIterator if necessary
|
||||
// assert(size <= string.length());
|
||||
if (string.length() > size) {
|
||||
attributedStrings.add(new AttributedString(
|
||||
string.substring(size)));
|
||||
size = string.length();
|
||||
}
|
||||
int iCount = attributedStrings.size();
|
||||
AttributedCharacterIterator iterators[] = new
|
||||
AttributedCharacterIterator[iCount];
|
||||
|
||||
for (int counter = 0; counter < iCount; counter++) {
|
||||
iterators[counter] = attributedStrings.
|
||||
get(counter).getIterator();
|
||||
}
|
||||
return new AttributedString(iterators).getIterator();
|
||||
}
|
||||
}
|
||||
640
jdkSrc/jdk8/java/text/ChoiceFormat.java
Normal file
640
jdkSrc/jdk8/java/text/ChoiceFormat.java
Normal file
@@ -0,0 +1,640 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is copyrighted
|
||||
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
|
||||
* materials are provided under terms of a License Agreement between Taligent
|
||||
* and Sun. This technology is protected by multiple US and International
|
||||
* patents. This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* A <code>ChoiceFormat</code> allows you to attach a format to a range of numbers.
|
||||
* It is generally used in a <code>MessageFormat</code> for handling plurals.
|
||||
* The choice is specified with an ascending list of doubles, where each item
|
||||
* specifies a half-open interval up to the next item:
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* X matches j if and only if limit[j] ≤ X < limit[j+1]
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
* If there is no match, then either the first or last index is used, depending
|
||||
* on whether the number (X) is too low or too high. If the limit array is not
|
||||
* in ascending order, the results of formatting will be incorrect. ChoiceFormat
|
||||
* also accepts <code>\u221E</code> as equivalent to infinity(INF).
|
||||
*
|
||||
* <p>
|
||||
* <strong>Note:</strong>
|
||||
* <code>ChoiceFormat</code> differs from the other <code>Format</code>
|
||||
* classes in that you create a <code>ChoiceFormat</code> object with a
|
||||
* constructor (not with a <code>getInstance</code> style factory
|
||||
* method). The factory methods aren't necessary because <code>ChoiceFormat</code>
|
||||
* doesn't require any complex setup for a given locale. In fact,
|
||||
* <code>ChoiceFormat</code> doesn't implement any locale specific behavior.
|
||||
*
|
||||
* <p>
|
||||
* When creating a <code>ChoiceFormat</code>, you must specify an array of formats
|
||||
* and an array of limits. The length of these arrays must be the same.
|
||||
* For example,
|
||||
* <ul>
|
||||
* <li>
|
||||
* <em>limits</em> = {1,2,3,4,5,6,7}<br>
|
||||
* <em>formats</em> = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"}
|
||||
* <li>
|
||||
* <em>limits</em> = {0, 1, ChoiceFormat.nextDouble(1)}<br>
|
||||
* <em>formats</em> = {"no files", "one file", "many files"}<br>
|
||||
* (<code>nextDouble</code> can be used to get the next higher double, to
|
||||
* make the half-open interval.)
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Here is a simple example that shows formatting and parsing:
|
||||
* <blockquote>
|
||||
* <pre>{@code
|
||||
* double[] limits = {1,2,3,4,5,6,7};
|
||||
* String[] dayOfWeekNames = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"};
|
||||
* ChoiceFormat form = new ChoiceFormat(limits, dayOfWeekNames);
|
||||
* ParsePosition status = new ParsePosition(0);
|
||||
* for (double i = 0.0; i <= 8.0; ++i) {
|
||||
* status.setIndex(0);
|
||||
* System.out.println(i + " -> " + form.format(i) + " -> "
|
||||
* + form.parse(form.format(i),status));
|
||||
* }
|
||||
* }</pre>
|
||||
* </blockquote>
|
||||
* Here is a more complex example, with a pattern format:
|
||||
* <blockquote>
|
||||
* <pre>{@code
|
||||
* double[] filelimits = {0,1,2};
|
||||
* String[] filepart = {"are no files","is one file","are {2} files"};
|
||||
* ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
|
||||
* Format[] testFormats = {fileform, null, NumberFormat.getInstance()};
|
||||
* MessageFormat pattform = new MessageFormat("There {0} on {1}");
|
||||
* pattform.setFormats(testFormats);
|
||||
* Object[] testArgs = {null, "ADisk", null};
|
||||
* for (int i = 0; i < 4; ++i) {
|
||||
* testArgs[0] = new Integer(i);
|
||||
* testArgs[2] = testArgs[0];
|
||||
* System.out.println(pattform.format(testArgs));
|
||||
* }
|
||||
* }</pre>
|
||||
* </blockquote>
|
||||
* <p>
|
||||
* Specifying a pattern for ChoiceFormat objects is fairly straightforward.
|
||||
* For example:
|
||||
* <blockquote>
|
||||
* <pre>{@code
|
||||
* ChoiceFormat fmt = new ChoiceFormat(
|
||||
* "-1#is negative| 0#is zero or fraction | 1#is one |1.0<is 1+ |2#is two |2<is more than 2.");
|
||||
* System.out.println("Formatter Pattern : " + fmt.toPattern());
|
||||
*
|
||||
* System.out.println("Format with -INF : " + fmt.format(Double.NEGATIVE_INFINITY));
|
||||
* System.out.println("Format with -1.0 : " + fmt.format(-1.0));
|
||||
* System.out.println("Format with 0 : " + fmt.format(0));
|
||||
* System.out.println("Format with 0.9 : " + fmt.format(0.9));
|
||||
* System.out.println("Format with 1.0 : " + fmt.format(1));
|
||||
* System.out.println("Format with 1.5 : " + fmt.format(1.5));
|
||||
* System.out.println("Format with 2 : " + fmt.format(2));
|
||||
* System.out.println("Format with 2.1 : " + fmt.format(2.1));
|
||||
* System.out.println("Format with NaN : " + fmt.format(Double.NaN));
|
||||
* System.out.println("Format with +INF : " + fmt.format(Double.POSITIVE_INFINITY));
|
||||
* }</pre>
|
||||
* </blockquote>
|
||||
* And the output result would be like the following:
|
||||
* <blockquote>
|
||||
* <pre>{@code
|
||||
* Format with -INF : is negative
|
||||
* Format with -1.0 : is negative
|
||||
* Format with 0 : is zero or fraction
|
||||
* Format with 0.9 : is zero or fraction
|
||||
* Format with 1.0 : is one
|
||||
* Format with 1.5 : is 1+
|
||||
* Format with 2 : is two
|
||||
* Format with 2.1 : is more than 2.
|
||||
* Format with NaN : is negative
|
||||
* Format with +INF : is more than 2.
|
||||
* }</pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* <h3><a name="synchronization">Synchronization</a></h3>
|
||||
*
|
||||
* <p>
|
||||
* Choice formats are not synchronized.
|
||||
* It is recommended to create separate format instances for each thread.
|
||||
* If multiple threads access a format concurrently, it must be synchronized
|
||||
* externally.
|
||||
*
|
||||
*
|
||||
* @see DecimalFormat
|
||||
* @see MessageFormat
|
||||
* @author Mark Davis
|
||||
*/
|
||||
public class ChoiceFormat extends NumberFormat {
|
||||
|
||||
// Proclaim serial compatibility with 1.1 FCS
|
||||
private static final long serialVersionUID = 1795184449645032964L;
|
||||
|
||||
/**
|
||||
* Sets the pattern.
|
||||
* @param newPattern See the class description.
|
||||
*/
|
||||
public void applyPattern(String newPattern) {
|
||||
StringBuffer[] segments = new StringBuffer[2];
|
||||
for (int i = 0; i < segments.length; ++i) {
|
||||
segments[i] = new StringBuffer();
|
||||
}
|
||||
double[] newChoiceLimits = new double[30];
|
||||
String[] newChoiceFormats = new String[30];
|
||||
int count = 0;
|
||||
int part = 0;
|
||||
double startValue = 0;
|
||||
double oldStartValue = Double.NaN;
|
||||
boolean inQuote = false;
|
||||
for (int i = 0; i < newPattern.length(); ++i) {
|
||||
char ch = newPattern.charAt(i);
|
||||
if (ch=='\'') {
|
||||
// Check for "''" indicating a literal quote
|
||||
if ((i+1)<newPattern.length() && newPattern.charAt(i+1)==ch) {
|
||||
segments[part].append(ch);
|
||||
++i;
|
||||
} else {
|
||||
inQuote = !inQuote;
|
||||
}
|
||||
} else if (inQuote) {
|
||||
segments[part].append(ch);
|
||||
} else if (ch == '<' || ch == '#' || ch == '\u2264') {
|
||||
if (segments[0].length() == 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
try {
|
||||
String tempBuffer = segments[0].toString();
|
||||
if (tempBuffer.equals("\u221E")) {
|
||||
startValue = Double.POSITIVE_INFINITY;
|
||||
} else if (tempBuffer.equals("-\u221E")) {
|
||||
startValue = Double.NEGATIVE_INFINITY;
|
||||
} else {
|
||||
startValue = Double.valueOf(segments[0].toString()).doubleValue();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (ch == '<' && startValue != Double.POSITIVE_INFINITY &&
|
||||
startValue != Double.NEGATIVE_INFINITY) {
|
||||
startValue = nextDouble(startValue);
|
||||
}
|
||||
if (startValue <= oldStartValue) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
segments[0].setLength(0);
|
||||
part = 1;
|
||||
} else if (ch == '|') {
|
||||
if (count == newChoiceLimits.length) {
|
||||
newChoiceLimits = doubleArraySize(newChoiceLimits);
|
||||
newChoiceFormats = doubleArraySize(newChoiceFormats);
|
||||
}
|
||||
newChoiceLimits[count] = startValue;
|
||||
newChoiceFormats[count] = segments[1].toString();
|
||||
++count;
|
||||
oldStartValue = startValue;
|
||||
segments[1].setLength(0);
|
||||
part = 0;
|
||||
} else {
|
||||
segments[part].append(ch);
|
||||
}
|
||||
}
|
||||
// clean up last one
|
||||
if (part == 1) {
|
||||
if (count == newChoiceLimits.length) {
|
||||
newChoiceLimits = doubleArraySize(newChoiceLimits);
|
||||
newChoiceFormats = doubleArraySize(newChoiceFormats);
|
||||
}
|
||||
newChoiceLimits[count] = startValue;
|
||||
newChoiceFormats[count] = segments[1].toString();
|
||||
++count;
|
||||
}
|
||||
choiceLimits = new double[count];
|
||||
System.arraycopy(newChoiceLimits, 0, choiceLimits, 0, count);
|
||||
choiceFormats = new String[count];
|
||||
System.arraycopy(newChoiceFormats, 0, choiceFormats, 0, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pattern.
|
||||
*
|
||||
* @return the pattern string
|
||||
*/
|
||||
public String toPattern() {
|
||||
StringBuffer result = new StringBuffer();
|
||||
for (int i = 0; i < choiceLimits.length; ++i) {
|
||||
if (i != 0) {
|
||||
result.append('|');
|
||||
}
|
||||
// choose based upon which has less precision
|
||||
// approximate that by choosing the closest one to an integer.
|
||||
// could do better, but it's not worth it.
|
||||
double less = previousDouble(choiceLimits[i]);
|
||||
double tryLessOrEqual = Math.abs(Math.IEEEremainder(choiceLimits[i], 1.0d));
|
||||
double tryLess = Math.abs(Math.IEEEremainder(less, 1.0d));
|
||||
|
||||
if (tryLessOrEqual < tryLess) {
|
||||
result.append(""+choiceLimits[i]);
|
||||
result.append('#');
|
||||
} else {
|
||||
if (choiceLimits[i] == Double.POSITIVE_INFINITY) {
|
||||
result.append("\u221E");
|
||||
} else if (choiceLimits[i] == Double.NEGATIVE_INFINITY) {
|
||||
result.append("-\u221E");
|
||||
} else {
|
||||
result.append(""+less);
|
||||
}
|
||||
result.append('<');
|
||||
}
|
||||
// Append choiceFormats[i], using quotes if there are special characters.
|
||||
// Single quotes themselves must be escaped in either case.
|
||||
String text = choiceFormats[i];
|
||||
boolean needQuote = text.indexOf('<') >= 0
|
||||
|| text.indexOf('#') >= 0
|
||||
|| text.indexOf('\u2264') >= 0
|
||||
|| text.indexOf('|') >= 0;
|
||||
if (needQuote) result.append('\'');
|
||||
if (text.indexOf('\'') < 0) result.append(text);
|
||||
else {
|
||||
for (int j=0; j<text.length(); ++j) {
|
||||
char c = text.charAt(j);
|
||||
result.append(c);
|
||||
if (c == '\'') result.append(c);
|
||||
}
|
||||
}
|
||||
if (needQuote) result.append('\'');
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs with limits and corresponding formats based on the pattern.
|
||||
*
|
||||
* @param newPattern the new pattern string
|
||||
* @see #applyPattern
|
||||
*/
|
||||
public ChoiceFormat(String newPattern) {
|
||||
applyPattern(newPattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs with the limits and the corresponding formats.
|
||||
*
|
||||
* @param limits limits in ascending order
|
||||
* @param formats corresponding format strings
|
||||
* @see #setChoices
|
||||
*/
|
||||
public ChoiceFormat(double[] limits, String[] formats) {
|
||||
setChoices(limits, formats);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the choices to be used in formatting.
|
||||
* @param limits contains the top value that you want
|
||||
* parsed with that format, and should be in ascending sorted order. When
|
||||
* formatting X, the choice will be the i, where
|
||||
* limit[i] ≤ X {@literal <} limit[i+1].
|
||||
* If the limit array is not in ascending order, the results of formatting
|
||||
* will be incorrect.
|
||||
* @param formats are the formats you want to use for each limit.
|
||||
* They can be either Format objects or Strings.
|
||||
* When formatting with object Y,
|
||||
* if the object is a NumberFormat, then ((NumberFormat) Y).format(X)
|
||||
* is called. Otherwise Y.toString() is called.
|
||||
*/
|
||||
public void setChoices(double[] limits, String formats[]) {
|
||||
if (limits.length != formats.length) {
|
||||
throw new IllegalArgumentException(
|
||||
"Array and limit arrays must be of the same length.");
|
||||
}
|
||||
choiceLimits = Arrays.copyOf(limits, limits.length);
|
||||
choiceFormats = Arrays.copyOf(formats, formats.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the limits passed in the constructor.
|
||||
* @return the limits.
|
||||
*/
|
||||
public double[] getLimits() {
|
||||
double[] newLimits = Arrays.copyOf(choiceLimits, choiceLimits.length);
|
||||
return newLimits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formats passed in the constructor.
|
||||
* @return the formats.
|
||||
*/
|
||||
public Object[] getFormats() {
|
||||
Object[] newFormats = Arrays.copyOf(choiceFormats, choiceFormats.length);
|
||||
return newFormats;
|
||||
}
|
||||
|
||||
// Overrides
|
||||
|
||||
/**
|
||||
* Specialization of format. This method really calls
|
||||
* <code>format(double, StringBuffer, FieldPosition)</code>
|
||||
* thus the range of longs that are supported is only equal to
|
||||
* the range that can be stored by double. This will never be
|
||||
* a practical limitation.
|
||||
*/
|
||||
public StringBuffer format(long number, StringBuffer toAppendTo,
|
||||
FieldPosition status) {
|
||||
return format((double)number, toAppendTo, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns pattern with formatted double.
|
||||
* @param number number to be formatted and substituted.
|
||||
* @param toAppendTo where text is appended.
|
||||
* @param status ignore no useful status is returned.
|
||||
*/
|
||||
public StringBuffer format(double number, StringBuffer toAppendTo,
|
||||
FieldPosition status) {
|
||||
// find the number
|
||||
int i;
|
||||
for (i = 0; i < choiceLimits.length; ++i) {
|
||||
if (!(number >= choiceLimits[i])) {
|
||||
// same as number < choiceLimits, except catchs NaN
|
||||
break;
|
||||
}
|
||||
}
|
||||
--i;
|
||||
if (i < 0) i = 0;
|
||||
// return either a formatted number, or a string
|
||||
return toAppendTo.append(choiceFormats[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a Number from the input text.
|
||||
* @param text the source text.
|
||||
* @param status an input-output parameter. On input, the
|
||||
* status.index field indicates the first character of the
|
||||
* source text that should be parsed. On exit, if no error
|
||||
* occurred, status.index is set to the first unparsed character
|
||||
* in the source text. On exit, if an error did occur,
|
||||
* status.index is unchanged and status.errorIndex is set to the
|
||||
* first index of the character that caused the parse to fail.
|
||||
* @return A Number representing the value of the number parsed.
|
||||
*/
|
||||
public Number parse(String text, ParsePosition status) {
|
||||
// find the best number (defined as the one with the longest parse)
|
||||
int start = status.index;
|
||||
int furthest = start;
|
||||
double bestNumber = Double.NaN;
|
||||
double tempNumber = 0.0;
|
||||
for (int i = 0; i < choiceFormats.length; ++i) {
|
||||
String tempString = choiceFormats[i];
|
||||
if (text.regionMatches(start, tempString, 0, tempString.length())) {
|
||||
status.index = start + tempString.length();
|
||||
tempNumber = choiceLimits[i];
|
||||
if (status.index > furthest) {
|
||||
furthest = status.index;
|
||||
bestNumber = tempNumber;
|
||||
if (furthest == text.length()) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
status.index = furthest;
|
||||
if (status.index == start) {
|
||||
status.errorIndex = furthest;
|
||||
}
|
||||
return new Double(bestNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the least double greater than {@code d}.
|
||||
* If {@code NaN}, returns same value.
|
||||
* <p>Used to make half-open intervals.
|
||||
*
|
||||
* @param d the reference value
|
||||
* @return the least double value greather than {@code d}
|
||||
* @see #previousDouble
|
||||
*/
|
||||
public static final double nextDouble (double d) {
|
||||
return nextDouble(d,true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the greatest double less than {@code d}.
|
||||
* If {@code NaN}, returns same value.
|
||||
*
|
||||
* @param d the reference value
|
||||
* @return the greatest double value less than {@code d}
|
||||
* @see #nextDouble
|
||||
*/
|
||||
public static final double previousDouble (double d) {
|
||||
return nextDouble(d,false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides Cloneable
|
||||
*/
|
||||
public Object clone()
|
||||
{
|
||||
ChoiceFormat other = (ChoiceFormat) super.clone();
|
||||
// for primitives or immutables, shallow clone is enough
|
||||
other.choiceLimits = choiceLimits.clone();
|
||||
other.choiceFormats = choiceFormats.clone();
|
||||
return other;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a hash code for the message format object.
|
||||
*/
|
||||
public int hashCode() {
|
||||
int result = choiceLimits.length;
|
||||
if (choiceFormats.length > 0) {
|
||||
// enough for reasonable distribution
|
||||
result ^= choiceFormats[choiceFormats.length-1].hashCode();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Equality comparision between two
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) return false;
|
||||
if (this == obj) // quick check
|
||||
return true;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
ChoiceFormat other = (ChoiceFormat) obj;
|
||||
return (Arrays.equals(choiceLimits, other.choiceLimits)
|
||||
&& Arrays.equals(choiceFormats, other.choiceFormats));
|
||||
}
|
||||
|
||||
/**
|
||||
* After reading an object from the input stream, do a simple verification
|
||||
* to maintain class invariants.
|
||||
* @throws InvalidObjectException if the objects read from the stream is invalid.
|
||||
*/
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
in.defaultReadObject();
|
||||
if (choiceLimits.length != choiceFormats.length) {
|
||||
throw new InvalidObjectException(
|
||||
"limits and format arrays of different length.");
|
||||
}
|
||||
}
|
||||
|
||||
// ===============privates===========================
|
||||
|
||||
/**
|
||||
* A list of lower bounds for the choices. The formatter will return
|
||||
* <code>choiceFormats[i]</code> if the number being formatted is greater than or equal to
|
||||
* <code>choiceLimits[i]</code> and less than <code>choiceLimits[i+1]</code>.
|
||||
* @serial
|
||||
*/
|
||||
private double[] choiceLimits;
|
||||
|
||||
/**
|
||||
* A list of choice strings. The formatter will return
|
||||
* <code>choiceFormats[i]</code> if the number being formatted is greater than or equal to
|
||||
* <code>choiceLimits[i]</code> and less than <code>choiceLimits[i+1]</code>.
|
||||
* @serial
|
||||
*/
|
||||
private String[] choiceFormats;
|
||||
|
||||
/*
|
||||
static final long SIGN = 0x8000000000000000L;
|
||||
static final long EXPONENT = 0x7FF0000000000000L;
|
||||
static final long SIGNIFICAND = 0x000FFFFFFFFFFFFFL;
|
||||
|
||||
private static double nextDouble (double d, boolean positive) {
|
||||
if (Double.isNaN(d) || Double.isInfinite(d)) {
|
||||
return d;
|
||||
}
|
||||
long bits = Double.doubleToLongBits(d);
|
||||
long significand = bits & SIGNIFICAND;
|
||||
if (bits < 0) {
|
||||
significand |= (SIGN | EXPONENT);
|
||||
}
|
||||
long exponent = bits & EXPONENT;
|
||||
if (positive) {
|
||||
significand += 1;
|
||||
// FIXME fix overflow & underflow
|
||||
} else {
|
||||
significand -= 1;
|
||||
// FIXME fix overflow & underflow
|
||||
}
|
||||
bits = exponent | (significand & ~EXPONENT);
|
||||
return Double.longBitsToDouble(bits);
|
||||
}
|
||||
*/
|
||||
|
||||
static final long SIGN = 0x8000000000000000L;
|
||||
static final long EXPONENT = 0x7FF0000000000000L;
|
||||
static final long POSITIVEINFINITY = 0x7FF0000000000000L;
|
||||
|
||||
/**
|
||||
* Finds the least double greater than {@code d} (if {@code positive} is
|
||||
* {@code true}), or the greatest double less than {@code d} (if
|
||||
* {@code positive} is {@code false}).
|
||||
* If {@code NaN}, returns same value.
|
||||
*
|
||||
* Does not affect floating-point flags,
|
||||
* provided these member functions do not:
|
||||
* Double.longBitsToDouble(long)
|
||||
* Double.doubleToLongBits(double)
|
||||
* Double.isNaN(double)
|
||||
*
|
||||
* @param d the reference value
|
||||
* @param positive {@code true} if the least double is desired;
|
||||
* {@code false} otherwise
|
||||
* @return the least or greater double value
|
||||
*/
|
||||
public static double nextDouble (double d, boolean positive) {
|
||||
|
||||
/* filter out NaN's */
|
||||
if (Double.isNaN(d)) {
|
||||
return d;
|
||||
}
|
||||
|
||||
/* zero's are also a special case */
|
||||
if (d == 0.0) {
|
||||
double smallestPositiveDouble = Double.longBitsToDouble(1L);
|
||||
if (positive) {
|
||||
return smallestPositiveDouble;
|
||||
} else {
|
||||
return -smallestPositiveDouble;
|
||||
}
|
||||
}
|
||||
|
||||
/* if entering here, d is a nonzero value */
|
||||
|
||||
/* hold all bits in a long for later use */
|
||||
long bits = Double.doubleToLongBits(d);
|
||||
|
||||
/* strip off the sign bit */
|
||||
long magnitude = bits & ~SIGN;
|
||||
|
||||
/* if next double away from zero, increase magnitude */
|
||||
if ((bits > 0) == positive) {
|
||||
if (magnitude != POSITIVEINFINITY) {
|
||||
magnitude += 1;
|
||||
}
|
||||
}
|
||||
/* else decrease magnitude */
|
||||
else {
|
||||
magnitude -= 1;
|
||||
}
|
||||
|
||||
/* restore sign bit and return */
|
||||
long signbit = bits & SIGN;
|
||||
return Double.longBitsToDouble (magnitude | signbit);
|
||||
}
|
||||
|
||||
private static double[] doubleArraySize(double[] array) {
|
||||
int oldSize = array.length;
|
||||
double[] newArray = new double[oldSize * 2];
|
||||
System.arraycopy(array, 0, newArray, 0, oldSize);
|
||||
return newArray;
|
||||
}
|
||||
|
||||
private String[] doubleArraySize(String[] array) {
|
||||
int oldSize = array.length;
|
||||
String[] newArray = new String[oldSize * 2];
|
||||
System.arraycopy(array, 0, newArray, 0, oldSize);
|
||||
return newArray;
|
||||
}
|
||||
|
||||
}
|
||||
782
jdkSrc/jdk8/java/text/CollationElementIterator.java
Normal file
782
jdkSrc/jdk8/java/text/CollationElementIterator.java
Normal file
@@ -0,0 +1,782 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is copyrighted
|
||||
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
|
||||
* materials are provided under terms of a License Agreement between Taligent
|
||||
* and Sun. This technology is protected by multiple US and International
|
||||
* patents. This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.lang.Character;
|
||||
import java.util.Vector;
|
||||
import sun.text.CollatorUtilities;
|
||||
import sun.text.normalizer.NormalizerBase;
|
||||
|
||||
/**
|
||||
* The <code>CollationElementIterator</code> class is used as an iterator
|
||||
* to walk through each character of an international string. Use the iterator
|
||||
* to return the ordering priority of the positioned character. The ordering
|
||||
* priority of a character, which we refer to as a key, defines how a character
|
||||
* is collated in the given collation object.
|
||||
*
|
||||
* <p>
|
||||
* For example, consider the following in Spanish:
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* "ca" → the first key is key('c') and second key is key('a').
|
||||
* "cha" → the first key is key('ch') and second key is key('a').
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
* And in German,
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* "\u00e4b" → the first key is key('a'), the second key is key('e'), and
|
||||
* the third key is key('b').
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
* The key of a character is an integer composed of primary order(short),
|
||||
* secondary order(byte), and tertiary order(byte). Java strictly defines
|
||||
* the size and signedness of its primitive data types. Therefore, the static
|
||||
* functions <code>primaryOrder</code>, <code>secondaryOrder</code>, and
|
||||
* <code>tertiaryOrder</code> return <code>int</code>, <code>short</code>,
|
||||
* and <code>short</code> respectively to ensure the correctness of the key
|
||||
* value.
|
||||
*
|
||||
* <p>
|
||||
* Example of the iterator usage,
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
*
|
||||
* String testString = "This is a test";
|
||||
* Collator col = Collator.getInstance();
|
||||
* if (col instanceof RuleBasedCollator) {
|
||||
* RuleBasedCollator ruleBasedCollator = (RuleBasedCollator)col;
|
||||
* CollationElementIterator collationElementIterator = ruleBasedCollator.getCollationElementIterator(testString);
|
||||
* int primaryOrder = CollationElementIterator.primaryOrder(collationElementIterator.next());
|
||||
* :
|
||||
* }
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* <p>
|
||||
* <code>CollationElementIterator.next</code> returns the collation order
|
||||
* of the next character. A collation order consists of primary order,
|
||||
* secondary order and tertiary order. The data type of the collation
|
||||
* order is <strong>int</strong>. The first 16 bits of a collation order
|
||||
* is its primary order; the next 8 bits is the secondary order and the
|
||||
* last 8 bits is the tertiary order.
|
||||
*
|
||||
* <p><b>Note:</b> <code>CollationElementIterator</code> is a part of
|
||||
* <code>RuleBasedCollator</code> implementation. It is only usable
|
||||
* with <code>RuleBasedCollator</code> instances.
|
||||
*
|
||||
* @see Collator
|
||||
* @see RuleBasedCollator
|
||||
* @author Helena Shih, Laura Werner, Richard Gillam
|
||||
*/
|
||||
public final class CollationElementIterator
|
||||
{
|
||||
/**
|
||||
* Null order which indicates the end of string is reached by the
|
||||
* cursor.
|
||||
*/
|
||||
public final static int NULLORDER = 0xffffffff;
|
||||
|
||||
/**
|
||||
* CollationElementIterator constructor. This takes the source string and
|
||||
* the collation object. The cursor will walk thru the source string based
|
||||
* on the predefined collation rules. If the source string is empty,
|
||||
* NULLORDER will be returned on the calls to next().
|
||||
* @param sourceText the source string.
|
||||
* @param owner the collation object.
|
||||
*/
|
||||
CollationElementIterator(String sourceText, RuleBasedCollator owner) {
|
||||
this.owner = owner;
|
||||
ordering = owner.getTables();
|
||||
if ( sourceText.length() != 0 ) {
|
||||
NormalizerBase.Mode mode =
|
||||
CollatorUtilities.toNormalizerMode(owner.getDecomposition());
|
||||
text = new NormalizerBase(sourceText, mode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CollationElementIterator constructor. This takes the source string and
|
||||
* the collation object. The cursor will walk thru the source string based
|
||||
* on the predefined collation rules. If the source string is empty,
|
||||
* NULLORDER will be returned on the calls to next().
|
||||
* @param sourceText the source string.
|
||||
* @param owner the collation object.
|
||||
*/
|
||||
CollationElementIterator(CharacterIterator sourceText, RuleBasedCollator owner) {
|
||||
this.owner = owner;
|
||||
ordering = owner.getTables();
|
||||
NormalizerBase.Mode mode =
|
||||
CollatorUtilities.toNormalizerMode(owner.getDecomposition());
|
||||
text = new NormalizerBase(sourceText, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the cursor to the beginning of the string. The next call
|
||||
* to next() will return the first collation element in the string.
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
if (text != null) {
|
||||
text.reset();
|
||||
NormalizerBase.Mode mode =
|
||||
CollatorUtilities.toNormalizerMode(owner.getDecomposition());
|
||||
text.setMode(mode);
|
||||
}
|
||||
buffer = null;
|
||||
expIndex = 0;
|
||||
swapOrder = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next collation element in the string. <p>This iterator iterates
|
||||
* over a sequence of collation elements that were built from the string.
|
||||
* Because there isn't necessarily a one-to-one mapping from characters to
|
||||
* collation elements, this doesn't mean the same thing as "return the
|
||||
* collation element [or ordering priority] of the next character in the
|
||||
* string".</p>
|
||||
* <p>This function returns the collation element that the iterator is currently
|
||||
* pointing to and then updates the internal pointer to point to the next element.
|
||||
* previous() updates the pointer first and then returns the element. This
|
||||
* means that when you change direction while iterating (i.e., call next() and
|
||||
* then call previous(), or call previous() and then call next()), you'll get
|
||||
* back the same element twice.</p>
|
||||
*
|
||||
* @return the next collation element
|
||||
*/
|
||||
public int next()
|
||||
{
|
||||
if (text == null) {
|
||||
return NULLORDER;
|
||||
}
|
||||
NormalizerBase.Mode textMode = text.getMode();
|
||||
// convert the owner's mode to something the Normalizer understands
|
||||
NormalizerBase.Mode ownerMode =
|
||||
CollatorUtilities.toNormalizerMode(owner.getDecomposition());
|
||||
if (textMode != ownerMode) {
|
||||
text.setMode(ownerMode);
|
||||
}
|
||||
|
||||
// if buffer contains any decomposed char values
|
||||
// return their strength orders before continuing in
|
||||
// the Normalizer's CharacterIterator.
|
||||
if (buffer != null) {
|
||||
if (expIndex < buffer.length) {
|
||||
return strengthOrder(buffer[expIndex++]);
|
||||
} else {
|
||||
buffer = null;
|
||||
expIndex = 0;
|
||||
}
|
||||
} else if (swapOrder != 0) {
|
||||
if (Character.isSupplementaryCodePoint(swapOrder)) {
|
||||
char[] chars = Character.toChars(swapOrder);
|
||||
swapOrder = chars[1];
|
||||
return chars[0] << 16;
|
||||
}
|
||||
int order = swapOrder << 16;
|
||||
swapOrder = 0;
|
||||
return order;
|
||||
}
|
||||
int ch = text.next();
|
||||
|
||||
// are we at the end of Normalizer's text?
|
||||
if (ch == NormalizerBase.DONE) {
|
||||
return NULLORDER;
|
||||
}
|
||||
|
||||
int value = ordering.getUnicodeOrder(ch);
|
||||
if (value == RuleBasedCollator.UNMAPPED) {
|
||||
swapOrder = ch;
|
||||
return UNMAPPEDCHARVALUE;
|
||||
}
|
||||
else if (value >= RuleBasedCollator.CONTRACTCHARINDEX) {
|
||||
value = nextContractChar(ch);
|
||||
}
|
||||
if (value >= RuleBasedCollator.EXPANDCHARINDEX) {
|
||||
buffer = ordering.getExpandValueList(value);
|
||||
expIndex = 0;
|
||||
value = buffer[expIndex++];
|
||||
}
|
||||
|
||||
if (ordering.isSEAsianSwapping()) {
|
||||
int consonant;
|
||||
if (isThaiPreVowel(ch)) {
|
||||
consonant = text.next();
|
||||
if (isThaiBaseConsonant(consonant)) {
|
||||
buffer = makeReorderedBuffer(consonant, value, buffer, true);
|
||||
value = buffer[0];
|
||||
expIndex = 1;
|
||||
} else if (consonant != NormalizerBase.DONE) {
|
||||
text.previous();
|
||||
}
|
||||
}
|
||||
if (isLaoPreVowel(ch)) {
|
||||
consonant = text.next();
|
||||
if (isLaoBaseConsonant(consonant)) {
|
||||
buffer = makeReorderedBuffer(consonant, value, buffer, true);
|
||||
value = buffer[0];
|
||||
expIndex = 1;
|
||||
} else if (consonant != NormalizerBase.DONE) {
|
||||
text.previous();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return strengthOrder(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the previous collation element in the string. <p>This iterator iterates
|
||||
* over a sequence of collation elements that were built from the string.
|
||||
* Because there isn't necessarily a one-to-one mapping from characters to
|
||||
* collation elements, this doesn't mean the same thing as "return the
|
||||
* collation element [or ordering priority] of the previous character in the
|
||||
* string".</p>
|
||||
* <p>This function updates the iterator's internal pointer to point to the
|
||||
* collation element preceding the one it's currently pointing to and then
|
||||
* returns that element, while next() returns the current element and then
|
||||
* updates the pointer. This means that when you change direction while
|
||||
* iterating (i.e., call next() and then call previous(), or call previous()
|
||||
* and then call next()), you'll get back the same element twice.</p>
|
||||
*
|
||||
* @return the previous collation element
|
||||
* @since 1.2
|
||||
*/
|
||||
public int previous()
|
||||
{
|
||||
if (text == null) {
|
||||
return NULLORDER;
|
||||
}
|
||||
NormalizerBase.Mode textMode = text.getMode();
|
||||
// convert the owner's mode to something the Normalizer understands
|
||||
NormalizerBase.Mode ownerMode =
|
||||
CollatorUtilities.toNormalizerMode(owner.getDecomposition());
|
||||
if (textMode != ownerMode) {
|
||||
text.setMode(ownerMode);
|
||||
}
|
||||
if (buffer != null) {
|
||||
if (expIndex > 0) {
|
||||
return strengthOrder(buffer[--expIndex]);
|
||||
} else {
|
||||
buffer = null;
|
||||
expIndex = 0;
|
||||
}
|
||||
} else if (swapOrder != 0) {
|
||||
if (Character.isSupplementaryCodePoint(swapOrder)) {
|
||||
char[] chars = Character.toChars(swapOrder);
|
||||
swapOrder = chars[1];
|
||||
return chars[0] << 16;
|
||||
}
|
||||
int order = swapOrder << 16;
|
||||
swapOrder = 0;
|
||||
return order;
|
||||
}
|
||||
int ch = text.previous();
|
||||
if (ch == NormalizerBase.DONE) {
|
||||
return NULLORDER;
|
||||
}
|
||||
|
||||
int value = ordering.getUnicodeOrder(ch);
|
||||
|
||||
if (value == RuleBasedCollator.UNMAPPED) {
|
||||
swapOrder = UNMAPPEDCHARVALUE;
|
||||
return ch;
|
||||
} else if (value >= RuleBasedCollator.CONTRACTCHARINDEX) {
|
||||
value = prevContractChar(ch);
|
||||
}
|
||||
if (value >= RuleBasedCollator.EXPANDCHARINDEX) {
|
||||
buffer = ordering.getExpandValueList(value);
|
||||
expIndex = buffer.length;
|
||||
value = buffer[--expIndex];
|
||||
}
|
||||
|
||||
if (ordering.isSEAsianSwapping()) {
|
||||
int vowel;
|
||||
if (isThaiBaseConsonant(ch)) {
|
||||
vowel = text.previous();
|
||||
if (isThaiPreVowel(vowel)) {
|
||||
buffer = makeReorderedBuffer(vowel, value, buffer, false);
|
||||
expIndex = buffer.length - 1;
|
||||
value = buffer[expIndex];
|
||||
} else {
|
||||
text.next();
|
||||
}
|
||||
}
|
||||
if (isLaoBaseConsonant(ch)) {
|
||||
vowel = text.previous();
|
||||
if (isLaoPreVowel(vowel)) {
|
||||
buffer = makeReorderedBuffer(vowel, value, buffer, false);
|
||||
expIndex = buffer.length - 1;
|
||||
value = buffer[expIndex];
|
||||
} else {
|
||||
text.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return strengthOrder(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the primary component of a collation element.
|
||||
* @param order the collation element
|
||||
* @return the element's primary component
|
||||
*/
|
||||
public final static int primaryOrder(int order)
|
||||
{
|
||||
order &= RBCollationTables.PRIMARYORDERMASK;
|
||||
return (order >>> RBCollationTables.PRIMARYORDERSHIFT);
|
||||
}
|
||||
/**
|
||||
* Return the secondary component of a collation element.
|
||||
* @param order the collation element
|
||||
* @return the element's secondary component
|
||||
*/
|
||||
public final static short secondaryOrder(int order)
|
||||
{
|
||||
order = order & RBCollationTables.SECONDARYORDERMASK;
|
||||
return ((short)(order >> RBCollationTables.SECONDARYORDERSHIFT));
|
||||
}
|
||||
/**
|
||||
* Return the tertiary component of a collation element.
|
||||
* @param order the collation element
|
||||
* @return the element's tertiary component
|
||||
*/
|
||||
public final static short tertiaryOrder(int order)
|
||||
{
|
||||
return ((short)(order &= RBCollationTables.TERTIARYORDERMASK));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the comparison order in the desired strength. Ignore the other
|
||||
* differences.
|
||||
* @param order The order value
|
||||
*/
|
||||
final int strengthOrder(int order)
|
||||
{
|
||||
int s = owner.getStrength();
|
||||
if (s == Collator.PRIMARY)
|
||||
{
|
||||
order &= RBCollationTables.PRIMARYDIFFERENCEONLY;
|
||||
} else if (s == Collator.SECONDARY)
|
||||
{
|
||||
order &= RBCollationTables.SECONDARYDIFFERENCEONLY;
|
||||
}
|
||||
return order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the iterator to point to the collation element corresponding to
|
||||
* the specified character (the parameter is a CHARACTER offset in the
|
||||
* original string, not an offset into its corresponding sequence of
|
||||
* collation elements). The value returned by the next call to next()
|
||||
* will be the collation element corresponding to the specified position
|
||||
* in the text. If that position is in the middle of a contracting
|
||||
* character sequence, the result of the next call to next() is the
|
||||
* collation element for that sequence. This means that getOffset()
|
||||
* is not guaranteed to return the same value as was passed to a preceding
|
||||
* call to setOffset().
|
||||
*
|
||||
* @param newOffset The new character offset into the original text.
|
||||
* @since 1.2
|
||||
*/
|
||||
@SuppressWarnings("deprecation") // getBeginIndex, getEndIndex and setIndex are deprecated
|
||||
public void setOffset(int newOffset)
|
||||
{
|
||||
if (text != null) {
|
||||
if (newOffset < text.getBeginIndex()
|
||||
|| newOffset >= text.getEndIndex()) {
|
||||
text.setIndexOnly(newOffset);
|
||||
} else {
|
||||
int c = text.setIndex(newOffset);
|
||||
|
||||
// if the desired character isn't used in a contracting character
|
||||
// sequence, bypass all the backing-up logic-- we're sitting on
|
||||
// the right character already
|
||||
if (ordering.usedInContractSeq(c)) {
|
||||
// walk backwards through the string until we see a character
|
||||
// that DOESN'T participate in a contracting character sequence
|
||||
while (ordering.usedInContractSeq(c)) {
|
||||
c = text.previous();
|
||||
}
|
||||
// now walk forward using this object's next() method until
|
||||
// we pass the starting point and set our current position
|
||||
// to the beginning of the last "character" before or at
|
||||
// our starting position
|
||||
int last = text.getIndex();
|
||||
while (text.getIndex() <= newOffset) {
|
||||
last = text.getIndex();
|
||||
next();
|
||||
}
|
||||
text.setIndexOnly(last);
|
||||
// we don't need this, since last is the last index
|
||||
// that is the starting of the contraction which encompass
|
||||
// newOffset
|
||||
// text.previous();
|
||||
}
|
||||
}
|
||||
}
|
||||
buffer = null;
|
||||
expIndex = 0;
|
||||
swapOrder = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the character offset in the original text corresponding to the next
|
||||
* collation element. (That is, getOffset() returns the position in the text
|
||||
* corresponding to the collation element that will be returned by the next
|
||||
* call to next().) This value will always be the index of the FIRST character
|
||||
* corresponding to the collation element (a contracting character sequence is
|
||||
* when two or more characters all correspond to the same collation element).
|
||||
* This means if you do setOffset(x) followed immediately by getOffset(), getOffset()
|
||||
* won't necessarily return x.
|
||||
*
|
||||
* @return The character offset in the original text corresponding to the collation
|
||||
* element that will be returned by the next call to next().
|
||||
* @since 1.2
|
||||
*/
|
||||
public int getOffset()
|
||||
{
|
||||
return (text != null) ? text.getIndex() : 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the maximum length of any expansion sequences that end
|
||||
* with the specified comparison order.
|
||||
* @param order a collation order returned by previous or next.
|
||||
* @return the maximum length of any expansion sequences ending
|
||||
* with the specified order.
|
||||
* @since 1.2
|
||||
*/
|
||||
public int getMaxExpansion(int order)
|
||||
{
|
||||
return ordering.getMaxExpansion(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a new string over which to iterate.
|
||||
*
|
||||
* @param source the new source text
|
||||
* @since 1.2
|
||||
*/
|
||||
public void setText(String source)
|
||||
{
|
||||
buffer = null;
|
||||
swapOrder = 0;
|
||||
expIndex = 0;
|
||||
NormalizerBase.Mode mode =
|
||||
CollatorUtilities.toNormalizerMode(owner.getDecomposition());
|
||||
if (text == null) {
|
||||
text = new NormalizerBase(source, mode);
|
||||
} else {
|
||||
text.setMode(mode);
|
||||
text.setText(source);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a new string over which to iterate.
|
||||
*
|
||||
* @param source the new source text.
|
||||
* @since 1.2
|
||||
*/
|
||||
public void setText(CharacterIterator source)
|
||||
{
|
||||
buffer = null;
|
||||
swapOrder = 0;
|
||||
expIndex = 0;
|
||||
NormalizerBase.Mode mode =
|
||||
CollatorUtilities.toNormalizerMode(owner.getDecomposition());
|
||||
if (text == null) {
|
||||
text = new NormalizerBase(source, mode);
|
||||
} else {
|
||||
text.setMode(mode);
|
||||
text.setText(source);
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================
|
||||
// privates
|
||||
//============================================================
|
||||
|
||||
/**
|
||||
* Determine if a character is a Thai vowel (which sorts after
|
||||
* its base consonant).
|
||||
*/
|
||||
private final static boolean isThaiPreVowel(int ch) {
|
||||
return (ch >= 0x0e40) && (ch <= 0x0e44);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a character is a Thai base consonant
|
||||
*/
|
||||
private final static boolean isThaiBaseConsonant(int ch) {
|
||||
return (ch >= 0x0e01) && (ch <= 0x0e2e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a character is a Lao vowel (which sorts after
|
||||
* its base consonant).
|
||||
*/
|
||||
private final static boolean isLaoPreVowel(int ch) {
|
||||
return (ch >= 0x0ec0) && (ch <= 0x0ec4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a character is a Lao base consonant
|
||||
*/
|
||||
private final static boolean isLaoBaseConsonant(int ch) {
|
||||
return (ch >= 0x0e81) && (ch <= 0x0eae);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method produces a buffer which contains the collation
|
||||
* elements for the two characters, with colFirst's values preceding
|
||||
* another character's. Presumably, the other character precedes colFirst
|
||||
* in logical order (otherwise you wouldn't need this method would you?).
|
||||
* The assumption is that the other char's value(s) have already been
|
||||
* computed. If this char has a single element it is passed to this
|
||||
* method as lastValue, and lastExpansion is null. If it has an
|
||||
* expansion it is passed in lastExpansion, and colLastValue is ignored.
|
||||
*/
|
||||
private int[] makeReorderedBuffer(int colFirst,
|
||||
int lastValue,
|
||||
int[] lastExpansion,
|
||||
boolean forward) {
|
||||
|
||||
int[] result;
|
||||
|
||||
int firstValue = ordering.getUnicodeOrder(colFirst);
|
||||
if (firstValue >= RuleBasedCollator.CONTRACTCHARINDEX) {
|
||||
firstValue = forward? nextContractChar(colFirst) : prevContractChar(colFirst);
|
||||
}
|
||||
|
||||
int[] firstExpansion = null;
|
||||
if (firstValue >= RuleBasedCollator.EXPANDCHARINDEX) {
|
||||
firstExpansion = ordering.getExpandValueList(firstValue);
|
||||
}
|
||||
|
||||
if (!forward) {
|
||||
int temp1 = firstValue;
|
||||
firstValue = lastValue;
|
||||
lastValue = temp1;
|
||||
int[] temp2 = firstExpansion;
|
||||
firstExpansion = lastExpansion;
|
||||
lastExpansion = temp2;
|
||||
}
|
||||
|
||||
if (firstExpansion == null && lastExpansion == null) {
|
||||
result = new int [2];
|
||||
result[0] = firstValue;
|
||||
result[1] = lastValue;
|
||||
}
|
||||
else {
|
||||
int firstLength = firstExpansion==null? 1 : firstExpansion.length;
|
||||
int lastLength = lastExpansion==null? 1 : lastExpansion.length;
|
||||
result = new int[firstLength + lastLength];
|
||||
|
||||
if (firstExpansion == null) {
|
||||
result[0] = firstValue;
|
||||
}
|
||||
else {
|
||||
System.arraycopy(firstExpansion, 0, result, 0, firstLength);
|
||||
}
|
||||
|
||||
if (lastExpansion == null) {
|
||||
result[firstLength] = lastValue;
|
||||
}
|
||||
else {
|
||||
System.arraycopy(lastExpansion, 0, result, firstLength, lastLength);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a comparison order is ignorable.
|
||||
* @return true if a character is ignorable, false otherwise.
|
||||
*/
|
||||
final static boolean isIgnorable(int order)
|
||||
{
|
||||
return ((primaryOrder(order) == 0) ? true : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ordering priority of the next contracting character in the
|
||||
* string.
|
||||
* @param ch the starting character of a contracting character token
|
||||
* @return the next contracting character's ordering. Returns NULLORDER
|
||||
* if the end of string is reached.
|
||||
*/
|
||||
private int nextContractChar(int ch)
|
||||
{
|
||||
// First get the ordering of this single character,
|
||||
// which is always the first element in the list
|
||||
Vector<EntryPair> list = ordering.getContractValues(ch);
|
||||
EntryPair pair = list.firstElement();
|
||||
int order = pair.value;
|
||||
|
||||
// find out the length of the longest contracting character sequence in the list.
|
||||
// There's logic in the builder code to make sure the longest sequence is always
|
||||
// the last.
|
||||
pair = list.lastElement();
|
||||
int maxLength = pair.entryName.length();
|
||||
|
||||
// (the Normalizer is cloned here so that the seeking we do in the next loop
|
||||
// won't affect our real position in the text)
|
||||
NormalizerBase tempText = (NormalizerBase)text.clone();
|
||||
|
||||
// extract the next maxLength characters in the string (we have to do this using the
|
||||
// Normalizer to ensure that our offsets correspond to those the rest of the
|
||||
// iterator is using) and store it in "fragment".
|
||||
tempText.previous();
|
||||
key.setLength(0);
|
||||
int c = tempText.next();
|
||||
while (maxLength > 0 && c != NormalizerBase.DONE) {
|
||||
if (Character.isSupplementaryCodePoint(c)) {
|
||||
key.append(Character.toChars(c));
|
||||
maxLength -= 2;
|
||||
} else {
|
||||
key.append((char)c);
|
||||
--maxLength;
|
||||
}
|
||||
c = tempText.next();
|
||||
}
|
||||
String fragment = key.toString();
|
||||
// now that we have that fragment, iterate through this list looking for the
|
||||
// longest sequence that matches the characters in the actual text. (maxLength
|
||||
// is used here to keep track of the length of the longest sequence)
|
||||
// Upon exit from this loop, maxLength will contain the length of the matching
|
||||
// sequence and order will contain the collation-element value corresponding
|
||||
// to this sequence
|
||||
maxLength = 1;
|
||||
for (int i = list.size() - 1; i > 0; i--) {
|
||||
pair = list.elementAt(i);
|
||||
if (!pair.fwd)
|
||||
continue;
|
||||
|
||||
if (fragment.startsWith(pair.entryName) && pair.entryName.length()
|
||||
> maxLength) {
|
||||
maxLength = pair.entryName.length();
|
||||
order = pair.value;
|
||||
}
|
||||
}
|
||||
|
||||
// seek our current iteration position to the end of the matching sequence
|
||||
// and return the appropriate collation-element value (if there was no matching
|
||||
// sequence, we're already seeked to the right position and order already contains
|
||||
// the correct collation-element value for the single character)
|
||||
while (maxLength > 1) {
|
||||
c = text.next();
|
||||
maxLength -= Character.charCount(c);
|
||||
}
|
||||
return order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ordering priority of the previous contracting character in the
|
||||
* string.
|
||||
* @param ch the starting character of a contracting character token
|
||||
* @return the next contracting character's ordering. Returns NULLORDER
|
||||
* if the end of string is reached.
|
||||
*/
|
||||
private int prevContractChar(int ch)
|
||||
{
|
||||
// This function is identical to nextContractChar(), except that we've
|
||||
// switched things so that the next() and previous() calls on the Normalizer
|
||||
// are switched and so that we skip entry pairs with the fwd flag turned on
|
||||
// rather than off. Notice that we still use append() and startsWith() when
|
||||
// working on the fragment. This is because the entry pairs that are used
|
||||
// in reverse iteration have their names reversed already.
|
||||
Vector<EntryPair> list = ordering.getContractValues(ch);
|
||||
EntryPair pair = list.firstElement();
|
||||
int order = pair.value;
|
||||
|
||||
pair = list.lastElement();
|
||||
int maxLength = pair.entryName.length();
|
||||
|
||||
NormalizerBase tempText = (NormalizerBase)text.clone();
|
||||
|
||||
tempText.next();
|
||||
key.setLength(0);
|
||||
int c = tempText.previous();
|
||||
while (maxLength > 0 && c != NormalizerBase.DONE) {
|
||||
if (Character.isSupplementaryCodePoint(c)) {
|
||||
key.append(Character.toChars(c));
|
||||
maxLength -= 2;
|
||||
} else {
|
||||
key.append((char)c);
|
||||
--maxLength;
|
||||
}
|
||||
c = tempText.previous();
|
||||
}
|
||||
String fragment = key.toString();
|
||||
|
||||
maxLength = 1;
|
||||
for (int i = list.size() - 1; i > 0; i--) {
|
||||
pair = list.elementAt(i);
|
||||
if (pair.fwd)
|
||||
continue;
|
||||
|
||||
if (fragment.startsWith(pair.entryName) && pair.entryName.length()
|
||||
> maxLength) {
|
||||
maxLength = pair.entryName.length();
|
||||
order = pair.value;
|
||||
}
|
||||
}
|
||||
|
||||
while (maxLength > 1) {
|
||||
c = text.previous();
|
||||
maxLength -= Character.charCount(c);
|
||||
}
|
||||
return order;
|
||||
}
|
||||
|
||||
final static int UNMAPPEDCHARVALUE = 0x7FFF0000;
|
||||
|
||||
private NormalizerBase text = null;
|
||||
private int[] buffer = null;
|
||||
private int expIndex = 0;
|
||||
private StringBuffer key = new StringBuffer(5);
|
||||
private int swapOrder = 0;
|
||||
private RBCollationTables ordering;
|
||||
private RuleBasedCollator owner;
|
||||
}
|
||||
149
jdkSrc/jdk8/java/text/CollationKey.java
Normal file
149
jdkSrc/jdk8/java/text/CollationKey.java
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is copyrighted
|
||||
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
|
||||
* materials are provided under terms of a License Agreement between Taligent
|
||||
* and Sun. This technology is protected by multiple US and International
|
||||
* patents. This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
/**
|
||||
* A <code>CollationKey</code> represents a <code>String</code> under the
|
||||
* rules of a specific <code>Collator</code> object. Comparing two
|
||||
* <code>CollationKey</code>s returns the relative order of the
|
||||
* <code>String</code>s they represent. Using <code>CollationKey</code>s
|
||||
* to compare <code>String</code>s is generally faster than using
|
||||
* <code>Collator.compare</code>. Thus, when the <code>String</code>s
|
||||
* must be compared multiple times, for example when sorting a list
|
||||
* of <code>String</code>s. It's more efficient to use <code>CollationKey</code>s.
|
||||
*
|
||||
* <p>
|
||||
* You can not create <code>CollationKey</code>s directly. Rather,
|
||||
* generate them by calling <code>Collator.getCollationKey</code>.
|
||||
* You can only compare <code>CollationKey</code>s generated from
|
||||
* the same <code>Collator</code> object.
|
||||
*
|
||||
* <p>
|
||||
* Generating a <code>CollationKey</code> for a <code>String</code>
|
||||
* involves examining the entire <code>String</code>
|
||||
* and converting it to series of bits that can be compared bitwise. This
|
||||
* allows fast comparisons once the keys are generated. The cost of generating
|
||||
* keys is recouped in faster comparisons when <code>String</code>s need
|
||||
* to be compared many times. On the other hand, the result of a comparison
|
||||
* is often determined by the first couple of characters of each <code>String</code>.
|
||||
* <code>Collator.compare</code> examines only as many characters as it needs which
|
||||
* allows it to be faster when doing single comparisons.
|
||||
* <p>
|
||||
* The following example shows how <code>CollationKey</code>s might be used
|
||||
* to sort a list of <code>String</code>s.
|
||||
* <blockquote>
|
||||
* <pre>{@code
|
||||
* // Create an array of CollationKeys for the Strings to be sorted.
|
||||
* Collator myCollator = Collator.getInstance();
|
||||
* CollationKey[] keys = new CollationKey[3];
|
||||
* keys[0] = myCollator.getCollationKey("Tom");
|
||||
* keys[1] = myCollator.getCollationKey("Dick");
|
||||
* keys[2] = myCollator.getCollationKey("Harry");
|
||||
* sort(keys);
|
||||
*
|
||||
* //...
|
||||
*
|
||||
* // Inside body of sort routine, compare keys this way
|
||||
* if (keys[i].compareTo(keys[j]) > 0)
|
||||
* // swap keys[i] and keys[j]
|
||||
*
|
||||
* //...
|
||||
*
|
||||
* // Finally, when we've returned from sort.
|
||||
* System.out.println(keys[0].getSourceString());
|
||||
* System.out.println(keys[1].getSourceString());
|
||||
* System.out.println(keys[2].getSourceString());
|
||||
* }</pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* @see Collator
|
||||
* @see RuleBasedCollator
|
||||
* @author Helena Shih
|
||||
*/
|
||||
|
||||
public abstract class CollationKey implements Comparable<CollationKey> {
|
||||
/**
|
||||
* Compare this CollationKey to the target CollationKey. The collation rules of the
|
||||
* Collator object which created these keys are applied. <strong>Note:</strong>
|
||||
* CollationKeys created by different Collators can not be compared.
|
||||
* @param target target CollationKey
|
||||
* @return Returns an integer value. Value is less than zero if this is less
|
||||
* than target, value is zero if this and target are equal and value is greater than
|
||||
* zero if this is greater than target.
|
||||
* @see java.text.Collator#compare
|
||||
*/
|
||||
abstract public int compareTo(CollationKey target);
|
||||
|
||||
/**
|
||||
* Returns the String that this CollationKey represents.
|
||||
*
|
||||
* @return the source string of this CollationKey
|
||||
*/
|
||||
public String getSourceString() {
|
||||
return source;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts the CollationKey to a sequence of bits. If two CollationKeys
|
||||
* could be legitimately compared, then one could compare the byte arrays
|
||||
* for each of those keys to obtain the same result. Byte arrays are
|
||||
* organized most significant byte first.
|
||||
*
|
||||
* @return a byte array representation of the CollationKey
|
||||
*/
|
||||
abstract public byte[] toByteArray();
|
||||
|
||||
|
||||
/**
|
||||
* CollationKey constructor.
|
||||
*
|
||||
* @param source the source string
|
||||
* @exception NullPointerException if {@code source} is null
|
||||
* @since 1.6
|
||||
*/
|
||||
protected CollationKey(String source) {
|
||||
if (source==null){
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
final private String source;
|
||||
}
|
||||
515
jdkSrc/jdk8/java/text/Collator.java
Normal file
515
jdkSrc/jdk8/java/text/Collator.java
Normal file
@@ -0,0 +1,515 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is copyrighted
|
||||
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
|
||||
* materials are provided under terms of a License Agreement between Taligent
|
||||
* and Sun. This technology is protected by multiple US and International
|
||||
* patents. This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.text.spi.CollatorProvider;
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import sun.util.locale.provider.LocaleProviderAdapter;
|
||||
import sun.util.locale.provider.LocaleServiceProviderPool;
|
||||
|
||||
|
||||
/**
|
||||
* The <code>Collator</code> class performs locale-sensitive
|
||||
* <code>String</code> comparison. You use this class to build
|
||||
* searching and sorting routines for natural language text.
|
||||
*
|
||||
* <p>
|
||||
* <code>Collator</code> is an abstract base class. Subclasses
|
||||
* implement specific collation strategies. One subclass,
|
||||
* <code>RuleBasedCollator</code>, is currently provided with
|
||||
* the Java Platform and is applicable to a wide set of languages. Other
|
||||
* subclasses may be created to handle more specialized needs.
|
||||
*
|
||||
* <p>
|
||||
* Like other locale-sensitive classes, you can use the static
|
||||
* factory method, <code>getInstance</code>, to obtain the appropriate
|
||||
* <code>Collator</code> object for a given locale. You will only need
|
||||
* to look at the subclasses of <code>Collator</code> if you need
|
||||
* to understand the details of a particular collation strategy or
|
||||
* if you need to modify that strategy.
|
||||
*
|
||||
* <p>
|
||||
* The following example shows how to compare two strings using
|
||||
* the <code>Collator</code> for the default locale.
|
||||
* <blockquote>
|
||||
* <pre>{@code
|
||||
* // Compare two strings in the default locale
|
||||
* Collator myCollator = Collator.getInstance();
|
||||
* if( myCollator.compare("abc", "ABC") < 0 )
|
||||
* System.out.println("abc is less than ABC");
|
||||
* else
|
||||
* System.out.println("abc is greater than or equal to ABC");
|
||||
* }</pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* <p>
|
||||
* You can set a <code>Collator</code>'s <em>strength</em> property
|
||||
* to determine the level of difference considered significant in
|
||||
* comparisons. Four strengths are provided: <code>PRIMARY</code>,
|
||||
* <code>SECONDARY</code>, <code>TERTIARY</code>, and <code>IDENTICAL</code>.
|
||||
* The exact assignment of strengths to language features is
|
||||
* locale dependant. For example, in Czech, "e" and "f" are considered
|
||||
* primary differences, while "e" and "ě" are secondary differences,
|
||||
* "e" and "E" are tertiary differences and "e" and "e" are identical.
|
||||
* The following shows how both case and accents could be ignored for
|
||||
* US English.
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* //Get the Collator for US English and set its strength to PRIMARY
|
||||
* Collator usCollator = Collator.getInstance(Locale.US);
|
||||
* usCollator.setStrength(Collator.PRIMARY);
|
||||
* if( usCollator.compare("abc", "ABC") == 0 ) {
|
||||
* System.out.println("Strings are equivalent");
|
||||
* }
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
* <p>
|
||||
* For comparing <code>String</code>s exactly once, the <code>compare</code>
|
||||
* method provides the best performance. When sorting a list of
|
||||
* <code>String</code>s however, it is generally necessary to compare each
|
||||
* <code>String</code> multiple times. In this case, <code>CollationKey</code>s
|
||||
* provide better performance. The <code>CollationKey</code> class converts
|
||||
* a <code>String</code> to a series of bits that can be compared bitwise
|
||||
* against other <code>CollationKey</code>s. A <code>CollationKey</code> is
|
||||
* created by a <code>Collator</code> object for a given <code>String</code>.
|
||||
* <br>
|
||||
* <strong>Note:</strong> <code>CollationKey</code>s from different
|
||||
* <code>Collator</code>s can not be compared. See the class description
|
||||
* for {@link CollationKey}
|
||||
* for an example using <code>CollationKey</code>s.
|
||||
*
|
||||
* @see RuleBasedCollator
|
||||
* @see CollationKey
|
||||
* @see CollationElementIterator
|
||||
* @see Locale
|
||||
* @author Helena Shih, Laura Werner, Richard Gillam
|
||||
*/
|
||||
|
||||
public abstract class Collator
|
||||
implements java.util.Comparator<Object>, Cloneable
|
||||
{
|
||||
/**
|
||||
* Collator strength value. When set, only PRIMARY differences are
|
||||
* considered significant during comparison. The assignment of strengths
|
||||
* to language features is locale dependant. A common example is for
|
||||
* different base letters ("a" vs "b") to be considered a PRIMARY difference.
|
||||
* @see java.text.Collator#setStrength
|
||||
* @see java.text.Collator#getStrength
|
||||
*/
|
||||
public final static int PRIMARY = 0;
|
||||
/**
|
||||
* Collator strength value. When set, only SECONDARY and above differences are
|
||||
* considered significant during comparison. The assignment of strengths
|
||||
* to language features is locale dependant. A common example is for
|
||||
* different accented forms of the same base letter ("a" vs "\u00E4") to be
|
||||
* considered a SECONDARY difference.
|
||||
* @see java.text.Collator#setStrength
|
||||
* @see java.text.Collator#getStrength
|
||||
*/
|
||||
public final static int SECONDARY = 1;
|
||||
/**
|
||||
* Collator strength value. When set, only TERTIARY and above differences are
|
||||
* considered significant during comparison. The assignment of strengths
|
||||
* to language features is locale dependant. A common example is for
|
||||
* case differences ("a" vs "A") to be considered a TERTIARY difference.
|
||||
* @see java.text.Collator#setStrength
|
||||
* @see java.text.Collator#getStrength
|
||||
*/
|
||||
public final static int TERTIARY = 2;
|
||||
|
||||
/**
|
||||
* Collator strength value. When set, all differences are
|
||||
* considered significant during comparison. The assignment of strengths
|
||||
* to language features is locale dependant. A common example is for control
|
||||
* characters ("\u0001" vs "\u0002") to be considered equal at the
|
||||
* PRIMARY, SECONDARY, and TERTIARY levels but different at the IDENTICAL
|
||||
* level. Additionally, differences between pre-composed accents such as
|
||||
* "\u00C0" (A-grave) and combining accents such as "A\u0300"
|
||||
* (A, combining-grave) will be considered significant at the IDENTICAL
|
||||
* level if decomposition is set to NO_DECOMPOSITION.
|
||||
*/
|
||||
public final static int IDENTICAL = 3;
|
||||
|
||||
/**
|
||||
* Decomposition mode value. With NO_DECOMPOSITION
|
||||
* set, accented characters will not be decomposed for collation. This
|
||||
* is the default setting and provides the fastest collation but
|
||||
* will only produce correct results for languages that do not use accents.
|
||||
* @see java.text.Collator#getDecomposition
|
||||
* @see java.text.Collator#setDecomposition
|
||||
*/
|
||||
public final static int NO_DECOMPOSITION = 0;
|
||||
|
||||
/**
|
||||
* Decomposition mode value. With CANONICAL_DECOMPOSITION
|
||||
* set, characters that are canonical variants according to Unicode
|
||||
* standard will be decomposed for collation. This should be used to get
|
||||
* correct collation of accented characters.
|
||||
* <p>
|
||||
* CANONICAL_DECOMPOSITION corresponds to Normalization Form D as
|
||||
* described in
|
||||
* <a href="http://www.unicode.org/unicode/reports/tr15/tr15-23.html">Unicode
|
||||
* Technical Report #15</a>.
|
||||
* @see java.text.Collator#getDecomposition
|
||||
* @see java.text.Collator#setDecomposition
|
||||
*/
|
||||
public final static int CANONICAL_DECOMPOSITION = 1;
|
||||
|
||||
/**
|
||||
* Decomposition mode value. With FULL_DECOMPOSITION
|
||||
* set, both Unicode canonical variants and Unicode compatibility variants
|
||||
* will be decomposed for collation. This causes not only accented
|
||||
* characters to be collated, but also characters that have special formats
|
||||
* to be collated with their norminal form. For example, the half-width and
|
||||
* full-width ASCII and Katakana characters are then collated together.
|
||||
* FULL_DECOMPOSITION is the most complete and therefore the slowest
|
||||
* decomposition mode.
|
||||
* <p>
|
||||
* FULL_DECOMPOSITION corresponds to Normalization Form KD as
|
||||
* described in
|
||||
* <a href="http://www.unicode.org/unicode/reports/tr15/tr15-23.html">Unicode
|
||||
* Technical Report #15</a>.
|
||||
* @see java.text.Collator#getDecomposition
|
||||
* @see java.text.Collator#setDecomposition
|
||||
*/
|
||||
public final static int FULL_DECOMPOSITION = 2;
|
||||
|
||||
/**
|
||||
* Gets the Collator for the current default locale.
|
||||
* The default locale is determined by java.util.Locale.getDefault.
|
||||
* @return the Collator for the default locale.(for example, en_US)
|
||||
* @see java.util.Locale#getDefault
|
||||
*/
|
||||
public static synchronized Collator getInstance() {
|
||||
return getInstance(Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Collator for the desired locale.
|
||||
* @param desiredLocale the desired locale.
|
||||
* @return the Collator for the desired locale.
|
||||
* @see java.util.Locale
|
||||
* @see java.util.ResourceBundle
|
||||
*/
|
||||
public static Collator getInstance(Locale desiredLocale) {
|
||||
SoftReference<Collator> ref = cache.get(desiredLocale);
|
||||
Collator result = (ref != null) ? ref.get() : null;
|
||||
if (result == null) {
|
||||
LocaleProviderAdapter adapter;
|
||||
adapter = LocaleProviderAdapter.getAdapter(CollatorProvider.class,
|
||||
desiredLocale);
|
||||
CollatorProvider provider = adapter.getCollatorProvider();
|
||||
result = provider.getInstance(desiredLocale);
|
||||
if (result == null) {
|
||||
result = LocaleProviderAdapter.forJRE()
|
||||
.getCollatorProvider().getInstance(desiredLocale);
|
||||
}
|
||||
while (true) {
|
||||
if (ref != null) {
|
||||
// Remove the empty SoftReference if any
|
||||
cache.remove(desiredLocale, ref);
|
||||
}
|
||||
ref = cache.putIfAbsent(desiredLocale, new SoftReference<>(result));
|
||||
if (ref == null) {
|
||||
break;
|
||||
}
|
||||
Collator cachedColl = ref.get();
|
||||
if (cachedColl != null) {
|
||||
result = cachedColl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (Collator) result.clone(); // make the world safe
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the source string to the target string according to the
|
||||
* collation rules for this Collator. Returns an integer less than,
|
||||
* equal to or greater than zero depending on whether the source String is
|
||||
* less than, equal to or greater than the target string. See the Collator
|
||||
* class description for an example of use.
|
||||
* <p>
|
||||
* For a one time comparison, this method has the best performance. If a
|
||||
* given String will be involved in multiple comparisons, CollationKey.compareTo
|
||||
* has the best performance. See the Collator class description for an example
|
||||
* using CollationKeys.
|
||||
* @param source the source string.
|
||||
* @param target the target string.
|
||||
* @return Returns an integer value. Value is less than zero if source is less than
|
||||
* target, value is zero if source and target are equal, value is greater than zero
|
||||
* if source is greater than target.
|
||||
* @see java.text.CollationKey
|
||||
* @see java.text.Collator#getCollationKey
|
||||
*/
|
||||
public abstract int compare(String source, String target);
|
||||
|
||||
/**
|
||||
* Compares its two arguments for order. Returns a negative integer,
|
||||
* zero, or a positive integer as the first argument is less than, equal
|
||||
* to, or greater than the second.
|
||||
* <p>
|
||||
* This implementation merely returns
|
||||
* <code> compare((String)o1, (String)o2) </code>.
|
||||
*
|
||||
* @return a negative integer, zero, or a positive integer as the
|
||||
* first argument is less than, equal to, or greater than the
|
||||
* second.
|
||||
* @exception ClassCastException the arguments cannot be cast to Strings.
|
||||
* @see java.util.Comparator
|
||||
* @since 1.2
|
||||
*/
|
||||
@Override
|
||||
public int compare(Object o1, Object o2) {
|
||||
return compare((String)o1, (String)o2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the String into a series of bits that can be compared bitwise
|
||||
* to other CollationKeys. CollationKeys provide better performance than
|
||||
* Collator.compare when Strings are involved in multiple comparisons.
|
||||
* See the Collator class description for an example using CollationKeys.
|
||||
* @param source the string to be transformed into a collation key.
|
||||
* @return the CollationKey for the given String based on this Collator's collation
|
||||
* rules. If the source String is null, a null CollationKey is returned.
|
||||
* @see java.text.CollationKey
|
||||
* @see java.text.Collator#compare
|
||||
*/
|
||||
public abstract CollationKey getCollationKey(String source);
|
||||
|
||||
/**
|
||||
* Convenience method for comparing the equality of two strings based on
|
||||
* this Collator's collation rules.
|
||||
* @param source the source string to be compared with.
|
||||
* @param target the target string to be compared with.
|
||||
* @return true if the strings are equal according to the collation
|
||||
* rules. false, otherwise.
|
||||
* @see java.text.Collator#compare
|
||||
*/
|
||||
public boolean equals(String source, String target)
|
||||
{
|
||||
return (compare(source, target) == Collator.EQUAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this Collator's strength property. The strength property determines
|
||||
* the minimum level of difference considered significant during comparison.
|
||||
* See the Collator class description for an example of use.
|
||||
* @return this Collator's current strength property.
|
||||
* @see java.text.Collator#setStrength
|
||||
* @see java.text.Collator#PRIMARY
|
||||
* @see java.text.Collator#SECONDARY
|
||||
* @see java.text.Collator#TERTIARY
|
||||
* @see java.text.Collator#IDENTICAL
|
||||
*/
|
||||
public synchronized int getStrength()
|
||||
{
|
||||
return strength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this Collator's strength property. The strength property determines
|
||||
* the minimum level of difference considered significant during comparison.
|
||||
* See the Collator class description for an example of use.
|
||||
* @param newStrength the new strength value.
|
||||
* @see java.text.Collator#getStrength
|
||||
* @see java.text.Collator#PRIMARY
|
||||
* @see java.text.Collator#SECONDARY
|
||||
* @see java.text.Collator#TERTIARY
|
||||
* @see java.text.Collator#IDENTICAL
|
||||
* @exception IllegalArgumentException If the new strength value is not one of
|
||||
* PRIMARY, SECONDARY, TERTIARY or IDENTICAL.
|
||||
*/
|
||||
public synchronized void setStrength(int newStrength) {
|
||||
if ((newStrength != PRIMARY) &&
|
||||
(newStrength != SECONDARY) &&
|
||||
(newStrength != TERTIARY) &&
|
||||
(newStrength != IDENTICAL)) {
|
||||
throw new IllegalArgumentException("Incorrect comparison level.");
|
||||
}
|
||||
strength = newStrength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the decomposition mode of this Collator. Decomposition mode
|
||||
* determines how Unicode composed characters are handled. Adjusting
|
||||
* decomposition mode allows the user to select between faster and more
|
||||
* complete collation behavior.
|
||||
* <p>The three values for decomposition mode are:
|
||||
* <UL>
|
||||
* <LI>NO_DECOMPOSITION,
|
||||
* <LI>CANONICAL_DECOMPOSITION
|
||||
* <LI>FULL_DECOMPOSITION.
|
||||
* </UL>
|
||||
* See the documentation for these three constants for a description
|
||||
* of their meaning.
|
||||
* @return the decomposition mode
|
||||
* @see java.text.Collator#setDecomposition
|
||||
* @see java.text.Collator#NO_DECOMPOSITION
|
||||
* @see java.text.Collator#CANONICAL_DECOMPOSITION
|
||||
* @see java.text.Collator#FULL_DECOMPOSITION
|
||||
*/
|
||||
public synchronized int getDecomposition()
|
||||
{
|
||||
return decmp;
|
||||
}
|
||||
/**
|
||||
* Set the decomposition mode of this Collator. See getDecomposition
|
||||
* for a description of decomposition mode.
|
||||
* @param decompositionMode the new decomposition mode.
|
||||
* @see java.text.Collator#getDecomposition
|
||||
* @see java.text.Collator#NO_DECOMPOSITION
|
||||
* @see java.text.Collator#CANONICAL_DECOMPOSITION
|
||||
* @see java.text.Collator#FULL_DECOMPOSITION
|
||||
* @exception IllegalArgumentException If the given value is not a valid decomposition
|
||||
* mode.
|
||||
*/
|
||||
public synchronized void setDecomposition(int decompositionMode) {
|
||||
if ((decompositionMode != NO_DECOMPOSITION) &&
|
||||
(decompositionMode != CANONICAL_DECOMPOSITION) &&
|
||||
(decompositionMode != FULL_DECOMPOSITION)) {
|
||||
throw new IllegalArgumentException("Wrong decomposition mode.");
|
||||
}
|
||||
decmp = decompositionMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all locales for which the
|
||||
* <code>getInstance</code> methods of this class can return
|
||||
* localized instances.
|
||||
* The returned array represents the union of locales supported
|
||||
* by the Java runtime and by installed
|
||||
* {@link java.text.spi.CollatorProvider CollatorProvider} implementations.
|
||||
* It must contain at least a Locale instance equal to
|
||||
* {@link java.util.Locale#US Locale.US}.
|
||||
*
|
||||
* @return An array of locales for which localized
|
||||
* <code>Collator</code> instances are available.
|
||||
*/
|
||||
public static synchronized Locale[] getAvailableLocales() {
|
||||
LocaleServiceProviderPool pool =
|
||||
LocaleServiceProviderPool.getPool(CollatorProvider.class);
|
||||
return pool.getAvailableLocales();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides Cloneable
|
||||
*/
|
||||
@Override
|
||||
public Object clone()
|
||||
{
|
||||
try {
|
||||
return (Collator)super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the equality of two Collators.
|
||||
* @param that the Collator to be compared with this.
|
||||
* @return true if this Collator is the same as that Collator;
|
||||
* false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object that)
|
||||
{
|
||||
if (this == that) {
|
||||
return true;
|
||||
}
|
||||
if (that == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != that.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Collator other = (Collator) that;
|
||||
return ((strength == other.strength) &&
|
||||
(decmp == other.decmp));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the hash code for this Collator.
|
||||
*/
|
||||
@Override
|
||||
abstract public int hashCode();
|
||||
|
||||
/**
|
||||
* Default constructor. This constructor is
|
||||
* protected so subclasses can get access to it. Users typically create
|
||||
* a Collator sub-class by calling the factory method getInstance.
|
||||
* @see java.text.Collator#getInstance
|
||||
*/
|
||||
protected Collator()
|
||||
{
|
||||
strength = TERTIARY;
|
||||
decmp = CANONICAL_DECOMPOSITION;
|
||||
}
|
||||
|
||||
private int strength = 0;
|
||||
private int decmp = 0;
|
||||
private static final ConcurrentMap<Locale, SoftReference<Collator>> cache
|
||||
= new ConcurrentHashMap<>();
|
||||
|
||||
//
|
||||
// FIXME: These three constants should be removed.
|
||||
//
|
||||
/**
|
||||
* LESS is returned if source string is compared to be less than target
|
||||
* string in the compare() method.
|
||||
* @see java.text.Collator#compare
|
||||
*/
|
||||
final static int LESS = -1;
|
||||
/**
|
||||
* EQUAL is returned if source string is compared to be equal to target
|
||||
* string in the compare() method.
|
||||
* @see java.text.Collator#compare
|
||||
*/
|
||||
final static int EQUAL = 0;
|
||||
/**
|
||||
* GREATER is returned if source string is compared to be greater than
|
||||
* target string in the compare() method.
|
||||
* @see java.text.Collator#compare
|
||||
*/
|
||||
final static int GREATER = 1;
|
||||
}
|
||||
1040
jdkSrc/jdk8/java/text/DateFormat.java
Normal file
1040
jdkSrc/jdk8/java/text/DateFormat.java
Normal file
File diff suppressed because it is too large
Load Diff
876
jdkSrc/jdk8/java/text/DateFormatSymbols.java
Normal file
876
jdkSrc/jdk8/java/text/DateFormatSymbols.java
Normal file
@@ -0,0 +1,876 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is copyrighted
|
||||
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
|
||||
* materials are provided under terms of a License Agreement between Taligent
|
||||
* and Sun. This technology is protected by multiple US and International
|
||||
* patents. This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.text.spi.DateFormatSymbolsProvider;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import sun.util.locale.provider.LocaleProviderAdapter;
|
||||
import sun.util.locale.provider.LocaleServiceProviderPool;
|
||||
import sun.util.locale.provider.ResourceBundleBasedAdapter;
|
||||
import sun.util.locale.provider.TimeZoneNameUtility;
|
||||
|
||||
/**
|
||||
* <code>DateFormatSymbols</code> is a public class for encapsulating
|
||||
* localizable date-time formatting data, such as the names of the
|
||||
* months, the names of the days of the week, and the time zone data.
|
||||
* <code>SimpleDateFormat</code> uses
|
||||
* <code>DateFormatSymbols</code> to encapsulate this information.
|
||||
*
|
||||
* <p>
|
||||
* Typically you shouldn't use <code>DateFormatSymbols</code> directly.
|
||||
* Rather, you are encouraged to create a date-time formatter with the
|
||||
* <code>DateFormat</code> class's factory methods: <code>getTimeInstance</code>,
|
||||
* <code>getDateInstance</code>, or <code>getDateTimeInstance</code>.
|
||||
* These methods automatically create a <code>DateFormatSymbols</code> for
|
||||
* the formatter so that you don't have to. After the
|
||||
* formatter is created, you may modify its format pattern using the
|
||||
* <code>setPattern</code> method. For more information about
|
||||
* creating formatters using <code>DateFormat</code>'s factory methods,
|
||||
* see {@link DateFormat}.
|
||||
*
|
||||
* <p>
|
||||
* If you decide to create a date-time formatter with a specific
|
||||
* format pattern for a specific locale, you can do so with:
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* new SimpleDateFormat(aPattern, DateFormatSymbols.getInstance(aLocale)).
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* <p>
|
||||
* <code>DateFormatSymbols</code> objects are cloneable. When you obtain
|
||||
* a <code>DateFormatSymbols</code> object, feel free to modify the
|
||||
* date-time formatting data. For instance, you can replace the localized
|
||||
* date-time format pattern characters with the ones that you feel easy
|
||||
* to remember. Or you can change the representative cities
|
||||
* to your favorite ones.
|
||||
*
|
||||
* <p>
|
||||
* New <code>DateFormatSymbols</code> subclasses may be added to support
|
||||
* <code>SimpleDateFormat</code> for date-time formatting for additional locales.
|
||||
|
||||
* @see DateFormat
|
||||
* @see SimpleDateFormat
|
||||
* @see java.util.SimpleTimeZone
|
||||
* @author Chen-Lieh Huang
|
||||
*/
|
||||
public class DateFormatSymbols implements Serializable, Cloneable {
|
||||
|
||||
/**
|
||||
* Construct a DateFormatSymbols object by loading format data from
|
||||
* resources for the default {@link java.util.Locale.Category#FORMAT FORMAT}
|
||||
* locale. This constructor can only
|
||||
* construct instances for the locales supported by the Java
|
||||
* runtime environment, not for those supported by installed
|
||||
* {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
|
||||
* implementations. For full locale coverage, use the
|
||||
* {@link #getInstance(Locale) getInstance} method.
|
||||
* <p>This is equivalent to calling
|
||||
* {@link #DateFormatSymbols(Locale)
|
||||
* DateFormatSymbols(Locale.getDefault(Locale.Category.FORMAT))}.
|
||||
* @see #getInstance()
|
||||
* @see java.util.Locale#getDefault(java.util.Locale.Category)
|
||||
* @see java.util.Locale.Category#FORMAT
|
||||
* @exception java.util.MissingResourceException
|
||||
* if the resources for the default locale cannot be
|
||||
* found or cannot be loaded.
|
||||
*/
|
||||
public DateFormatSymbols()
|
||||
{
|
||||
initializeData(Locale.getDefault(Locale.Category.FORMAT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a DateFormatSymbols object by loading format data from
|
||||
* resources for the given locale. This constructor can only
|
||||
* construct instances for the locales supported by the Java
|
||||
* runtime environment, not for those supported by installed
|
||||
* {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
|
||||
* implementations. For full locale coverage, use the
|
||||
* {@link #getInstance(Locale) getInstance} method.
|
||||
*
|
||||
* @param locale the desired locale
|
||||
* @see #getInstance(Locale)
|
||||
* @exception java.util.MissingResourceException
|
||||
* if the resources for the specified locale cannot be
|
||||
* found or cannot be loaded.
|
||||
*/
|
||||
public DateFormatSymbols(Locale locale)
|
||||
{
|
||||
initializeData(locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an uninitialized DateFormatSymbols.
|
||||
*/
|
||||
private DateFormatSymbols(boolean flag) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Era strings. For example: "AD" and "BC". An array of 2 strings,
|
||||
* indexed by <code>Calendar.BC</code> and <code>Calendar.AD</code>.
|
||||
* @serial
|
||||
*/
|
||||
String eras[] = null;
|
||||
|
||||
/**
|
||||
* Month strings. For example: "January", "February", etc. An array
|
||||
* of 13 strings (some calendars have 13 months), indexed by
|
||||
* <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
|
||||
* @serial
|
||||
*/
|
||||
String months[] = null;
|
||||
|
||||
/**
|
||||
* Short month strings. For example: "Jan", "Feb", etc. An array of
|
||||
* 13 strings (some calendars have 13 months), indexed by
|
||||
* <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
|
||||
|
||||
* @serial
|
||||
*/
|
||||
String shortMonths[] = null;
|
||||
|
||||
/**
|
||||
* Weekday strings. For example: "Sunday", "Monday", etc. An array
|
||||
* of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
|
||||
* <code>Calendar.MONDAY</code>, etc.
|
||||
* The element <code>weekdays[0]</code> is ignored.
|
||||
* @serial
|
||||
*/
|
||||
String weekdays[] = null;
|
||||
|
||||
/**
|
||||
* Short weekday strings. For example: "Sun", "Mon", etc. An array
|
||||
* of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
|
||||
* <code>Calendar.MONDAY</code>, etc.
|
||||
* The element <code>shortWeekdays[0]</code> is ignored.
|
||||
* @serial
|
||||
*/
|
||||
String shortWeekdays[] = null;
|
||||
|
||||
/**
|
||||
* AM and PM strings. For example: "AM" and "PM". An array of
|
||||
* 2 strings, indexed by <code>Calendar.AM</code> and
|
||||
* <code>Calendar.PM</code>.
|
||||
* @serial
|
||||
*/
|
||||
String ampms[] = null;
|
||||
|
||||
/**
|
||||
* Localized names of time zones in this locale. This is a
|
||||
* two-dimensional array of strings of size <em>n</em> by <em>m</em>,
|
||||
* where <em>m</em> is at least 5. Each of the <em>n</em> rows is an
|
||||
* entry containing the localized names for a single <code>TimeZone</code>.
|
||||
* Each such row contains (with <code>i</code> ranging from
|
||||
* 0..<em>n</em>-1):
|
||||
* <ul>
|
||||
* <li><code>zoneStrings[i][0]</code> - time zone ID</li>
|
||||
* <li><code>zoneStrings[i][1]</code> - long name of zone in standard
|
||||
* time</li>
|
||||
* <li><code>zoneStrings[i][2]</code> - short name of zone in
|
||||
* standard time</li>
|
||||
* <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
|
||||
* saving time</li>
|
||||
* <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
|
||||
* saving time</li>
|
||||
* </ul>
|
||||
* The zone ID is <em>not</em> localized; it's one of the valid IDs of
|
||||
* the {@link java.util.TimeZone TimeZone} class that are not
|
||||
* <a href="../java/util/TimeZone.html#CustomID">custom IDs</a>.
|
||||
* All other entries are localized names.
|
||||
* @see java.util.TimeZone
|
||||
* @serial
|
||||
*/
|
||||
String zoneStrings[][] = null;
|
||||
|
||||
/**
|
||||
* Indicates that zoneStrings is set externally with setZoneStrings() method.
|
||||
*/
|
||||
transient boolean isZoneStringsSet = false;
|
||||
|
||||
/**
|
||||
* Unlocalized date-time pattern characters. For example: 'y', 'd', etc.
|
||||
* All locales use the same these unlocalized pattern characters.
|
||||
*/
|
||||
static final String patternChars = "GyMdkHmsSEDFwWahKzZYuXL";
|
||||
|
||||
static final int PATTERN_ERA = 0; // G
|
||||
static final int PATTERN_YEAR = 1; // y
|
||||
static final int PATTERN_MONTH = 2; // M
|
||||
static final int PATTERN_DAY_OF_MONTH = 3; // d
|
||||
static final int PATTERN_HOUR_OF_DAY1 = 4; // k
|
||||
static final int PATTERN_HOUR_OF_DAY0 = 5; // H
|
||||
static final int PATTERN_MINUTE = 6; // m
|
||||
static final int PATTERN_SECOND = 7; // s
|
||||
static final int PATTERN_MILLISECOND = 8; // S
|
||||
static final int PATTERN_DAY_OF_WEEK = 9; // E
|
||||
static final int PATTERN_DAY_OF_YEAR = 10; // D
|
||||
static final int PATTERN_DAY_OF_WEEK_IN_MONTH = 11; // F
|
||||
static final int PATTERN_WEEK_OF_YEAR = 12; // w
|
||||
static final int PATTERN_WEEK_OF_MONTH = 13; // W
|
||||
static final int PATTERN_AM_PM = 14; // a
|
||||
static final int PATTERN_HOUR1 = 15; // h
|
||||
static final int PATTERN_HOUR0 = 16; // K
|
||||
static final int PATTERN_ZONE_NAME = 17; // z
|
||||
static final int PATTERN_ZONE_VALUE = 18; // Z
|
||||
static final int PATTERN_WEEK_YEAR = 19; // Y
|
||||
static final int PATTERN_ISO_DAY_OF_WEEK = 20; // u
|
||||
static final int PATTERN_ISO_ZONE = 21; // X
|
||||
static final int PATTERN_MONTH_STANDALONE = 22; // L
|
||||
|
||||
/**
|
||||
* Localized date-time pattern characters. For example, a locale may
|
||||
* wish to use 'u' rather than 'y' to represent years in its date format
|
||||
* pattern strings.
|
||||
* This string must be exactly 18 characters long, with the index of
|
||||
* the characters described by <code>DateFormat.ERA_FIELD</code>,
|
||||
* <code>DateFormat.YEAR_FIELD</code>, etc. Thus, if the string were
|
||||
* "Xz...", then localized patterns would use 'X' for era and 'z' for year.
|
||||
* @serial
|
||||
*/
|
||||
String localPatternChars = null;
|
||||
|
||||
/**
|
||||
* The locale which is used for initializing this DateFormatSymbols object.
|
||||
*
|
||||
* @since 1.6
|
||||
* @serial
|
||||
*/
|
||||
Locale locale = null;
|
||||
|
||||
/* use serialVersionUID from JDK 1.1.4 for interoperability */
|
||||
static final long serialVersionUID = -5987973545549424702L;
|
||||
|
||||
/**
|
||||
* Returns an array of all locales for which the
|
||||
* <code>getInstance</code> methods of this class can return
|
||||
* localized instances.
|
||||
* The returned array represents the union of locales supported by the
|
||||
* Java runtime and by installed
|
||||
* {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
|
||||
* implementations. It must contain at least a <code>Locale</code>
|
||||
* instance equal to {@link java.util.Locale#US Locale.US}.
|
||||
*
|
||||
* @return An array of locales for which localized
|
||||
* <code>DateFormatSymbols</code> instances are available.
|
||||
* @since 1.6
|
||||
*/
|
||||
public static Locale[] getAvailableLocales() {
|
||||
LocaleServiceProviderPool pool=
|
||||
LocaleServiceProviderPool.getPool(DateFormatSymbolsProvider.class);
|
||||
return pool.getAvailableLocales();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <code>DateFormatSymbols</code> instance for the default
|
||||
* locale. This method provides access to <code>DateFormatSymbols</code>
|
||||
* instances for locales supported by the Java runtime itself as well
|
||||
* as for those supported by installed
|
||||
* {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
|
||||
* implementations.
|
||||
* <p>This is equivalent to calling {@link #getInstance(Locale)
|
||||
* getInstance(Locale.getDefault(Locale.Category.FORMAT))}.
|
||||
* @see java.util.Locale#getDefault(java.util.Locale.Category)
|
||||
* @see java.util.Locale.Category#FORMAT
|
||||
* @return a <code>DateFormatSymbols</code> instance.
|
||||
* @since 1.6
|
||||
*/
|
||||
public static final DateFormatSymbols getInstance() {
|
||||
return getInstance(Locale.getDefault(Locale.Category.FORMAT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <code>DateFormatSymbols</code> instance for the specified
|
||||
* locale. This method provides access to <code>DateFormatSymbols</code>
|
||||
* instances for locales supported by the Java runtime itself as well
|
||||
* as for those supported by installed
|
||||
* {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
|
||||
* implementations.
|
||||
* @param locale the given locale.
|
||||
* @return a <code>DateFormatSymbols</code> instance.
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
* @since 1.6
|
||||
*/
|
||||
public static final DateFormatSymbols getInstance(Locale locale) {
|
||||
DateFormatSymbols dfs = getProviderInstance(locale);
|
||||
if (dfs != null) {
|
||||
return dfs;
|
||||
}
|
||||
throw new RuntimeException("DateFormatSymbols instance creation failed.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a DateFormatSymbols provided by a provider or found in
|
||||
* the cache. Note that this method returns a cached instance,
|
||||
* not its clone. Therefore, the instance should never be given to
|
||||
* an application.
|
||||
*/
|
||||
static final DateFormatSymbols getInstanceRef(Locale locale) {
|
||||
DateFormatSymbols dfs = getProviderInstance(locale);
|
||||
if (dfs != null) {
|
||||
return dfs;
|
||||
}
|
||||
throw new RuntimeException("DateFormatSymbols instance creation failed.");
|
||||
}
|
||||
|
||||
private static DateFormatSymbols getProviderInstance(Locale locale) {
|
||||
LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DateFormatSymbolsProvider.class, locale);
|
||||
DateFormatSymbolsProvider provider = adapter.getDateFormatSymbolsProvider();
|
||||
DateFormatSymbols dfsyms = provider.getInstance(locale);
|
||||
if (dfsyms == null) {
|
||||
provider = LocaleProviderAdapter.forJRE().getDateFormatSymbolsProvider();
|
||||
dfsyms = provider.getInstance(locale);
|
||||
}
|
||||
return dfsyms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets era strings. For example: "AD" and "BC".
|
||||
* @return the era strings.
|
||||
*/
|
||||
public String[] getEras() {
|
||||
return Arrays.copyOf(eras, eras.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets era strings. For example: "AD" and "BC".
|
||||
* @param newEras the new era strings.
|
||||
*/
|
||||
public void setEras(String[] newEras) {
|
||||
eras = Arrays.copyOf(newEras, newEras.length);
|
||||
cachedHashCode = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets month strings. For example: "January", "February", etc.
|
||||
*
|
||||
* <p>If the language requires different forms for formatting and
|
||||
* stand-alone usages, this method returns month names in the
|
||||
* formatting form. For example, the preferred month name for
|
||||
* January in the Czech language is <em>ledna</em> in the
|
||||
* formatting form, while it is <em>leden</em> in the stand-alone
|
||||
* form. This method returns {@code "ledna"} in this case. Refer
|
||||
* to the <a href="http://unicode.org/reports/tr35/#Calendar_Elements">
|
||||
* Calendar Elements in the Unicode Locale Data Markup Language
|
||||
* (LDML) specification</a> for more details.
|
||||
*
|
||||
* @return the month strings.
|
||||
*/
|
||||
public String[] getMonths() {
|
||||
return Arrays.copyOf(months, months.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets month strings. For example: "January", "February", etc.
|
||||
* @param newMonths the new month strings.
|
||||
*/
|
||||
public void setMonths(String[] newMonths) {
|
||||
months = Arrays.copyOf(newMonths, newMonths.length);
|
||||
cachedHashCode = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets short month strings. For example: "Jan", "Feb", etc.
|
||||
*
|
||||
* <p>If the language requires different forms for formatting and
|
||||
* stand-alone usages, This method returns short month names in
|
||||
* the formatting form. For example, the preferred abbreviation
|
||||
* for January in the Catalan language is <em>de gen.</em> in the
|
||||
* formatting form, while it is <em>gen.</em> in the stand-alone
|
||||
* form. This method returns {@code "de gen."} in this case. Refer
|
||||
* to the <a href="http://unicode.org/reports/tr35/#Calendar_Elements">
|
||||
* Calendar Elements in the Unicode Locale Data Markup Language
|
||||
* (LDML) specification</a> for more details.
|
||||
*
|
||||
* @return the short month strings.
|
||||
*/
|
||||
public String[] getShortMonths() {
|
||||
return Arrays.copyOf(shortMonths, shortMonths.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets short month strings. For example: "Jan", "Feb", etc.
|
||||
* @param newShortMonths the new short month strings.
|
||||
*/
|
||||
public void setShortMonths(String[] newShortMonths) {
|
||||
shortMonths = Arrays.copyOf(newShortMonths, newShortMonths.length);
|
||||
cachedHashCode = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets weekday strings. For example: "Sunday", "Monday", etc.
|
||||
* @return the weekday strings. Use <code>Calendar.SUNDAY</code>,
|
||||
* <code>Calendar.MONDAY</code>, etc. to index the result array.
|
||||
*/
|
||||
public String[] getWeekdays() {
|
||||
return Arrays.copyOf(weekdays, weekdays.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets weekday strings. For example: "Sunday", "Monday", etc.
|
||||
* @param newWeekdays the new weekday strings. The array should
|
||||
* be indexed by <code>Calendar.SUNDAY</code>,
|
||||
* <code>Calendar.MONDAY</code>, etc.
|
||||
*/
|
||||
public void setWeekdays(String[] newWeekdays) {
|
||||
weekdays = Arrays.copyOf(newWeekdays, newWeekdays.length);
|
||||
cachedHashCode = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets short weekday strings. For example: "Sun", "Mon", etc.
|
||||
* @return the short weekday strings. Use <code>Calendar.SUNDAY</code>,
|
||||
* <code>Calendar.MONDAY</code>, etc. to index the result array.
|
||||
*/
|
||||
public String[] getShortWeekdays() {
|
||||
return Arrays.copyOf(shortWeekdays, shortWeekdays.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets short weekday strings. For example: "Sun", "Mon", etc.
|
||||
* @param newShortWeekdays the new short weekday strings. The array should
|
||||
* be indexed by <code>Calendar.SUNDAY</code>,
|
||||
* <code>Calendar.MONDAY</code>, etc.
|
||||
*/
|
||||
public void setShortWeekdays(String[] newShortWeekdays) {
|
||||
shortWeekdays = Arrays.copyOf(newShortWeekdays, newShortWeekdays.length);
|
||||
cachedHashCode = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ampm strings. For example: "AM" and "PM".
|
||||
* @return the ampm strings.
|
||||
*/
|
||||
public String[] getAmPmStrings() {
|
||||
return Arrays.copyOf(ampms, ampms.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets ampm strings. For example: "AM" and "PM".
|
||||
* @param newAmpms the new ampm strings.
|
||||
*/
|
||||
public void setAmPmStrings(String[] newAmpms) {
|
||||
ampms = Arrays.copyOf(newAmpms, newAmpms.length);
|
||||
cachedHashCode = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets time zone strings. Use of this method is discouraged; use
|
||||
* {@link java.util.TimeZone#getDisplayName() TimeZone.getDisplayName()}
|
||||
* instead.
|
||||
* <p>
|
||||
* The value returned is a
|
||||
* two-dimensional array of strings of size <em>n</em> by <em>m</em>,
|
||||
* where <em>m</em> is at least 5. Each of the <em>n</em> rows is an
|
||||
* entry containing the localized names for a single <code>TimeZone</code>.
|
||||
* Each such row contains (with <code>i</code> ranging from
|
||||
* 0..<em>n</em>-1):
|
||||
* <ul>
|
||||
* <li><code>zoneStrings[i][0]</code> - time zone ID</li>
|
||||
* <li><code>zoneStrings[i][1]</code> - long name of zone in standard
|
||||
* time</li>
|
||||
* <li><code>zoneStrings[i][2]</code> - short name of zone in
|
||||
* standard time</li>
|
||||
* <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
|
||||
* saving time</li>
|
||||
* <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
|
||||
* saving time</li>
|
||||
* </ul>
|
||||
* The zone ID is <em>not</em> localized; it's one of the valid IDs of
|
||||
* the {@link java.util.TimeZone TimeZone} class that are not
|
||||
* <a href="../util/TimeZone.html#CustomID">custom IDs</a>.
|
||||
* All other entries are localized names. If a zone does not implement
|
||||
* daylight saving time, the daylight saving time names should not be used.
|
||||
* <p>
|
||||
* If {@link #setZoneStrings(String[][]) setZoneStrings} has been called
|
||||
* on this <code>DateFormatSymbols</code> instance, then the strings
|
||||
* provided by that call are returned. Otherwise, the returned array
|
||||
* contains names provided by the Java runtime and by installed
|
||||
* {@link java.util.spi.TimeZoneNameProvider TimeZoneNameProvider}
|
||||
* implementations.
|
||||
*
|
||||
* @return the time zone strings.
|
||||
* @see #setZoneStrings(String[][])
|
||||
*/
|
||||
public String[][] getZoneStrings() {
|
||||
return getZoneStringsImpl(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets time zone strings. The argument must be a
|
||||
* two-dimensional array of strings of size <em>n</em> by <em>m</em>,
|
||||
* where <em>m</em> is at least 5. Each of the <em>n</em> rows is an
|
||||
* entry containing the localized names for a single <code>TimeZone</code>.
|
||||
* Each such row contains (with <code>i</code> ranging from
|
||||
* 0..<em>n</em>-1):
|
||||
* <ul>
|
||||
* <li><code>zoneStrings[i][0]</code> - time zone ID</li>
|
||||
* <li><code>zoneStrings[i][1]</code> - long name of zone in standard
|
||||
* time</li>
|
||||
* <li><code>zoneStrings[i][2]</code> - short name of zone in
|
||||
* standard time</li>
|
||||
* <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
|
||||
* saving time</li>
|
||||
* <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
|
||||
* saving time</li>
|
||||
* </ul>
|
||||
* The zone ID is <em>not</em> localized; it's one of the valid IDs of
|
||||
* the {@link java.util.TimeZone TimeZone} class that are not
|
||||
* <a href="../util/TimeZone.html#CustomID">custom IDs</a>.
|
||||
* All other entries are localized names.
|
||||
*
|
||||
* @param newZoneStrings the new time zone strings.
|
||||
* @exception IllegalArgumentException if the length of any row in
|
||||
* <code>newZoneStrings</code> is less than 5
|
||||
* @exception NullPointerException if <code>newZoneStrings</code> is null
|
||||
* @see #getZoneStrings()
|
||||
*/
|
||||
public void setZoneStrings(String[][] newZoneStrings) {
|
||||
String[][] aCopy = new String[newZoneStrings.length][];
|
||||
for (int i = 0; i < newZoneStrings.length; ++i) {
|
||||
int len = newZoneStrings[i].length;
|
||||
if (len < 5) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
aCopy[i] = Arrays.copyOf(newZoneStrings[i], len);
|
||||
}
|
||||
zoneStrings = aCopy;
|
||||
isZoneStringsSet = true;
|
||||
cachedHashCode = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets localized date-time pattern characters. For example: 'u', 't', etc.
|
||||
* @return the localized date-time pattern characters.
|
||||
*/
|
||||
public String getLocalPatternChars() {
|
||||
return localPatternChars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets localized date-time pattern characters. For example: 'u', 't', etc.
|
||||
* @param newLocalPatternChars the new localized date-time
|
||||
* pattern characters.
|
||||
*/
|
||||
public void setLocalPatternChars(String newLocalPatternChars) {
|
||||
// Call toString() to throw an NPE in case the argument is null
|
||||
localPatternChars = newLocalPatternChars.toString();
|
||||
cachedHashCode = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides Cloneable
|
||||
*/
|
||||
public Object clone()
|
||||
{
|
||||
try
|
||||
{
|
||||
DateFormatSymbols other = (DateFormatSymbols)super.clone();
|
||||
copyMembers(this, other);
|
||||
return other;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override hashCode.
|
||||
* Generates a hash code for the DateFormatSymbols object.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = cachedHashCode;
|
||||
if (hashCode == 0) {
|
||||
hashCode = 5;
|
||||
hashCode = 11 * hashCode + Arrays.hashCode(eras);
|
||||
hashCode = 11 * hashCode + Arrays.hashCode(months);
|
||||
hashCode = 11 * hashCode + Arrays.hashCode(shortMonths);
|
||||
hashCode = 11 * hashCode + Arrays.hashCode(weekdays);
|
||||
hashCode = 11 * hashCode + Arrays.hashCode(shortWeekdays);
|
||||
hashCode = 11 * hashCode + Arrays.hashCode(ampms);
|
||||
hashCode = 11 * hashCode + Arrays.deepHashCode(getZoneStringsWrapper());
|
||||
hashCode = 11 * hashCode + Objects.hashCode(localPatternChars);
|
||||
cachedHashCode = hashCode;
|
||||
}
|
||||
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override equals
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj) return true;
|
||||
if (obj == null || getClass() != obj.getClass()) return false;
|
||||
DateFormatSymbols that = (DateFormatSymbols) obj;
|
||||
return (Arrays.equals(eras, that.eras)
|
||||
&& Arrays.equals(months, that.months)
|
||||
&& Arrays.equals(shortMonths, that.shortMonths)
|
||||
&& Arrays.equals(weekdays, that.weekdays)
|
||||
&& Arrays.equals(shortWeekdays, that.shortWeekdays)
|
||||
&& Arrays.equals(ampms, that.ampms)
|
||||
&& Arrays.deepEquals(getZoneStringsWrapper(), that.getZoneStringsWrapper())
|
||||
&& ((localPatternChars != null
|
||||
&& localPatternChars.equals(that.localPatternChars))
|
||||
|| (localPatternChars == null
|
||||
&& that.localPatternChars == null)));
|
||||
}
|
||||
|
||||
// =======================privates===============================
|
||||
|
||||
/**
|
||||
* Useful constant for defining time zone offsets.
|
||||
*/
|
||||
static final int millisPerHour = 60*60*1000;
|
||||
|
||||
/**
|
||||
* Cache to hold DateFormatSymbols instances per Locale.
|
||||
*/
|
||||
private static final ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> cachedInstances
|
||||
= new ConcurrentHashMap<>(3);
|
||||
|
||||
private transient int lastZoneIndex = 0;
|
||||
|
||||
/**
|
||||
* Cached hash code
|
||||
*/
|
||||
transient volatile int cachedHashCode = 0;
|
||||
|
||||
/**
|
||||
* Initializes this DateFormatSymbols with the locale data. This method uses
|
||||
* a cached DateFormatSymbols instance for the given locale if available. If
|
||||
* there's no cached one, this method creates an uninitialized instance and
|
||||
* populates its fields from the resource bundle for the locale, and caches
|
||||
* the instance. Note: zoneStrings isn't initialized in this method.
|
||||
*/
|
||||
private void initializeData(Locale locale) {
|
||||
SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
|
||||
DateFormatSymbols dfs;
|
||||
if (ref == null || (dfs = ref.get()) == null) {
|
||||
if (ref != null) {
|
||||
// Remove the empty SoftReference
|
||||
cachedInstances.remove(locale, ref);
|
||||
}
|
||||
dfs = new DateFormatSymbols(false);
|
||||
|
||||
// Initialize the fields from the ResourceBundle for locale.
|
||||
LocaleProviderAdapter adapter
|
||||
= LocaleProviderAdapter.getAdapter(DateFormatSymbolsProvider.class, locale);
|
||||
// Avoid any potential recursions
|
||||
if (!(adapter instanceof ResourceBundleBasedAdapter)) {
|
||||
adapter = LocaleProviderAdapter.getResourceBundleBased();
|
||||
}
|
||||
ResourceBundle resource
|
||||
= ((ResourceBundleBasedAdapter)adapter).getLocaleData().getDateFormatData(locale);
|
||||
|
||||
dfs.locale = locale;
|
||||
// JRE and CLDR use different keys
|
||||
// JRE: Eras, short.Eras and narrow.Eras
|
||||
// CLDR: long.Eras, Eras and narrow.Eras
|
||||
if (resource.containsKey("Eras")) {
|
||||
dfs.eras = resource.getStringArray("Eras");
|
||||
} else if (resource.containsKey("long.Eras")) {
|
||||
dfs.eras = resource.getStringArray("long.Eras");
|
||||
} else if (resource.containsKey("short.Eras")) {
|
||||
dfs.eras = resource.getStringArray("short.Eras");
|
||||
}
|
||||
dfs.months = resource.getStringArray("MonthNames");
|
||||
dfs.shortMonths = resource.getStringArray("MonthAbbreviations");
|
||||
dfs.ampms = resource.getStringArray("AmPmMarkers");
|
||||
dfs.localPatternChars = resource.getString("DateTimePatternChars");
|
||||
|
||||
// Day of week names are stored in a 1-based array.
|
||||
dfs.weekdays = toOneBasedArray(resource.getStringArray("DayNames"));
|
||||
dfs.shortWeekdays = toOneBasedArray(resource.getStringArray("DayAbbreviations"));
|
||||
|
||||
// Put dfs in the cache
|
||||
ref = new SoftReference<>(dfs);
|
||||
SoftReference<DateFormatSymbols> x = cachedInstances.putIfAbsent(locale, ref);
|
||||
if (x != null) {
|
||||
DateFormatSymbols y = x.get();
|
||||
if (y == null) {
|
||||
// Replace the empty SoftReference with ref.
|
||||
cachedInstances.replace(locale, x, ref);
|
||||
} else {
|
||||
ref = x;
|
||||
dfs = y;
|
||||
}
|
||||
}
|
||||
// If the bundle's locale isn't the target locale, put another cache
|
||||
// entry for the bundle's locale.
|
||||
Locale bundleLocale = resource.getLocale();
|
||||
if (!bundleLocale.equals(locale)) {
|
||||
SoftReference<DateFormatSymbols> z
|
||||
= cachedInstances.putIfAbsent(bundleLocale, ref);
|
||||
if (z != null && z.get() == null) {
|
||||
cachedInstances.replace(bundleLocale, z, ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the field values from dfs to this instance.
|
||||
copyMembers(dfs, this);
|
||||
}
|
||||
|
||||
private static String[] toOneBasedArray(String[] src) {
|
||||
int len = src.length;
|
||||
String[] dst = new String[len + 1];
|
||||
dst[0] = "";
|
||||
for (int i = 0; i < len; i++) {
|
||||
dst[i + 1] = src[i];
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**
|
||||
* Package private: used by SimpleDateFormat
|
||||
* Gets the index for the given time zone ID to obtain the time zone
|
||||
* strings for formatting. The time zone ID is just for programmatic
|
||||
* lookup. NOT LOCALIZED!!!
|
||||
* @param ID the given time zone ID.
|
||||
* @return the index of the given time zone ID. Returns -1 if
|
||||
* the given time zone ID can't be located in the DateFormatSymbols object.
|
||||
* @see java.util.SimpleTimeZone
|
||||
*/
|
||||
final int getZoneIndex(String ID) {
|
||||
String[][] zoneStrings = getZoneStringsWrapper();
|
||||
|
||||
/*
|
||||
* getZoneIndex has been re-written for performance reasons. instead of
|
||||
* traversing the zoneStrings array every time, we cache the last used zone
|
||||
* index
|
||||
*/
|
||||
if (lastZoneIndex < zoneStrings.length && ID.equals(zoneStrings[lastZoneIndex][0])) {
|
||||
return lastZoneIndex;
|
||||
}
|
||||
|
||||
/* slow path, search entire list */
|
||||
for (int index = 0; index < zoneStrings.length; index++) {
|
||||
if (ID.equals(zoneStrings[index][0])) {
|
||||
lastZoneIndex = index;
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper method to the getZoneStrings(), which is called from inside
|
||||
* the java.text package and not to mutate the returned arrays, so that
|
||||
* it does not need to create a defensive copy.
|
||||
*/
|
||||
final String[][] getZoneStringsWrapper() {
|
||||
if (isSubclassObject()) {
|
||||
return getZoneStrings();
|
||||
} else {
|
||||
return getZoneStringsImpl(false);
|
||||
}
|
||||
}
|
||||
|
||||
private String[][] getZoneStringsImpl(boolean needsCopy) {
|
||||
if (zoneStrings == null) {
|
||||
zoneStrings = TimeZoneNameUtility.getZoneStrings(locale);
|
||||
}
|
||||
|
||||
if (!needsCopy) {
|
||||
return zoneStrings;
|
||||
}
|
||||
|
||||
int len = zoneStrings.length;
|
||||
String[][] aCopy = new String[len][];
|
||||
for (int i = 0; i < len; i++) {
|
||||
aCopy[i] = Arrays.copyOf(zoneStrings[i], zoneStrings[i].length);
|
||||
}
|
||||
return aCopy;
|
||||
}
|
||||
|
||||
private boolean isSubclassObject() {
|
||||
return !getClass().getName().equals("java.text.DateFormatSymbols");
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones all the data members from the source DateFormatSymbols to
|
||||
* the target DateFormatSymbols.
|
||||
*
|
||||
* @param src the source DateFormatSymbols.
|
||||
* @param dst the target DateFormatSymbols.
|
||||
*/
|
||||
private void copyMembers(DateFormatSymbols src, DateFormatSymbols dst)
|
||||
{
|
||||
dst.locale = src.locale;
|
||||
dst.eras = Arrays.copyOf(src.eras, src.eras.length);
|
||||
dst.months = Arrays.copyOf(src.months, src.months.length);
|
||||
dst.shortMonths = Arrays.copyOf(src.shortMonths, src.shortMonths.length);
|
||||
dst.weekdays = Arrays.copyOf(src.weekdays, src.weekdays.length);
|
||||
dst.shortWeekdays = Arrays.copyOf(src.shortWeekdays, src.shortWeekdays.length);
|
||||
dst.ampms = Arrays.copyOf(src.ampms, src.ampms.length);
|
||||
if (src.zoneStrings != null) {
|
||||
dst.zoneStrings = src.getZoneStringsImpl(true);
|
||||
} else {
|
||||
dst.zoneStrings = null;
|
||||
}
|
||||
dst.localPatternChars = src.localPatternChars;
|
||||
dst.cachedHashCode = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out the default serializable data, after ensuring the
|
||||
* <code>zoneStrings</code> field is initialized in order to make
|
||||
* sure the backward compatibility.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
private void writeObject(ObjectOutputStream stream) throws IOException {
|
||||
if (zoneStrings == null) {
|
||||
zoneStrings = TimeZoneNameUtility.getZoneStrings(locale);
|
||||
}
|
||||
stream.defaultWriteObject();
|
||||
}
|
||||
}
|
||||
4223
jdkSrc/jdk8/java/text/DecimalFormat.java
Normal file
4223
jdkSrc/jdk8/java/text/DecimalFormat.java
Normal file
File diff suppressed because it is too large
Load Diff
878
jdkSrc/jdk8/java/text/DecimalFormatSymbols.java
Normal file
878
jdkSrc/jdk8/java/text/DecimalFormatSymbols.java
Normal file
@@ -0,0 +1,878 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is copyrighted
|
||||
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
|
||||
* materials are provided under terms of a License Agreement between Taligent
|
||||
* and Sun. This technology is protected by multiple US and International
|
||||
* patents. This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.text.spi.DecimalFormatSymbolsProvider;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Currency;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import sun.util.locale.provider.LocaleProviderAdapter;
|
||||
import sun.util.locale.provider.LocaleServiceProviderPool;
|
||||
import sun.util.locale.provider.ResourceBundleBasedAdapter;
|
||||
|
||||
/**
|
||||
* This class represents the set of symbols (such as the decimal separator,
|
||||
* the grouping separator, and so on) needed by <code>DecimalFormat</code>
|
||||
* to format numbers. <code>DecimalFormat</code> creates for itself an instance of
|
||||
* <code>DecimalFormatSymbols</code> from its locale data. If you need to change any
|
||||
* of these symbols, you can get the <code>DecimalFormatSymbols</code> object from
|
||||
* your <code>DecimalFormat</code> and modify it.
|
||||
*
|
||||
* @see java.util.Locale
|
||||
* @see DecimalFormat
|
||||
* @author Mark Davis
|
||||
* @author Alan Liu
|
||||
*/
|
||||
|
||||
public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
|
||||
/**
|
||||
* Create a DecimalFormatSymbols object for the default
|
||||
* {@link java.util.Locale.Category#FORMAT FORMAT} locale.
|
||||
* This constructor can only construct instances for the locales
|
||||
* supported by the Java runtime environment, not for those
|
||||
* supported by installed
|
||||
* {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
|
||||
* implementations. For full locale coverage, use the
|
||||
* {@link #getInstance(Locale) getInstance} method.
|
||||
* <p>This is equivalent to calling
|
||||
* {@link #DecimalFormatSymbols(Locale)
|
||||
* DecimalFormatSymbols(Locale.getDefault(Locale.Category.FORMAT))}.
|
||||
* @see java.util.Locale#getDefault(java.util.Locale.Category)
|
||||
* @see java.util.Locale.Category#FORMAT
|
||||
*/
|
||||
public DecimalFormatSymbols() {
|
||||
initialize( Locale.getDefault(Locale.Category.FORMAT) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a DecimalFormatSymbols object for the given locale.
|
||||
* This constructor can only construct instances for the locales
|
||||
* supported by the Java runtime environment, not for those
|
||||
* supported by installed
|
||||
* {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
|
||||
* implementations. For full locale coverage, use the
|
||||
* {@link #getInstance(Locale) getInstance} method.
|
||||
* If the specified locale contains the {@link java.util.Locale#UNICODE_LOCALE_EXTENSION}
|
||||
* for the numbering system, the instance is initialized with the specified numbering
|
||||
* system if the JRE implementation supports it. For example,
|
||||
* <pre>
|
||||
* NumberFormat.getNumberInstance(Locale.forLanguageTag("th-TH-u-nu-thai"))
|
||||
* </pre>
|
||||
* This may return a {@code NumberFormat} instance with the Thai numbering system,
|
||||
* instead of the Latin numbering system.
|
||||
*
|
||||
* @param locale the desired locale
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
*/
|
||||
public DecimalFormatSymbols( Locale locale ) {
|
||||
initialize( locale );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all locales for which the
|
||||
* <code>getInstance</code> methods of this class can return
|
||||
* localized instances.
|
||||
* The returned array represents the union of locales supported by the Java
|
||||
* runtime and by installed
|
||||
* {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
|
||||
* implementations. It must contain at least a <code>Locale</code>
|
||||
* instance equal to {@link java.util.Locale#US Locale.US}.
|
||||
*
|
||||
* @return an array of locales for which localized
|
||||
* <code>DecimalFormatSymbols</code> instances are available.
|
||||
* @since 1.6
|
||||
*/
|
||||
public static Locale[] getAvailableLocales() {
|
||||
LocaleServiceProviderPool pool =
|
||||
LocaleServiceProviderPool.getPool(DecimalFormatSymbolsProvider.class);
|
||||
return pool.getAvailableLocales();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <code>DecimalFormatSymbols</code> instance for the default
|
||||
* locale. This method provides access to <code>DecimalFormatSymbols</code>
|
||||
* instances for locales supported by the Java runtime itself as well
|
||||
* as for those supported by installed
|
||||
* {@link java.text.spi.DecimalFormatSymbolsProvider
|
||||
* DecimalFormatSymbolsProvider} implementations.
|
||||
* <p>This is equivalent to calling
|
||||
* {@link #getInstance(Locale)
|
||||
* getInstance(Locale.getDefault(Locale.Category.FORMAT))}.
|
||||
* @see java.util.Locale#getDefault(java.util.Locale.Category)
|
||||
* @see java.util.Locale.Category#FORMAT
|
||||
* @return a <code>DecimalFormatSymbols</code> instance.
|
||||
* @since 1.6
|
||||
*/
|
||||
public static final DecimalFormatSymbols getInstance() {
|
||||
return getInstance(Locale.getDefault(Locale.Category.FORMAT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <code>DecimalFormatSymbols</code> instance for the specified
|
||||
* locale. This method provides access to <code>DecimalFormatSymbols</code>
|
||||
* instances for locales supported by the Java runtime itself as well
|
||||
* as for those supported by installed
|
||||
* {@link java.text.spi.DecimalFormatSymbolsProvider
|
||||
* DecimalFormatSymbolsProvider} implementations.
|
||||
* If the specified locale contains the {@link java.util.Locale#UNICODE_LOCALE_EXTENSION}
|
||||
* for the numbering system, the instance is initialized with the specified numbering
|
||||
* system if the JRE implementation supports it. For example,
|
||||
* <pre>
|
||||
* NumberFormat.getNumberInstance(Locale.forLanguageTag("th-TH-u-nu-thai"))
|
||||
* </pre>
|
||||
* This may return a {@code NumberFormat} instance with the Thai numbering system,
|
||||
* instead of the Latin numbering system.
|
||||
*
|
||||
* @param locale the desired locale.
|
||||
* @return a <code>DecimalFormatSymbols</code> instance.
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
* @since 1.6
|
||||
*/
|
||||
public static final DecimalFormatSymbols getInstance(Locale locale) {
|
||||
LocaleProviderAdapter adapter;
|
||||
adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, locale);
|
||||
DecimalFormatSymbolsProvider provider = adapter.getDecimalFormatSymbolsProvider();
|
||||
DecimalFormatSymbols dfsyms = provider.getInstance(locale);
|
||||
if (dfsyms == null) {
|
||||
provider = LocaleProviderAdapter.forJRE().getDecimalFormatSymbolsProvider();
|
||||
dfsyms = provider.getInstance(locale);
|
||||
}
|
||||
return dfsyms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character used for zero. Different for Arabic, etc.
|
||||
*
|
||||
* @return the character used for zero
|
||||
*/
|
||||
public char getZeroDigit() {
|
||||
return zeroDigit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the character used for zero. Different for Arabic, etc.
|
||||
*
|
||||
* @param zeroDigit the character used for zero
|
||||
*/
|
||||
public void setZeroDigit(char zeroDigit) {
|
||||
this.zeroDigit = zeroDigit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character used for thousands separator. Different for French, etc.
|
||||
*
|
||||
* @return the grouping separator
|
||||
*/
|
||||
public char getGroupingSeparator() {
|
||||
return groupingSeparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the character used for thousands separator. Different for French, etc.
|
||||
*
|
||||
* @param groupingSeparator the grouping separator
|
||||
*/
|
||||
public void setGroupingSeparator(char groupingSeparator) {
|
||||
this.groupingSeparator = groupingSeparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character used for decimal sign. Different for French, etc.
|
||||
*
|
||||
* @return the character used for decimal sign
|
||||
*/
|
||||
public char getDecimalSeparator() {
|
||||
return decimalSeparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the character used for decimal sign. Different for French, etc.
|
||||
*
|
||||
* @param decimalSeparator the character used for decimal sign
|
||||
*/
|
||||
public void setDecimalSeparator(char decimalSeparator) {
|
||||
this.decimalSeparator = decimalSeparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character used for per mille sign. Different for Arabic, etc.
|
||||
*
|
||||
* @return the character used for per mille sign
|
||||
*/
|
||||
public char getPerMill() {
|
||||
return perMill;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the character used for per mille sign. Different for Arabic, etc.
|
||||
*
|
||||
* @param perMill the character used for per mille sign
|
||||
*/
|
||||
public void setPerMill(char perMill) {
|
||||
this.perMill = perMill;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character used for percent sign. Different for Arabic, etc.
|
||||
*
|
||||
* @return the character used for percent sign
|
||||
*/
|
||||
public char getPercent() {
|
||||
return percent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the character used for percent sign. Different for Arabic, etc.
|
||||
*
|
||||
* @param percent the character used for percent sign
|
||||
*/
|
||||
public void setPercent(char percent) {
|
||||
this.percent = percent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character used for a digit in a pattern.
|
||||
*
|
||||
* @return the character used for a digit in a pattern
|
||||
*/
|
||||
public char getDigit() {
|
||||
return digit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the character used for a digit in a pattern.
|
||||
*
|
||||
* @param digit the character used for a digit in a pattern
|
||||
*/
|
||||
public void setDigit(char digit) {
|
||||
this.digit = digit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character used to separate positive and negative subpatterns
|
||||
* in a pattern.
|
||||
*
|
||||
* @return the pattern separator
|
||||
*/
|
||||
public char getPatternSeparator() {
|
||||
return patternSeparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the character used to separate positive and negative subpatterns
|
||||
* in a pattern.
|
||||
*
|
||||
* @param patternSeparator the pattern separator
|
||||
*/
|
||||
public void setPatternSeparator(char patternSeparator) {
|
||||
this.patternSeparator = patternSeparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string used to represent infinity. Almost always left
|
||||
* unchanged.
|
||||
*
|
||||
* @return the string representing infinity
|
||||
*/
|
||||
public String getInfinity() {
|
||||
return infinity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the string used to represent infinity. Almost always left
|
||||
* unchanged.
|
||||
*
|
||||
* @param infinity the string representing infinity
|
||||
*/
|
||||
public void setInfinity(String infinity) {
|
||||
this.infinity = infinity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string used to represent "not a number". Almost always left
|
||||
* unchanged.
|
||||
*
|
||||
* @return the string representing "not a number"
|
||||
*/
|
||||
public String getNaN() {
|
||||
return NaN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the string used to represent "not a number". Almost always left
|
||||
* unchanged.
|
||||
*
|
||||
* @param NaN the string representing "not a number"
|
||||
*/
|
||||
public void setNaN(String NaN) {
|
||||
this.NaN = NaN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character used to represent minus sign. If no explicit
|
||||
* negative format is specified, one is formed by prefixing
|
||||
* minusSign to the positive format.
|
||||
*
|
||||
* @return the character representing minus sign
|
||||
*/
|
||||
public char getMinusSign() {
|
||||
return minusSign;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the character used to represent minus sign. If no explicit
|
||||
* negative format is specified, one is formed by prefixing
|
||||
* minusSign to the positive format.
|
||||
*
|
||||
* @param minusSign the character representing minus sign
|
||||
*/
|
||||
public void setMinusSign(char minusSign) {
|
||||
this.minusSign = minusSign;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currency symbol for the currency of these
|
||||
* DecimalFormatSymbols in their locale.
|
||||
*
|
||||
* @return the currency symbol
|
||||
* @since 1.2
|
||||
*/
|
||||
public String getCurrencySymbol()
|
||||
{
|
||||
return currencySymbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the currency symbol for the currency of these
|
||||
* DecimalFormatSymbols in their locale.
|
||||
*
|
||||
* @param currency the currency symbol
|
||||
* @since 1.2
|
||||
*/
|
||||
public void setCurrencySymbol(String currency)
|
||||
{
|
||||
currencySymbol = currency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ISO 4217 currency code of the currency of these
|
||||
* DecimalFormatSymbols.
|
||||
*
|
||||
* @return the currency code
|
||||
* @since 1.2
|
||||
*/
|
||||
public String getInternationalCurrencySymbol()
|
||||
{
|
||||
return intlCurrencySymbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ISO 4217 currency code of the currency of these
|
||||
* DecimalFormatSymbols.
|
||||
* If the currency code is valid (as defined by
|
||||
* {@link java.util.Currency#getInstance(java.lang.String) Currency.getInstance}),
|
||||
* this also sets the currency attribute to the corresponding Currency
|
||||
* instance and the currency symbol attribute to the currency's symbol
|
||||
* in the DecimalFormatSymbols' locale. If the currency code is not valid,
|
||||
* then the currency attribute is set to null and the currency symbol
|
||||
* attribute is not modified.
|
||||
*
|
||||
* @param currencyCode the currency code
|
||||
* @see #setCurrency
|
||||
* @see #setCurrencySymbol
|
||||
* @since 1.2
|
||||
*/
|
||||
public void setInternationalCurrencySymbol(String currencyCode)
|
||||
{
|
||||
intlCurrencySymbol = currencyCode;
|
||||
currency = null;
|
||||
if (currencyCode != null) {
|
||||
try {
|
||||
currency = Currency.getInstance(currencyCode);
|
||||
currencySymbol = currency.getSymbol();
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currency of these DecimalFormatSymbols. May be null if the
|
||||
* currency symbol attribute was previously set to a value that's not
|
||||
* a valid ISO 4217 currency code.
|
||||
*
|
||||
* @return the currency used, or null
|
||||
* @since 1.4
|
||||
*/
|
||||
public Currency getCurrency() {
|
||||
return currency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the currency of these DecimalFormatSymbols.
|
||||
* This also sets the currency symbol attribute to the currency's symbol
|
||||
* in the DecimalFormatSymbols' locale, and the international currency
|
||||
* symbol attribute to the currency's ISO 4217 currency code.
|
||||
*
|
||||
* @param currency the new currency to be used
|
||||
* @exception NullPointerException if <code>currency</code> is null
|
||||
* @since 1.4
|
||||
* @see #setCurrencySymbol
|
||||
* @see #setInternationalCurrencySymbol
|
||||
*/
|
||||
public void setCurrency(Currency currency) {
|
||||
if (currency == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.currency = currency;
|
||||
intlCurrencySymbol = currency.getCurrencyCode();
|
||||
currencySymbol = currency.getSymbol(locale);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the monetary decimal separator.
|
||||
*
|
||||
* @return the monetary decimal separator
|
||||
* @since 1.2
|
||||
*/
|
||||
public char getMonetaryDecimalSeparator()
|
||||
{
|
||||
return monetarySeparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the monetary decimal separator.
|
||||
*
|
||||
* @param sep the monetary decimal separator
|
||||
* @since 1.2
|
||||
*/
|
||||
public void setMonetaryDecimalSeparator(char sep)
|
||||
{
|
||||
monetarySeparator = sep;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
// BEGIN Package Private methods ... to be made public later
|
||||
//------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the character used to separate the mantissa from the exponent.
|
||||
*/
|
||||
char getExponentialSymbol()
|
||||
{
|
||||
return exponential;
|
||||
}
|
||||
/**
|
||||
* Returns the string used to separate the mantissa from the exponent.
|
||||
* Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
|
||||
*
|
||||
* @return the exponent separator string
|
||||
* @see #setExponentSeparator(java.lang.String)
|
||||
* @since 1.6
|
||||
*/
|
||||
public String getExponentSeparator()
|
||||
{
|
||||
return exponentialSeparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the character used to separate the mantissa from the exponent.
|
||||
*/
|
||||
void setExponentialSymbol(char exp)
|
||||
{
|
||||
exponential = exp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the string used to separate the mantissa from the exponent.
|
||||
* Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
|
||||
*
|
||||
* @param exp the exponent separator string
|
||||
* @exception NullPointerException if <code>exp</code> is null
|
||||
* @see #getExponentSeparator()
|
||||
* @since 1.6
|
||||
*/
|
||||
public void setExponentSeparator(String exp)
|
||||
{
|
||||
if (exp == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
exponentialSeparator = exp;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
// END Package Private methods ... to be made public later
|
||||
//------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Standard override.
|
||||
*/
|
||||
@Override
|
||||
public Object clone() {
|
||||
try {
|
||||
return (DecimalFormatSymbols)super.clone();
|
||||
// other fields are bit-copied
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override equals.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) return false;
|
||||
if (this == obj) return true;
|
||||
if (getClass() != obj.getClass()) return false;
|
||||
DecimalFormatSymbols other = (DecimalFormatSymbols) obj;
|
||||
return (zeroDigit == other.zeroDigit &&
|
||||
groupingSeparator == other.groupingSeparator &&
|
||||
decimalSeparator == other.decimalSeparator &&
|
||||
percent == other.percent &&
|
||||
perMill == other.perMill &&
|
||||
digit == other.digit &&
|
||||
minusSign == other.minusSign &&
|
||||
patternSeparator == other.patternSeparator &&
|
||||
infinity.equals(other.infinity) &&
|
||||
NaN.equals(other.NaN) &&
|
||||
currencySymbol.equals(other.currencySymbol) &&
|
||||
intlCurrencySymbol.equals(other.intlCurrencySymbol) &&
|
||||
currency == other.currency &&
|
||||
monetarySeparator == other.monetarySeparator &&
|
||||
exponentialSeparator.equals(other.exponentialSeparator) &&
|
||||
locale.equals(other.locale));
|
||||
}
|
||||
|
||||
/**
|
||||
* Override hashCode.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = zeroDigit;
|
||||
result = result * 37 + groupingSeparator;
|
||||
result = result * 37 + decimalSeparator;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the symbols from the FormatData resource bundle.
|
||||
*/
|
||||
private void initialize( Locale locale ) {
|
||||
this.locale = locale;
|
||||
|
||||
// get resource bundle data
|
||||
LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, locale);
|
||||
// Avoid potential recursions
|
||||
if (!(adapter instanceof ResourceBundleBasedAdapter)) {
|
||||
adapter = LocaleProviderAdapter.getResourceBundleBased();
|
||||
}
|
||||
Object[] data = adapter.getLocaleResources(locale).getDecimalFormatSymbolsData();
|
||||
String[] numberElements = (String[]) data[0];
|
||||
|
||||
decimalSeparator = numberElements[0].charAt(0);
|
||||
groupingSeparator = numberElements[1].charAt(0);
|
||||
patternSeparator = numberElements[2].charAt(0);
|
||||
percent = numberElements[3].charAt(0);
|
||||
zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc.
|
||||
digit = numberElements[5].charAt(0);
|
||||
minusSign = numberElements[6].charAt(0);
|
||||
exponential = numberElements[7].charAt(0);
|
||||
exponentialSeparator = numberElements[7]; //string representation new since 1.6
|
||||
perMill = numberElements[8].charAt(0);
|
||||
infinity = numberElements[9];
|
||||
NaN = numberElements[10];
|
||||
|
||||
// Try to obtain the currency used in the locale's country.
|
||||
// Check for empty country string separately because it's a valid
|
||||
// country ID for Locale (and used for the C locale), but not a valid
|
||||
// ISO 3166 country code, and exceptions are expensive.
|
||||
if (locale.getCountry().length() > 0) {
|
||||
try {
|
||||
currency = Currency.getInstance(locale);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// use default values below for compatibility
|
||||
}
|
||||
}
|
||||
if (currency != null) {
|
||||
intlCurrencySymbol = currency.getCurrencyCode();
|
||||
if (data[1] != null && data[1] == intlCurrencySymbol) {
|
||||
currencySymbol = (String) data[2];
|
||||
} else {
|
||||
currencySymbol = currency.getSymbol(locale);
|
||||
data[1] = intlCurrencySymbol;
|
||||
data[2] = currencySymbol;
|
||||
}
|
||||
} else {
|
||||
// default values
|
||||
intlCurrencySymbol = "XXX";
|
||||
try {
|
||||
currency = Currency.getInstance(intlCurrencySymbol);
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
currencySymbol = "\u00A4";
|
||||
}
|
||||
// Currently the monetary decimal separator is the same as the
|
||||
// standard decimal separator for all locales that we support.
|
||||
// If that changes, add a new entry to NumberElements.
|
||||
monetarySeparator = decimalSeparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the default serializable fields, provides default values for objects
|
||||
* in older serial versions, and initializes non-serializable fields.
|
||||
* If <code>serialVersionOnStream</code>
|
||||
* is less than 1, initializes <code>monetarySeparator</code> to be
|
||||
* the same as <code>decimalSeparator</code> and <code>exponential</code>
|
||||
* to be 'E'.
|
||||
* If <code>serialVersionOnStream</code> is less than 2,
|
||||
* initializes <code>locale</code>to the root locale, and initializes
|
||||
* If <code>serialVersionOnStream</code> is less than 3, it initializes
|
||||
* <code>exponentialSeparator</code> using <code>exponential</code>.
|
||||
* Sets <code>serialVersionOnStream</code> back to the maximum allowed value so that
|
||||
* default serialization will work properly if this object is streamed out again.
|
||||
* Initializes the currency from the intlCurrencySymbol field.
|
||||
*
|
||||
* @since JDK 1.1.6
|
||||
*/
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
if (serialVersionOnStream < 1) {
|
||||
// Didn't have monetarySeparator or exponential field;
|
||||
// use defaults.
|
||||
monetarySeparator = decimalSeparator;
|
||||
exponential = 'E';
|
||||
}
|
||||
if (serialVersionOnStream < 2) {
|
||||
// didn't have locale; use root locale
|
||||
locale = Locale.ROOT;
|
||||
}
|
||||
if (serialVersionOnStream < 3) {
|
||||
// didn't have exponentialSeparator. Create one using exponential
|
||||
exponentialSeparator = Character.toString(exponential);
|
||||
}
|
||||
serialVersionOnStream = currentSerialVersion;
|
||||
|
||||
if (intlCurrencySymbol != null) {
|
||||
try {
|
||||
currency = Currency.getInstance(intlCurrencySymbol);
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Character used for zero.
|
||||
*
|
||||
* @serial
|
||||
* @see #getZeroDigit
|
||||
*/
|
||||
private char zeroDigit;
|
||||
|
||||
/**
|
||||
* Character used for thousands separator.
|
||||
*
|
||||
* @serial
|
||||
* @see #getGroupingSeparator
|
||||
*/
|
||||
private char groupingSeparator;
|
||||
|
||||
/**
|
||||
* Character used for decimal sign.
|
||||
*
|
||||
* @serial
|
||||
* @see #getDecimalSeparator
|
||||
*/
|
||||
private char decimalSeparator;
|
||||
|
||||
/**
|
||||
* Character used for per mille sign.
|
||||
*
|
||||
* @serial
|
||||
* @see #getPerMill
|
||||
*/
|
||||
private char perMill;
|
||||
|
||||
/**
|
||||
* Character used for percent sign.
|
||||
* @serial
|
||||
* @see #getPercent
|
||||
*/
|
||||
private char percent;
|
||||
|
||||
/**
|
||||
* Character used for a digit in a pattern.
|
||||
*
|
||||
* @serial
|
||||
* @see #getDigit
|
||||
*/
|
||||
private char digit;
|
||||
|
||||
/**
|
||||
* Character used to separate positive and negative subpatterns
|
||||
* in a pattern.
|
||||
*
|
||||
* @serial
|
||||
* @see #getPatternSeparator
|
||||
*/
|
||||
private char patternSeparator;
|
||||
|
||||
/**
|
||||
* String used to represent infinity.
|
||||
* @serial
|
||||
* @see #getInfinity
|
||||
*/
|
||||
private String infinity;
|
||||
|
||||
/**
|
||||
* String used to represent "not a number".
|
||||
* @serial
|
||||
* @see #getNaN
|
||||
*/
|
||||
private String NaN;
|
||||
|
||||
/**
|
||||
* Character used to represent minus sign.
|
||||
* @serial
|
||||
* @see #getMinusSign
|
||||
*/
|
||||
private char minusSign;
|
||||
|
||||
/**
|
||||
* String denoting the local currency, e.g. "$".
|
||||
* @serial
|
||||
* @see #getCurrencySymbol
|
||||
*/
|
||||
private String currencySymbol;
|
||||
|
||||
/**
|
||||
* ISO 4217 currency code denoting the local currency, e.g. "USD".
|
||||
* @serial
|
||||
* @see #getInternationalCurrencySymbol
|
||||
*/
|
||||
private String intlCurrencySymbol;
|
||||
|
||||
/**
|
||||
* The decimal separator used when formatting currency values.
|
||||
* @serial
|
||||
* @since JDK 1.1.6
|
||||
* @see #getMonetaryDecimalSeparator
|
||||
*/
|
||||
private char monetarySeparator; // Field new in JDK 1.1.6
|
||||
|
||||
/**
|
||||
* The character used to distinguish the exponent in a number formatted
|
||||
* in exponential notation, e.g. 'E' for a number such as "1.23E45".
|
||||
* <p>
|
||||
* Note that the public API provides no way to set this field,
|
||||
* even though it is supported by the implementation and the stream format.
|
||||
* The intent is that this will be added to the API in the future.
|
||||
*
|
||||
* @serial
|
||||
* @since JDK 1.1.6
|
||||
*/
|
||||
private char exponential; // Field new in JDK 1.1.6
|
||||
|
||||
/**
|
||||
* The string used to separate the mantissa from the exponent.
|
||||
* Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
|
||||
* <p>
|
||||
* If both <code>exponential</code> and <code>exponentialSeparator</code>
|
||||
* exist, this <code>exponentialSeparator</code> has the precedence.
|
||||
*
|
||||
* @serial
|
||||
* @since 1.6
|
||||
*/
|
||||
private String exponentialSeparator; // Field new in JDK 1.6
|
||||
|
||||
/**
|
||||
* The locale of these currency format symbols.
|
||||
*
|
||||
* @serial
|
||||
* @since 1.4
|
||||
*/
|
||||
private Locale locale;
|
||||
|
||||
// currency; only the ISO code is serialized.
|
||||
private transient Currency currency;
|
||||
|
||||
// Proclaim JDK 1.1 FCS compatibility
|
||||
static final long serialVersionUID = 5772796243397350300L;
|
||||
|
||||
// The internal serial version which says which version was written
|
||||
// - 0 (default) for version up to JDK 1.1.5
|
||||
// - 1 for version from JDK 1.1.6, which includes two new fields:
|
||||
// monetarySeparator and exponential.
|
||||
// - 2 for version from J2SE 1.4, which includes locale field.
|
||||
// - 3 for version from J2SE 1.6, which includes exponentialSeparator field.
|
||||
private static final int currentSerialVersion = 3;
|
||||
|
||||
/**
|
||||
* Describes the version of <code>DecimalFormatSymbols</code> present on the stream.
|
||||
* Possible values are:
|
||||
* <ul>
|
||||
* <li><b>0</b> (or uninitialized): versions prior to JDK 1.1.6.
|
||||
*
|
||||
* <li><b>1</b>: Versions written by JDK 1.1.6 or later, which include
|
||||
* two new fields: <code>monetarySeparator</code> and <code>exponential</code>.
|
||||
* <li><b>2</b>: Versions written by J2SE 1.4 or later, which include a
|
||||
* new <code>locale</code> field.
|
||||
* <li><b>3</b>: Versions written by J2SE 1.6 or later, which include a
|
||||
* new <code>exponentialSeparator</code> field.
|
||||
* </ul>
|
||||
* When streaming out a <code>DecimalFormatSymbols</code>, the most recent format
|
||||
* (corresponding to the highest allowable <code>serialVersionOnStream</code>)
|
||||
* is always written.
|
||||
*
|
||||
* @serial
|
||||
* @since JDK 1.1.6
|
||||
*/
|
||||
private int serialVersionOnStream = currentSerialVersion;
|
||||
}
|
||||
823
jdkSrc/jdk8/java/text/DigitList.java
Normal file
823
jdkSrc/jdk8/java/text/DigitList.java
Normal file
@@ -0,0 +1,823 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is copyrighted
|
||||
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
|
||||
* materials are provided under terms of a License Agreement between Taligent
|
||||
* and Sun. This technology is protected by multiple US and International
|
||||
* patents. This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.math.RoundingMode;
|
||||
import sun.misc.FloatingDecimal;
|
||||
|
||||
/**
|
||||
* Digit List. Private to DecimalFormat.
|
||||
* Handles the transcoding
|
||||
* between numeric values and strings of characters. Only handles
|
||||
* non-negative numbers. The division of labor between DigitList and
|
||||
* DecimalFormat is that DigitList handles the radix 10 representation
|
||||
* issues; DecimalFormat handles the locale-specific issues such as
|
||||
* positive/negative, grouping, decimal point, currency, and so on.
|
||||
*
|
||||
* A DigitList is really a representation of a floating point value.
|
||||
* It may be an integer value; we assume that a double has sufficient
|
||||
* precision to represent all digits of a long.
|
||||
*
|
||||
* The DigitList representation consists of a string of characters,
|
||||
* which are the digits radix 10, from '0' to '9'. It also has a radix
|
||||
* 10 exponent associated with it. The value represented by a DigitList
|
||||
* object can be computed by mulitplying the fraction f, where 0 <= f < 1,
|
||||
* derived by placing all the digits of the list to the right of the
|
||||
* decimal point, by 10^exponent.
|
||||
*
|
||||
* @see Locale
|
||||
* @see Format
|
||||
* @see NumberFormat
|
||||
* @see DecimalFormat
|
||||
* @see ChoiceFormat
|
||||
* @see MessageFormat
|
||||
* @author Mark Davis, Alan Liu
|
||||
*/
|
||||
final class DigitList implements Cloneable {
|
||||
/**
|
||||
* The maximum number of significant digits in an IEEE 754 double, that
|
||||
* is, in a Java double. This must not be increased, or garbage digits
|
||||
* will be generated, and should not be decreased, or accuracy will be lost.
|
||||
*/
|
||||
public static final int MAX_COUNT = 19; // == Long.toString(Long.MAX_VALUE).length()
|
||||
|
||||
/**
|
||||
* These data members are intentionally public and can be set directly.
|
||||
*
|
||||
* The value represented is given by placing the decimal point before
|
||||
* digits[decimalAt]. If decimalAt is < 0, then leading zeros between
|
||||
* the decimal point and the first nonzero digit are implied. If decimalAt
|
||||
* is > count, then trailing zeros between the digits[count-1] and the
|
||||
* decimal point are implied.
|
||||
*
|
||||
* Equivalently, the represented value is given by f * 10^decimalAt. Here
|
||||
* f is a value 0.1 <= f < 1 arrived at by placing the digits in Digits to
|
||||
* the right of the decimal.
|
||||
*
|
||||
* DigitList is normalized, so if it is non-zero, figits[0] is non-zero. We
|
||||
* don't allow denormalized numbers because our exponent is effectively of
|
||||
* unlimited magnitude. The count value contains the number of significant
|
||||
* digits present in digits[].
|
||||
*
|
||||
* Zero is represented by any DigitList with count == 0 or with each digits[i]
|
||||
* for all i <= count == '0'.
|
||||
*/
|
||||
public int decimalAt = 0;
|
||||
public int count = 0;
|
||||
public char[] digits = new char[MAX_COUNT];
|
||||
|
||||
private char[] data;
|
||||
private RoundingMode roundingMode = RoundingMode.HALF_EVEN;
|
||||
private boolean isNegative = false;
|
||||
|
||||
/**
|
||||
* Return true if the represented number is zero.
|
||||
*/
|
||||
boolean isZero() {
|
||||
for (int i=0; i < count; ++i) {
|
||||
if (digits[i] != '0') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the rounding mode
|
||||
*/
|
||||
void setRoundingMode(RoundingMode r) {
|
||||
roundingMode = r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears out the digits.
|
||||
* Use before appending them.
|
||||
* Typically, you set a series of digits with append, then at the point
|
||||
* you hit the decimal point, you set myDigitList.decimalAt = myDigitList.count;
|
||||
* then go on appending digits.
|
||||
*/
|
||||
public void clear () {
|
||||
decimalAt = 0;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a digit to the list, extending the list when necessary.
|
||||
*/
|
||||
public void append(char digit) {
|
||||
if (count == digits.length) {
|
||||
char[] data = new char[count + 100];
|
||||
System.arraycopy(digits, 0, data, 0, count);
|
||||
digits = data;
|
||||
}
|
||||
digits[count++] = digit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility routine to get the value of the digit list
|
||||
* If (count == 0) this throws a NumberFormatException, which
|
||||
* mimics Long.parseLong().
|
||||
*/
|
||||
public final double getDouble() {
|
||||
if (count == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
StringBuffer temp = getStringBuffer();
|
||||
temp.append('.');
|
||||
temp.append(digits, 0, count);
|
||||
temp.append('E');
|
||||
temp.append(decimalAt);
|
||||
return Double.parseDouble(temp.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility routine to get the value of the digit list.
|
||||
* If (count == 0) this returns 0, unlike Long.parseLong().
|
||||
*/
|
||||
public final long getLong() {
|
||||
// for now, simple implementation; later, do proper IEEE native stuff
|
||||
|
||||
if (count == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We have to check for this, because this is the one NEGATIVE value
|
||||
// we represent. If we tried to just pass the digits off to parseLong,
|
||||
// we'd get a parse failure.
|
||||
if (isLongMIN_VALUE()) {
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
StringBuffer temp = getStringBuffer();
|
||||
temp.append(digits, 0, count);
|
||||
for (int i = count; i < decimalAt; ++i) {
|
||||
temp.append('0');
|
||||
}
|
||||
return Long.parseLong(temp.toString());
|
||||
}
|
||||
|
||||
public final BigDecimal getBigDecimal() {
|
||||
if (count == 0) {
|
||||
if (decimalAt == 0) {
|
||||
return BigDecimal.ZERO;
|
||||
} else {
|
||||
return new BigDecimal("0E" + decimalAt);
|
||||
}
|
||||
}
|
||||
|
||||
if (decimalAt == count) {
|
||||
return new BigDecimal(digits, 0, count);
|
||||
} else {
|
||||
return new BigDecimal(digits, 0, count).scaleByPowerOfTen(decimalAt - count);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the number represented by this object can fit into
|
||||
* a long.
|
||||
* @param isPositive true if this number should be regarded as positive
|
||||
* @param ignoreNegativeZero true if -0 should be regarded as identical to
|
||||
* +0; otherwise they are considered distinct
|
||||
* @return true if this number fits into a Java long
|
||||
*/
|
||||
boolean fitsIntoLong(boolean isPositive, boolean ignoreNegativeZero) {
|
||||
// Figure out if the result will fit in a long. We have to
|
||||
// first look for nonzero digits after the decimal point;
|
||||
// then check the size. If the digit count is 18 or less, then
|
||||
// the value can definitely be represented as a long. If it is 19
|
||||
// then it may be too large.
|
||||
|
||||
// Trim trailing zeros. This does not change the represented value.
|
||||
while (count > 0 && digits[count - 1] == '0') {
|
||||
--count;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
// Positive zero fits into a long, but negative zero can only
|
||||
// be represented as a double. - bug 4162852
|
||||
return isPositive || ignoreNegativeZero;
|
||||
}
|
||||
|
||||
if (decimalAt < count || decimalAt > MAX_COUNT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (decimalAt < MAX_COUNT) return true;
|
||||
|
||||
// At this point we have decimalAt == count, and count == MAX_COUNT.
|
||||
// The number will overflow if it is larger than 9223372036854775807
|
||||
// or smaller than -9223372036854775808.
|
||||
for (int i=0; i<count; ++i) {
|
||||
char dig = digits[i], max = LONG_MIN_REP[i];
|
||||
if (dig > max) return false;
|
||||
if (dig < max) return true;
|
||||
}
|
||||
|
||||
// At this point the first count digits match. If decimalAt is less
|
||||
// than count, then the remaining digits are zero, and we return true.
|
||||
if (count < decimalAt) return true;
|
||||
|
||||
// Now we have a representation of Long.MIN_VALUE, without the leading
|
||||
// negative sign. If this represents a positive value, then it does
|
||||
// not fit; otherwise it fits.
|
||||
return !isPositive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the digit list to a representation of the given double value.
|
||||
* This method supports fixed-point notation.
|
||||
* @param isNegative Boolean value indicating whether the number is negative.
|
||||
* @param source Value to be converted; must not be Inf, -Inf, Nan,
|
||||
* or a value <= 0.
|
||||
* @param maximumFractionDigits The most fractional digits which should
|
||||
* be converted.
|
||||
*/
|
||||
final void set(boolean isNegative, double source, int maximumFractionDigits) {
|
||||
set(isNegative, source, maximumFractionDigits, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the digit list to a representation of the given double value.
|
||||
* This method supports both fixed-point and exponential notation.
|
||||
* @param isNegative Boolean value indicating whether the number is negative.
|
||||
* @param source Value to be converted; must not be Inf, -Inf, Nan,
|
||||
* or a value <= 0.
|
||||
* @param maximumDigits The most fractional or total digits which should
|
||||
* be converted.
|
||||
* @param fixedPoint If true, then maximumDigits is the maximum
|
||||
* fractional digits to be converted. If false, total digits.
|
||||
*/
|
||||
final void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) {
|
||||
|
||||
FloatingDecimal.BinaryToASCIIConverter fdConverter = FloatingDecimal.getBinaryToASCIIConverter(source);
|
||||
boolean hasBeenRoundedUp = fdConverter.digitsRoundedUp();
|
||||
boolean valueExactAsDecimal = fdConverter.decimalDigitsExact();
|
||||
assert !fdConverter.isExceptional();
|
||||
String digitsString = fdConverter.toJavaFormatString();
|
||||
|
||||
set(isNegative, digitsString,
|
||||
hasBeenRoundedUp, valueExactAsDecimal,
|
||||
maximumDigits, fixedPoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a representation of the form DDDDD, DDDDD.DDDDD, or
|
||||
* DDDDDE+/-DDDDD.
|
||||
* @param roundedUp whether or not rounding up has already happened.
|
||||
* @param valueExactAsDecimal whether or not collected digits provide
|
||||
* an exact decimal representation of the value.
|
||||
*/
|
||||
private void set(boolean isNegative, String s,
|
||||
boolean roundedUp, boolean valueExactAsDecimal,
|
||||
int maximumDigits, boolean fixedPoint) {
|
||||
|
||||
this.isNegative = isNegative;
|
||||
int len = s.length();
|
||||
char[] source = getDataChars(len);
|
||||
s.getChars(0, len, source, 0);
|
||||
|
||||
decimalAt = -1;
|
||||
count = 0;
|
||||
int exponent = 0;
|
||||
// Number of zeros between decimal point and first non-zero digit after
|
||||
// decimal point, for numbers < 1.
|
||||
int leadingZerosAfterDecimal = 0;
|
||||
boolean nonZeroDigitSeen = false;
|
||||
|
||||
for (int i = 0; i < len; ) {
|
||||
char c = source[i++];
|
||||
if (c == '.') {
|
||||
decimalAt = count;
|
||||
} else if (c == 'e' || c == 'E') {
|
||||
exponent = parseInt(source, i, len);
|
||||
break;
|
||||
} else {
|
||||
if (!nonZeroDigitSeen) {
|
||||
nonZeroDigitSeen = (c != '0');
|
||||
if (!nonZeroDigitSeen && decimalAt != -1)
|
||||
++leadingZerosAfterDecimal;
|
||||
}
|
||||
if (nonZeroDigitSeen) {
|
||||
digits[count++] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (decimalAt == -1) {
|
||||
decimalAt = count;
|
||||
}
|
||||
if (nonZeroDigitSeen) {
|
||||
decimalAt += exponent - leadingZerosAfterDecimal;
|
||||
}
|
||||
|
||||
if (fixedPoint) {
|
||||
// The negative of the exponent represents the number of leading
|
||||
// zeros between the decimal and the first non-zero digit, for
|
||||
// a value < 0.1 (e.g., for 0.00123, -decimalAt == 2). If this
|
||||
// is more than the maximum fraction digits, then we have an underflow
|
||||
// for the printed representation.
|
||||
if (-decimalAt > maximumDigits) {
|
||||
// Handle an underflow to zero when we round something like
|
||||
// 0.0009 to 2 fractional digits.
|
||||
count = 0;
|
||||
return;
|
||||
} else if (-decimalAt == maximumDigits) {
|
||||
// If we round 0.0009 to 3 fractional digits, then we have to
|
||||
// create a new one digit in the least significant location.
|
||||
if (shouldRoundUp(0, roundedUp, valueExactAsDecimal)) {
|
||||
count = 1;
|
||||
++decimalAt;
|
||||
digits[0] = '1';
|
||||
} else {
|
||||
count = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// else fall through
|
||||
}
|
||||
|
||||
// Eliminate trailing zeros.
|
||||
while (count > 1 && digits[count - 1] == '0') {
|
||||
--count;
|
||||
}
|
||||
|
||||
// Eliminate digits beyond maximum digits to be displayed.
|
||||
// Round up if appropriate.
|
||||
round(fixedPoint ? (maximumDigits + decimalAt) : maximumDigits,
|
||||
roundedUp, valueExactAsDecimal);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Round the representation to the given number of digits.
|
||||
* @param maximumDigits The maximum number of digits to be shown.
|
||||
* @param alreadyRounded whether or not rounding up has already happened.
|
||||
* @param valueExactAsDecimal whether or not collected digits provide
|
||||
* an exact decimal representation of the value.
|
||||
*
|
||||
* Upon return, count will be less than or equal to maximumDigits.
|
||||
*/
|
||||
private final void round(int maximumDigits,
|
||||
boolean alreadyRounded,
|
||||
boolean valueExactAsDecimal) {
|
||||
// Eliminate digits beyond maximum digits to be displayed.
|
||||
// Round up if appropriate.
|
||||
if (maximumDigits >= 0 && maximumDigits < count) {
|
||||
if (shouldRoundUp(maximumDigits, alreadyRounded, valueExactAsDecimal)) {
|
||||
// Rounding up involved incrementing digits from LSD to MSD.
|
||||
// In most cases this is simple, but in a worst case situation
|
||||
// (9999..99) we have to adjust the decimalAt value.
|
||||
for (;;) {
|
||||
--maximumDigits;
|
||||
if (maximumDigits < 0) {
|
||||
// We have all 9's, so we increment to a single digit
|
||||
// of one and adjust the exponent.
|
||||
digits[0] = '1';
|
||||
++decimalAt;
|
||||
maximumDigits = 0; // Adjust the count
|
||||
break;
|
||||
}
|
||||
|
||||
++digits[maximumDigits];
|
||||
if (digits[maximumDigits] <= '9') break;
|
||||
// digits[maximumDigits] = '0'; // Unnecessary since we'll truncate this
|
||||
}
|
||||
++maximumDigits; // Increment for use as count
|
||||
}
|
||||
count = maximumDigits;
|
||||
|
||||
// Eliminate trailing zeros.
|
||||
while (count > 1 && digits[count-1] == '0') {
|
||||
--count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if truncating the representation to the given number
|
||||
* of digits will result in an increment to the last digit. This
|
||||
* method implements the rounding modes defined in the
|
||||
* java.math.RoundingMode class.
|
||||
* [bnf]
|
||||
* @param maximumDigits the number of digits to keep, from 0 to
|
||||
* <code>count-1</code>. If 0, then all digits are rounded away, and
|
||||
* this method returns true if a one should be generated (e.g., formatting
|
||||
* 0.09 with "#.#").
|
||||
* @param alreadyRounded whether or not rounding up has already happened.
|
||||
* @param valueExactAsDecimal whether or not collected digits provide
|
||||
* an exact decimal representation of the value.
|
||||
* @exception ArithmeticException if rounding is needed with rounding
|
||||
* mode being set to RoundingMode.UNNECESSARY
|
||||
* @return true if digit <code>maximumDigits-1</code> should be
|
||||
* incremented
|
||||
*/
|
||||
private boolean shouldRoundUp(int maximumDigits,
|
||||
boolean alreadyRounded,
|
||||
boolean valueExactAsDecimal) {
|
||||
if (maximumDigits < count) {
|
||||
/*
|
||||
* To avoid erroneous double-rounding or truncation when converting
|
||||
* a binary double value to text, information about the exactness
|
||||
* of the conversion result in FloatingDecimal, as well as any
|
||||
* rounding done, is needed in this class.
|
||||
*
|
||||
* - For the HALF_DOWN, HALF_EVEN, HALF_UP rounding rules below:
|
||||
* In the case of formating float or double, We must take into
|
||||
* account what FloatingDecimal has done in the binary to decimal
|
||||
* conversion.
|
||||
*
|
||||
* Considering the tie cases, FloatingDecimal may round up the
|
||||
* value (returning decimal digits equal to tie when it is below),
|
||||
* or "truncate" the value to the tie while value is above it,
|
||||
* or provide the exact decimal digits when the binary value can be
|
||||
* converted exactly to its decimal representation given formating
|
||||
* rules of FloatingDecimal ( we have thus an exact decimal
|
||||
* representation of the binary value).
|
||||
*
|
||||
* - If the double binary value was converted exactly as a decimal
|
||||
* value, then DigitList code must apply the expected rounding
|
||||
* rule.
|
||||
*
|
||||
* - If FloatingDecimal already rounded up the decimal value,
|
||||
* DigitList should neither round up the value again in any of
|
||||
* the three rounding modes above.
|
||||
*
|
||||
* - If FloatingDecimal has truncated the decimal value to
|
||||
* an ending '5' digit, DigitList should round up the value in
|
||||
* all of the three rounding modes above.
|
||||
*
|
||||
*
|
||||
* This has to be considered only if digit at maximumDigits index
|
||||
* is exactly the last one in the set of digits, otherwise there are
|
||||
* remaining digits after that position and we don't have to consider
|
||||
* what FloatingDecimal did.
|
||||
*
|
||||
* - Other rounding modes are not impacted by these tie cases.
|
||||
*
|
||||
* - For other numbers that are always converted to exact digits
|
||||
* (like BigInteger, Long, ...), the passed alreadyRounded boolean
|
||||
* have to be set to false, and valueExactAsDecimal has to be set to
|
||||
* true in the upper DigitList call stack, providing the right state
|
||||
* for those situations..
|
||||
*/
|
||||
|
||||
switch(roundingMode) {
|
||||
case UP:
|
||||
for (int i=maximumDigits; i<count; ++i) {
|
||||
if (digits[i] != '0') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DOWN:
|
||||
break;
|
||||
case CEILING:
|
||||
for (int i=maximumDigits; i<count; ++i) {
|
||||
if (digits[i] != '0') {
|
||||
return !isNegative;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FLOOR:
|
||||
for (int i=maximumDigits; i<count; ++i) {
|
||||
if (digits[i] != '0') {
|
||||
return isNegative;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HALF_UP:
|
||||
case HALF_DOWN:
|
||||
if (digits[maximumDigits] > '5') {
|
||||
// Value is above tie ==> must round up
|
||||
return true;
|
||||
} else if (digits[maximumDigits] == '5') {
|
||||
// Digit at rounding position is a '5'. Tie cases.
|
||||
if (maximumDigits != (count - 1)) {
|
||||
// There are remaining digits. Above tie => must round up
|
||||
return true;
|
||||
} else {
|
||||
// Digit at rounding position is the last one !
|
||||
if (valueExactAsDecimal) {
|
||||
// Exact binary representation. On the tie.
|
||||
// Apply rounding given by roundingMode.
|
||||
return roundingMode == RoundingMode.HALF_UP;
|
||||
} else {
|
||||
// Not an exact binary representation.
|
||||
// Digit sequence either rounded up or truncated.
|
||||
// Round up only if it was truncated.
|
||||
return !alreadyRounded;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Digit at rounding position is < '5' ==> no round up.
|
||||
// Just let do the default, which is no round up (thus break).
|
||||
break;
|
||||
case HALF_EVEN:
|
||||
// Implement IEEE half-even rounding
|
||||
if (digits[maximumDigits] > '5') {
|
||||
return true;
|
||||
} else if (digits[maximumDigits] == '5' ) {
|
||||
if (maximumDigits == (count - 1)) {
|
||||
// the rounding position is exactly the last index :
|
||||
if (alreadyRounded)
|
||||
// If FloatingDecimal rounded up (value was below tie),
|
||||
// then we should not round up again.
|
||||
return false;
|
||||
|
||||
if (!valueExactAsDecimal)
|
||||
// Otherwise if the digits don't represent exact value,
|
||||
// value was above tie and FloatingDecimal truncated
|
||||
// digits to tie. We must round up.
|
||||
return true;
|
||||
else {
|
||||
// This is an exact tie value, and FloatingDecimal
|
||||
// provided all of the exact digits. We thus apply
|
||||
// HALF_EVEN rounding rule.
|
||||
return ((maximumDigits > 0) &&
|
||||
(digits[maximumDigits-1] % 2 != 0));
|
||||
}
|
||||
} else {
|
||||
// Rounds up if it gives a non null digit after '5'
|
||||
for (int i=maximumDigits+1; i<count; ++i) {
|
||||
if (digits[i] != '0')
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UNNECESSARY:
|
||||
for (int i=maximumDigits; i<count; ++i) {
|
||||
if (digits[i] != '0') {
|
||||
throw new ArithmeticException(
|
||||
"Rounding needed with the rounding mode being set to RoundingMode.UNNECESSARY");
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility routine to set the value of the digit list from a long
|
||||
*/
|
||||
final void set(boolean isNegative, long source) {
|
||||
set(isNegative, source, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the digit list to a representation of the given long value.
|
||||
* @param isNegative Boolean value indicating whether the number is negative.
|
||||
* @param source Value to be converted; must be >= 0 or ==
|
||||
* Long.MIN_VALUE.
|
||||
* @param maximumDigits The most digits which should be converted.
|
||||
* If maximumDigits is lower than the number of significant digits
|
||||
* in source, the representation will be rounded. Ignored if <= 0.
|
||||
*/
|
||||
final void set(boolean isNegative, long source, int maximumDigits) {
|
||||
this.isNegative = isNegative;
|
||||
|
||||
// This method does not expect a negative number. However,
|
||||
// "source" can be a Long.MIN_VALUE (-9223372036854775808),
|
||||
// if the number being formatted is a Long.MIN_VALUE. In that
|
||||
// case, it will be formatted as -Long.MIN_VALUE, a number
|
||||
// which is outside the legal range of a long, but which can
|
||||
// be represented by DigitList.
|
||||
if (source <= 0) {
|
||||
if (source == Long.MIN_VALUE) {
|
||||
decimalAt = count = MAX_COUNT;
|
||||
System.arraycopy(LONG_MIN_REP, 0, digits, 0, count);
|
||||
} else {
|
||||
decimalAt = count = 0; // Values <= 0 format as zero
|
||||
}
|
||||
} else {
|
||||
// Rewritten to improve performance. I used to call
|
||||
// Long.toString(), which was about 4x slower than this code.
|
||||
int left = MAX_COUNT;
|
||||
int right;
|
||||
while (source > 0) {
|
||||
digits[--left] = (char)('0' + (source % 10));
|
||||
source /= 10;
|
||||
}
|
||||
decimalAt = MAX_COUNT - left;
|
||||
// Don't copy trailing zeros. We are guaranteed that there is at
|
||||
// least one non-zero digit, so we don't have to check lower bounds.
|
||||
for (right = MAX_COUNT - 1; digits[right] == '0'; --right)
|
||||
;
|
||||
count = right - left + 1;
|
||||
System.arraycopy(digits, left, digits, 0, count);
|
||||
}
|
||||
if (maximumDigits > 0) round(maximumDigits, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the digit list to a representation of the given BigDecimal value.
|
||||
* This method supports both fixed-point and exponential notation.
|
||||
* @param isNegative Boolean value indicating whether the number is negative.
|
||||
* @param source Value to be converted; must not be a value <= 0.
|
||||
* @param maximumDigits The most fractional or total digits which should
|
||||
* be converted.
|
||||
* @param fixedPoint If true, then maximumDigits is the maximum
|
||||
* fractional digits to be converted. If false, total digits.
|
||||
*/
|
||||
final void set(boolean isNegative, BigDecimal source, int maximumDigits, boolean fixedPoint) {
|
||||
String s = source.toString();
|
||||
extendDigits(s.length());
|
||||
|
||||
set(isNegative, s,
|
||||
false, true,
|
||||
maximumDigits, fixedPoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the digit list to a representation of the given BigInteger value.
|
||||
* @param isNegative Boolean value indicating whether the number is negative.
|
||||
* @param source Value to be converted; must be >= 0.
|
||||
* @param maximumDigits The most digits which should be converted.
|
||||
* If maximumDigits is lower than the number of significant digits
|
||||
* in source, the representation will be rounded. Ignored if <= 0.
|
||||
*/
|
||||
final void set(boolean isNegative, BigInteger source, int maximumDigits) {
|
||||
this.isNegative = isNegative;
|
||||
String s = source.toString();
|
||||
int len = s.length();
|
||||
extendDigits(len);
|
||||
s.getChars(0, len, digits, 0);
|
||||
|
||||
decimalAt = len;
|
||||
int right;
|
||||
for (right = len - 1; right >= 0 && digits[right] == '0'; --right)
|
||||
;
|
||||
count = right + 1;
|
||||
|
||||
if (maximumDigits > 0) {
|
||||
round(maximumDigits, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* equality test between two digit lists.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) // quick check
|
||||
return true;
|
||||
if (!(obj instanceof DigitList)) // (1) same object?
|
||||
return false;
|
||||
DigitList other = (DigitList) obj;
|
||||
if (count != other.count ||
|
||||
decimalAt != other.decimalAt)
|
||||
return false;
|
||||
for (int i = 0; i < count; i++)
|
||||
if (digits[i] != other.digits[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the hash code for the digit list.
|
||||
*/
|
||||
public int hashCode() {
|
||||
int hashcode = decimalAt;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
hashcode = hashcode * 37 + digits[i];
|
||||
}
|
||||
|
||||
return hashcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of this object.
|
||||
* @return a clone of this instance.
|
||||
*/
|
||||
public Object clone() {
|
||||
try {
|
||||
DigitList other = (DigitList) super.clone();
|
||||
char[] newDigits = new char[digits.length];
|
||||
System.arraycopy(digits, 0, newDigits, 0, digits.length);
|
||||
other.digits = newDigits;
|
||||
other.tempBuffer = null;
|
||||
return other;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this DigitList represents Long.MIN_VALUE;
|
||||
* false, otherwise. This is required so that getLong() works.
|
||||
*/
|
||||
private boolean isLongMIN_VALUE() {
|
||||
if (decimalAt != count || count != MAX_COUNT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (digits[i] != LONG_MIN_REP[i]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final int parseInt(char[] str, int offset, int strLen) {
|
||||
char c;
|
||||
boolean positive = true;
|
||||
if ((c = str[offset]) == '-') {
|
||||
positive = false;
|
||||
offset++;
|
||||
} else if (c == '+') {
|
||||
offset++;
|
||||
}
|
||||
|
||||
int value = 0;
|
||||
while (offset < strLen) {
|
||||
c = str[offset++];
|
||||
if (c >= '0' && c <= '9') {
|
||||
value = value * 10 + (c - '0');
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return positive ? value : -value;
|
||||
}
|
||||
|
||||
// The digit part of -9223372036854775808L
|
||||
private static final char[] LONG_MIN_REP = "9223372036854775808".toCharArray();
|
||||
|
||||
public String toString() {
|
||||
if (isZero()) {
|
||||
return "0";
|
||||
}
|
||||
StringBuffer buf = getStringBuffer();
|
||||
buf.append("0.");
|
||||
buf.append(digits, 0, count);
|
||||
buf.append("x10^");
|
||||
buf.append(decimalAt);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private StringBuffer tempBuffer;
|
||||
|
||||
private StringBuffer getStringBuffer() {
|
||||
if (tempBuffer == null) {
|
||||
tempBuffer = new StringBuffer(MAX_COUNT);
|
||||
} else {
|
||||
tempBuffer.setLength(0);
|
||||
}
|
||||
return tempBuffer;
|
||||
}
|
||||
|
||||
private void extendDigits(int len) {
|
||||
if (len > digits.length) {
|
||||
digits = new char[len];
|
||||
}
|
||||
}
|
||||
|
||||
private final char[] getDataChars(int length) {
|
||||
if (data == null || data.length < length) {
|
||||
data = new char[length];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
53
jdkSrc/jdk8/java/text/DontCareFieldPosition.java
Normal file
53
jdkSrc/jdk8/java/text/DontCareFieldPosition.java
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
/**
|
||||
* DontCareFieldPosition defines no-op FieldDelegate. Its
|
||||
* singleton is used for the format methods that don't take a
|
||||
* FieldPosition.
|
||||
*/
|
||||
class DontCareFieldPosition extends FieldPosition {
|
||||
// The singleton of DontCareFieldPosition.
|
||||
static final FieldPosition INSTANCE = new DontCareFieldPosition();
|
||||
|
||||
private final Format.FieldDelegate noDelegate = new Format.FieldDelegate() {
|
||||
public void formatted(Format.Field attr, Object value, int start,
|
||||
int end, StringBuffer buffer) {
|
||||
}
|
||||
public void formatted(int fieldID, Format.Field attr, Object value,
|
||||
int start, int end, StringBuffer buffer) {
|
||||
}
|
||||
};
|
||||
|
||||
private DontCareFieldPosition() {
|
||||
super(0);
|
||||
}
|
||||
|
||||
Format.FieldDelegate getFieldDelegate() {
|
||||
return noDelegate;
|
||||
}
|
||||
}
|
||||
60
jdkSrc/jdk8/java/text/EntryPair.java
Normal file
60
jdkSrc/jdk8/java/text/EntryPair.java
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 1998, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is copyrighted
|
||||
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
|
||||
* materials are provided under terms of a License Agreement between Taligent
|
||||
* and Sun. This technology is protected by multiple US and International
|
||||
* patents. This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
/**
|
||||
* This is used for building contracting character tables. entryName
|
||||
* is the contracting character name and value is its collation
|
||||
* order.
|
||||
*/
|
||||
final class EntryPair
|
||||
{
|
||||
public String entryName;
|
||||
public int value;
|
||||
public boolean fwd;
|
||||
|
||||
public EntryPair(String name, int value) {
|
||||
this(name, value, true);
|
||||
}
|
||||
public EntryPair(String name, int value, boolean fwd) {
|
||||
this.entryName = name;
|
||||
this.value = value;
|
||||
this.fwd = fwd;
|
||||
}
|
||||
}
|
||||
314
jdkSrc/jdk8/java/text/FieldPosition.java
Normal file
314
jdkSrc/jdk8/java/text/FieldPosition.java
Normal file
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is copyrighted
|
||||
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
|
||||
* materials are provided under terms of a License Agreement between Taligent
|
||||
* and Sun. This technology is protected by multiple US and International
|
||||
* patents. This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
/**
|
||||
* <code>FieldPosition</code> is a simple class used by <code>Format</code>
|
||||
* and its subclasses to identify fields in formatted output. Fields can
|
||||
* be identified in two ways:
|
||||
* <ul>
|
||||
* <li>By an integer constant, whose names typically end with
|
||||
* <code>_FIELD</code>. The constants are defined in the various
|
||||
* subclasses of <code>Format</code>.
|
||||
* <li>By a <code>Format.Field</code> constant, see <code>ERA_FIELD</code>
|
||||
* and its friends in <code>DateFormat</code> for an example.
|
||||
* </ul>
|
||||
* <p>
|
||||
* <code>FieldPosition</code> keeps track of the position of the
|
||||
* field within the formatted output with two indices: the index
|
||||
* of the first character of the field and the index of the last
|
||||
* character of the field.
|
||||
*
|
||||
* <p>
|
||||
* One version of the <code>format</code> method in the various
|
||||
* <code>Format</code> classes requires a <code>FieldPosition</code>
|
||||
* object as an argument. You use this <code>format</code> method
|
||||
* to perform partial formatting or to get information about the
|
||||
* formatted output (such as the position of a field).
|
||||
*
|
||||
* <p>
|
||||
* If you are interested in the positions of all attributes in the
|
||||
* formatted string use the <code>Format</code> method
|
||||
* <code>formatToCharacterIterator</code>.
|
||||
*
|
||||
* @author Mark Davis
|
||||
* @see java.text.Format
|
||||
*/
|
||||
public class FieldPosition {
|
||||
|
||||
/**
|
||||
* Input: Desired field to determine start and end offsets for.
|
||||
* The meaning depends on the subclass of Format.
|
||||
*/
|
||||
int field = 0;
|
||||
|
||||
/**
|
||||
* Output: End offset of field in text.
|
||||
* If the field does not occur in the text, 0 is returned.
|
||||
*/
|
||||
int endIndex = 0;
|
||||
|
||||
/**
|
||||
* Output: Start offset of field in text.
|
||||
* If the field does not occur in the text, 0 is returned.
|
||||
*/
|
||||
int beginIndex = 0;
|
||||
|
||||
/**
|
||||
* Desired field this FieldPosition is for.
|
||||
*/
|
||||
private Format.Field attribute;
|
||||
|
||||
/**
|
||||
* Creates a FieldPosition object for the given field. Fields are
|
||||
* identified by constants, whose names typically end with _FIELD,
|
||||
* in the various subclasses of Format.
|
||||
*
|
||||
* @param field the field identifier
|
||||
* @see java.text.NumberFormat#INTEGER_FIELD
|
||||
* @see java.text.NumberFormat#FRACTION_FIELD
|
||||
* @see java.text.DateFormat#YEAR_FIELD
|
||||
* @see java.text.DateFormat#MONTH_FIELD
|
||||
*/
|
||||
public FieldPosition(int field) {
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a FieldPosition object for the given field constant. Fields are
|
||||
* identified by constants defined in the various <code>Format</code>
|
||||
* subclasses. This is equivalent to calling
|
||||
* <code>new FieldPosition(attribute, -1)</code>.
|
||||
*
|
||||
* @param attribute Format.Field constant identifying a field
|
||||
* @since 1.4
|
||||
*/
|
||||
public FieldPosition(Format.Field attribute) {
|
||||
this(attribute, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a <code>FieldPosition</code> object for the given field.
|
||||
* The field is identified by an attribute constant from one of the
|
||||
* <code>Field</code> subclasses as well as an integer field ID
|
||||
* defined by the <code>Format</code> subclasses. <code>Format</code>
|
||||
* subclasses that are aware of <code>Field</code> should give precedence
|
||||
* to <code>attribute</code> and ignore <code>fieldID</code> if
|
||||
* <code>attribute</code> is not null. However, older <code>Format</code>
|
||||
* subclasses may not be aware of <code>Field</code> and rely on
|
||||
* <code>fieldID</code>. If the field has no corresponding integer
|
||||
* constant, <code>fieldID</code> should be -1.
|
||||
*
|
||||
* @param attribute Format.Field constant identifying a field
|
||||
* @param fieldID integer constant identifying a field
|
||||
* @since 1.4
|
||||
*/
|
||||
public FieldPosition(Format.Field attribute, int fieldID) {
|
||||
this.attribute = attribute;
|
||||
this.field = fieldID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the field identifier as an attribute constant
|
||||
* from one of the <code>Field</code> subclasses. May return null if
|
||||
* the field is specified only by an integer field ID.
|
||||
*
|
||||
* @return Identifier for the field
|
||||
* @since 1.4
|
||||
*/
|
||||
public Format.Field getFieldAttribute() {
|
||||
return attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the field identifier.
|
||||
*
|
||||
* @return the field identifier
|
||||
*/
|
||||
public int getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the index of the first character in the requested field.
|
||||
*
|
||||
* @return the begin index
|
||||
*/
|
||||
public int getBeginIndex() {
|
||||
return beginIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the index of the character following the last character in the
|
||||
* requested field.
|
||||
*
|
||||
* @return the end index
|
||||
*/
|
||||
public int getEndIndex() {
|
||||
return endIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the begin index. For use by subclasses of Format.
|
||||
*
|
||||
* @param bi the begin index
|
||||
* @since 1.2
|
||||
*/
|
||||
public void setBeginIndex(int bi) {
|
||||
beginIndex = bi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the end index. For use by subclasses of Format.
|
||||
*
|
||||
* @param ei the end index
|
||||
* @since 1.2
|
||||
*/
|
||||
public void setEndIndex(int ei) {
|
||||
endIndex = ei;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>Format.FieldDelegate</code> instance that is associated
|
||||
* with the FieldPosition. When the delegate is notified of the same
|
||||
* field the FieldPosition is associated with, the begin/end will be
|
||||
* adjusted.
|
||||
*/
|
||||
Format.FieldDelegate getFieldDelegate() {
|
||||
return new Delegate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides equals
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj == null) return false;
|
||||
if (!(obj instanceof FieldPosition))
|
||||
return false;
|
||||
FieldPosition other = (FieldPosition) obj;
|
||||
if (attribute == null) {
|
||||
if (other.attribute != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!attribute.equals(other.attribute)) {
|
||||
return false;
|
||||
}
|
||||
return (beginIndex == other.beginIndex
|
||||
&& endIndex == other.endIndex
|
||||
&& field == other.field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code for this FieldPosition.
|
||||
* @return a hash code value for this object
|
||||
*/
|
||||
public int hashCode() {
|
||||
return (field << 24) | (beginIndex << 16) | endIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string representation of this FieldPosition.
|
||||
* @return a string representation of this object
|
||||
*/
|
||||
public String toString() {
|
||||
return getClass().getName() +
|
||||
"[field=" + field + ",attribute=" + attribute +
|
||||
",beginIndex=" + beginIndex +
|
||||
",endIndex=" + endIndex + ']';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if the receiver wants a <code>Format.Field</code> value and
|
||||
* <code>attribute</code> is equal to it.
|
||||
*/
|
||||
private boolean matchesField(Format.Field attribute) {
|
||||
if (this.attribute != null) {
|
||||
return this.attribute.equals(attribute);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the receiver wants a <code>Format.Field</code> value and
|
||||
* <code>attribute</code> is equal to it, or true if the receiver
|
||||
* represents an inteter constant and <code>field</code> equals it.
|
||||
*/
|
||||
private boolean matchesField(Format.Field attribute, int field) {
|
||||
if (this.attribute != null) {
|
||||
return this.attribute.equals(attribute);
|
||||
}
|
||||
return (field == this.field);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An implementation of FieldDelegate that will adjust the begin/end
|
||||
* of the FieldPosition if the arguments match the field of
|
||||
* the FieldPosition.
|
||||
*/
|
||||
private class Delegate implements Format.FieldDelegate {
|
||||
/**
|
||||
* Indicates whether the field has been encountered before. If this
|
||||
* is true, and <code>formatted</code> is invoked, the begin/end
|
||||
* are not updated.
|
||||
*/
|
||||
private boolean encounteredField;
|
||||
|
||||
public void formatted(Format.Field attr, Object value, int start,
|
||||
int end, StringBuffer buffer) {
|
||||
if (!encounteredField && matchesField(attr)) {
|
||||
setBeginIndex(start);
|
||||
setEndIndex(end);
|
||||
encounteredField = (start != end);
|
||||
}
|
||||
}
|
||||
|
||||
public void formatted(int fieldID, Format.Field attr, Object value,
|
||||
int start, int end, StringBuffer buffer) {
|
||||
if (!encounteredField && matchesField(attr, fieldID)) {
|
||||
setBeginIndex(start);
|
||||
setEndIndex(end);
|
||||
encounteredField = (start != end);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
406
jdkSrc/jdk8/java/text/Format.java
Normal file
406
jdkSrc/jdk8/java/text/Format.java
Normal file
@@ -0,0 +1,406 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is copyrighted
|
||||
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
|
||||
* materials are provided under terms of a License Agreement between Taligent
|
||||
* and Sun. This technology is protected by multiple US and International
|
||||
* patents. This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <code>Format</code> is an abstract base class for formatting locale-sensitive
|
||||
* information such as dates, messages, and numbers.
|
||||
*
|
||||
* <p>
|
||||
* <code>Format</code> defines the programming interface for formatting
|
||||
* locale-sensitive objects into <code>String</code>s (the
|
||||
* <code>format</code> method) and for parsing <code>String</code>s back
|
||||
* into objects (the <code>parseObject</code> method).
|
||||
*
|
||||
* <p>
|
||||
* Generally, a format's <code>parseObject</code> method must be able to parse
|
||||
* any string formatted by its <code>format</code> method. However, there may
|
||||
* be exceptional cases where this is not possible. For example, a
|
||||
* <code>format</code> method might create two adjacent integer numbers with
|
||||
* no separator in between, and in this case the <code>parseObject</code> could
|
||||
* not tell which digits belong to which number.
|
||||
*
|
||||
* <h3>Subclassing</h3>
|
||||
*
|
||||
* <p>
|
||||
* The Java Platform provides three specialized subclasses of <code>Format</code>--
|
||||
* <code>DateFormat</code>, <code>MessageFormat</code>, and
|
||||
* <code>NumberFormat</code>--for formatting dates, messages, and numbers,
|
||||
* respectively.
|
||||
* <p>
|
||||
* Concrete subclasses must implement three methods:
|
||||
* <ol>
|
||||
* <li> <code>format(Object obj, StringBuffer toAppendTo, FieldPosition pos)</code>
|
||||
* <li> <code>formatToCharacterIterator(Object obj)</code>
|
||||
* <li> <code>parseObject(String source, ParsePosition pos)</code>
|
||||
* </ol>
|
||||
* These general methods allow polymorphic parsing and formatting of objects
|
||||
* and are used, for example, by <code>MessageFormat</code>.
|
||||
* Subclasses often also provide additional <code>format</code> methods for
|
||||
* specific input types as well as <code>parse</code> methods for specific
|
||||
* result types. Any <code>parse</code> method that does not take a
|
||||
* <code>ParsePosition</code> argument should throw <code>ParseException</code>
|
||||
* when no text in the required format is at the beginning of the input text.
|
||||
*
|
||||
* <p>
|
||||
* Most subclasses will also implement the following factory methods:
|
||||
* <ol>
|
||||
* <li>
|
||||
* <code>getInstance</code> for getting a useful format object appropriate
|
||||
* for the current locale
|
||||
* <li>
|
||||
* <code>getInstance(Locale)</code> for getting a useful format
|
||||
* object appropriate for the specified locale
|
||||
* </ol>
|
||||
* In addition, some subclasses may also implement other
|
||||
* <code>getXxxxInstance</code> methods for more specialized control. For
|
||||
* example, the <code>NumberFormat</code> class provides
|
||||
* <code>getPercentInstance</code> and <code>getCurrencyInstance</code>
|
||||
* methods for getting specialized number formatters.
|
||||
*
|
||||
* <p>
|
||||
* Subclasses of <code>Format</code> that allow programmers to create objects
|
||||
* for locales (with <code>getInstance(Locale)</code> for example)
|
||||
* must also implement the following class method:
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* public static Locale[] getAvailableLocales()
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* <p>
|
||||
* And finally subclasses may define a set of constants to identify the various
|
||||
* fields in the formatted output. These constants are used to create a FieldPosition
|
||||
* object which identifies what information is contained in the field and its
|
||||
* position in the formatted result. These constants should be named
|
||||
* <code><em>item</em>_FIELD</code> where <code><em>item</em></code> identifies
|
||||
* the field. For examples of these constants, see <code>ERA_FIELD</code> and its
|
||||
* friends in {@link DateFormat}.
|
||||
*
|
||||
* <h4><a name="synchronization">Synchronization</a></h4>
|
||||
*
|
||||
* <p>
|
||||
* Formats are generally not synchronized.
|
||||
* It is recommended to create separate format instances for each thread.
|
||||
* If multiple threads access a format concurrently, it must be synchronized
|
||||
* externally.
|
||||
*
|
||||
* @see java.text.ParsePosition
|
||||
* @see java.text.FieldPosition
|
||||
* @see java.text.NumberFormat
|
||||
* @see java.text.DateFormat
|
||||
* @see java.text.MessageFormat
|
||||
* @author Mark Davis
|
||||
*/
|
||||
public abstract class Format implements Serializable, Cloneable {
|
||||
|
||||
private static final long serialVersionUID = -299282585814624189L;
|
||||
|
||||
/**
|
||||
* Sole constructor. (For invocation by subclass constructors, typically
|
||||
* implicit.)
|
||||
*/
|
||||
protected Format() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an object to produce a string. This is equivalent to
|
||||
* <blockquote>
|
||||
* {@link #format(Object, StringBuffer, FieldPosition) format}<code>(obj,
|
||||
* new StringBuffer(), new FieldPosition(0)).toString();</code>
|
||||
* </blockquote>
|
||||
*
|
||||
* @param obj The object to format
|
||||
* @return Formatted string.
|
||||
* @exception IllegalArgumentException if the Format cannot format the given
|
||||
* object
|
||||
*/
|
||||
public final String format (Object obj) {
|
||||
return format(obj, new StringBuffer(), new FieldPosition(0)).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an object and appends the resulting text to a given string
|
||||
* buffer.
|
||||
* If the <code>pos</code> argument identifies a field used by the format,
|
||||
* then its indices are set to the beginning and end of the first such
|
||||
* field encountered.
|
||||
*
|
||||
* @param obj The object to format
|
||||
* @param toAppendTo where the text is to be appended
|
||||
* @param pos A <code>FieldPosition</code> identifying a field
|
||||
* in the formatted text
|
||||
* @return the string buffer passed in as <code>toAppendTo</code>,
|
||||
* with formatted text appended
|
||||
* @exception NullPointerException if <code>toAppendTo</code> or
|
||||
* <code>pos</code> is null
|
||||
* @exception IllegalArgumentException if the Format cannot format the given
|
||||
* object
|
||||
*/
|
||||
public abstract StringBuffer format(Object obj,
|
||||
StringBuffer toAppendTo,
|
||||
FieldPosition pos);
|
||||
|
||||
/**
|
||||
* Formats an Object producing an <code>AttributedCharacterIterator</code>.
|
||||
* You can use the returned <code>AttributedCharacterIterator</code>
|
||||
* to build the resulting String, as well as to determine information
|
||||
* about the resulting String.
|
||||
* <p>
|
||||
* Each attribute key of the AttributedCharacterIterator will be of type
|
||||
* <code>Field</code>. It is up to each <code>Format</code> implementation
|
||||
* to define what the legal values are for each attribute in the
|
||||
* <code>AttributedCharacterIterator</code>, but typically the attribute
|
||||
* key is also used as the attribute value.
|
||||
* <p>The default implementation creates an
|
||||
* <code>AttributedCharacterIterator</code> with no attributes. Subclasses
|
||||
* that support fields should override this and create an
|
||||
* <code>AttributedCharacterIterator</code> with meaningful attributes.
|
||||
*
|
||||
* @exception NullPointerException if obj is null.
|
||||
* @exception IllegalArgumentException when the Format cannot format the
|
||||
* given object.
|
||||
* @param obj The object to format
|
||||
* @return AttributedCharacterIterator describing the formatted value.
|
||||
* @since 1.4
|
||||
*/
|
||||
public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
|
||||
return createAttributedCharacterIterator(format(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses text from a string to produce an object.
|
||||
* <p>
|
||||
* The method attempts to parse text starting at the index given by
|
||||
* <code>pos</code>.
|
||||
* If parsing succeeds, then the index of <code>pos</code> is updated
|
||||
* to the index after the last character used (parsing does not necessarily
|
||||
* use all characters up to the end of the string), and the parsed
|
||||
* object is returned. The updated <code>pos</code> can be used to
|
||||
* indicate the starting point for the next call to this method.
|
||||
* If an error occurs, then the index of <code>pos</code> is not
|
||||
* changed, the error index of <code>pos</code> is set to the index of
|
||||
* the character where the error occurred, and null is returned.
|
||||
*
|
||||
* @param source A <code>String</code>, part of which should be parsed.
|
||||
* @param pos A <code>ParsePosition</code> object with index and error
|
||||
* index information as described above.
|
||||
* @return An <code>Object</code> parsed from the string. In case of
|
||||
* error, returns null.
|
||||
* @exception NullPointerException if <code>pos</code> is null.
|
||||
*/
|
||||
public abstract Object parseObject (String source, ParsePosition pos);
|
||||
|
||||
/**
|
||||
* Parses text from the beginning of the given string to produce an object.
|
||||
* The method may not use the entire text of the given string.
|
||||
*
|
||||
* @param source A <code>String</code> whose beginning should be parsed.
|
||||
* @return An <code>Object</code> parsed from the string.
|
||||
* @exception ParseException if the beginning of the specified string
|
||||
* cannot be parsed.
|
||||
*/
|
||||
public Object parseObject(String source) throws ParseException {
|
||||
ParsePosition pos = new ParsePosition(0);
|
||||
Object result = parseObject(source, pos);
|
||||
if (pos.index == 0) {
|
||||
throw new ParseException("Format.parseObject(String) failed",
|
||||
pos.errorIndex);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a copy of this object.
|
||||
*
|
||||
* @return a clone of this instance.
|
||||
*/
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
// will never happen
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Convenience methods for creating AttributedCharacterIterators from
|
||||
// different parameters.
|
||||
//
|
||||
|
||||
/**
|
||||
* Creates an <code>AttributedCharacterIterator</code> for the String
|
||||
* <code>s</code>.
|
||||
*
|
||||
* @param s String to create AttributedCharacterIterator from
|
||||
* @return AttributedCharacterIterator wrapping s
|
||||
*/
|
||||
AttributedCharacterIterator createAttributedCharacterIterator(String s) {
|
||||
AttributedString as = new AttributedString(s);
|
||||
|
||||
return as.getIterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an <code>AttributedCharacterIterator</code> containing the
|
||||
* concatenated contents of the passed in
|
||||
* <code>AttributedCharacterIterator</code>s.
|
||||
*
|
||||
* @param iterators AttributedCharacterIterators used to create resulting
|
||||
* AttributedCharacterIterators
|
||||
* @return AttributedCharacterIterator wrapping passed in
|
||||
* AttributedCharacterIterators
|
||||
*/
|
||||
AttributedCharacterIterator createAttributedCharacterIterator(
|
||||
AttributedCharacterIterator[] iterators) {
|
||||
AttributedString as = new AttributedString(iterators);
|
||||
|
||||
return as.getIterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an AttributedCharacterIterator with the String
|
||||
* <code>string</code> and additional key/value pair <code>key</code>,
|
||||
* <code>value</code>.
|
||||
*
|
||||
* @param string String to create AttributedCharacterIterator from
|
||||
* @param key Key for AttributedCharacterIterator
|
||||
* @param value Value associated with key in AttributedCharacterIterator
|
||||
* @return AttributedCharacterIterator wrapping args
|
||||
*/
|
||||
AttributedCharacterIterator createAttributedCharacterIterator(
|
||||
String string, AttributedCharacterIterator.Attribute key,
|
||||
Object value) {
|
||||
AttributedString as = new AttributedString(string);
|
||||
|
||||
as.addAttribute(key, value);
|
||||
return as.getIterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an AttributedCharacterIterator with the contents of
|
||||
* <code>iterator</code> and the additional attribute <code>key</code>
|
||||
* <code>value</code>.
|
||||
*
|
||||
* @param iterator Initial AttributedCharacterIterator to add arg to
|
||||
* @param key Key for AttributedCharacterIterator
|
||||
* @param value Value associated with key in AttributedCharacterIterator
|
||||
* @return AttributedCharacterIterator wrapping args
|
||||
*/
|
||||
AttributedCharacterIterator createAttributedCharacterIterator(
|
||||
AttributedCharacterIterator iterator,
|
||||
AttributedCharacterIterator.Attribute key, Object value) {
|
||||
AttributedString as = new AttributedString(iterator);
|
||||
|
||||
as.addAttribute(key, value);
|
||||
return as.getIterator();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Defines constants that are used as attribute keys in the
|
||||
* <code>AttributedCharacterIterator</code> returned
|
||||
* from <code>Format.formatToCharacterIterator</code> and as
|
||||
* field identifiers in <code>FieldPosition</code>.
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
public static class Field extends AttributedCharacterIterator.Attribute {
|
||||
|
||||
// Proclaim serial compatibility with 1.4 FCS
|
||||
private static final long serialVersionUID = 276966692217360283L;
|
||||
|
||||
/**
|
||||
* Creates a Field with the specified name.
|
||||
*
|
||||
* @param name Name of the attribute
|
||||
*/
|
||||
protected Field(String name) {
|
||||
super(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* FieldDelegate is notified by the various <code>Format</code>
|
||||
* implementations as they are formatting the Objects. This allows for
|
||||
* storage of the individual sections of the formatted String for
|
||||
* later use, such as in a <code>FieldPosition</code> or for an
|
||||
* <code>AttributedCharacterIterator</code>.
|
||||
* <p>
|
||||
* Delegates should NOT assume that the <code>Format</code> will notify
|
||||
* the delegate of fields in any particular order.
|
||||
*
|
||||
* @see FieldPosition#getFieldDelegate
|
||||
* @see CharacterIteratorFieldDelegate
|
||||
*/
|
||||
interface FieldDelegate {
|
||||
/**
|
||||
* Notified when a particular region of the String is formatted. This
|
||||
* method will be invoked if there is no corresponding integer field id
|
||||
* matching <code>attr</code>.
|
||||
*
|
||||
* @param attr Identifies the field matched
|
||||
* @param value Value associated with the field
|
||||
* @param start Beginning location of the field, will be >= 0
|
||||
* @param end End of the field, will be >= start and <= buffer.length()
|
||||
* @param buffer Contains current formatted value, receiver should
|
||||
* NOT modify it.
|
||||
*/
|
||||
public void formatted(Format.Field attr, Object value, int start,
|
||||
int end, StringBuffer buffer);
|
||||
|
||||
/**
|
||||
* Notified when a particular region of the String is formatted.
|
||||
*
|
||||
* @param fieldID Identifies the field by integer
|
||||
* @param attr Identifies the field matched
|
||||
* @param value Value associated with the field
|
||||
* @param start Beginning location of the field, will be >= 0
|
||||
* @param end End of the field, will be >= start and <= buffer.length()
|
||||
* @param buffer Contains current formatted value, receiver should
|
||||
* NOT modify it.
|
||||
*/
|
||||
public void formatted(int fieldID, Format.Field attr, Object value,
|
||||
int start, int end, StringBuffer buffer);
|
||||
}
|
||||
}
|
||||
342
jdkSrc/jdk8/java/text/MergeCollation.java
Normal file
342
jdkSrc/jdk8/java/text/MergeCollation.java
Normal file
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996, 1997 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is copyrighted
|
||||
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
|
||||
* materials are provided under terms of a License Agreement between Taligent
|
||||
* and Sun. This technology is protected by multiple US and International
|
||||
* patents. This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Utility class for normalizing and merging patterns for collation.
|
||||
* Patterns are strings of the form <entry>*, where <entry> has the
|
||||
* form:
|
||||
* <pattern> := <entry>*
|
||||
* <entry> := <separator><chars>{"/"<extension>}
|
||||
* <separator> := "=", ",", ";", "<", "&"
|
||||
* <chars>, and <extension> are both arbitrary strings.
|
||||
* unquoted whitespaces are ignored.
|
||||
* 'xxx' can be used to quote characters
|
||||
* One difference from Collator is that & is used to reset to a current
|
||||
* point. Or, in other words, it introduces a new sequence which is to
|
||||
* be added to the old.
|
||||
* That is: "a < b < c < d" is the same as "a < b & b < c & c < d" OR
|
||||
* "a < b < d & b < c"
|
||||
* XXX: make '' be a single quote.
|
||||
* @see PatternEntry
|
||||
* @author Mark Davis, Helena Shih
|
||||
*/
|
||||
|
||||
final class MergeCollation {
|
||||
|
||||
/**
|
||||
* Creates from a pattern
|
||||
* @exception ParseException If the input pattern is incorrect.
|
||||
*/
|
||||
public MergeCollation(String pattern) throws ParseException
|
||||
{
|
||||
for (int i = 0; i < statusArray.length; i++)
|
||||
statusArray[i] = 0;
|
||||
setPattern(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* recovers current pattern
|
||||
*/
|
||||
public String getPattern() {
|
||||
return getPattern(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* recovers current pattern.
|
||||
* @param withWhiteSpace puts spacing around the entries, and \n
|
||||
* before & and <
|
||||
*/
|
||||
public String getPattern(boolean withWhiteSpace) {
|
||||
StringBuffer result = new StringBuffer();
|
||||
PatternEntry tmp = null;
|
||||
ArrayList<PatternEntry> extList = null;
|
||||
int i;
|
||||
for (i = 0; i < patterns.size(); ++i) {
|
||||
PatternEntry entry = patterns.get(i);
|
||||
if (entry.extension.length() != 0) {
|
||||
if (extList == null)
|
||||
extList = new ArrayList<>();
|
||||
extList.add(entry);
|
||||
} else {
|
||||
if (extList != null) {
|
||||
PatternEntry last = findLastWithNoExtension(i-1);
|
||||
for (int j = extList.size() - 1; j >= 0 ; j--) {
|
||||
tmp = extList.get(j);
|
||||
tmp.addToBuffer(result, false, withWhiteSpace, last);
|
||||
}
|
||||
extList = null;
|
||||
}
|
||||
entry.addToBuffer(result, false, withWhiteSpace, null);
|
||||
}
|
||||
}
|
||||
if (extList != null) {
|
||||
PatternEntry last = findLastWithNoExtension(i-1);
|
||||
for (int j = extList.size() - 1; j >= 0 ; j--) {
|
||||
tmp = extList.get(j);
|
||||
tmp.addToBuffer(result, false, withWhiteSpace, last);
|
||||
}
|
||||
extList = null;
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private final PatternEntry findLastWithNoExtension(int i) {
|
||||
for (--i;i >= 0; --i) {
|
||||
PatternEntry entry = patterns.get(i);
|
||||
if (entry.extension.length() == 0) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* emits the pattern for collation builder.
|
||||
* @return emits the string in the format understable to the collation
|
||||
* builder.
|
||||
*/
|
||||
public String emitPattern() {
|
||||
return emitPattern(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* emits the pattern for collation builder.
|
||||
* @param withWhiteSpace puts spacing around the entries, and \n
|
||||
* before & and <
|
||||
* @return emits the string in the format understable to the collation
|
||||
* builder.
|
||||
*/
|
||||
public String emitPattern(boolean withWhiteSpace) {
|
||||
StringBuffer result = new StringBuffer();
|
||||
for (int i = 0; i < patterns.size(); ++i)
|
||||
{
|
||||
PatternEntry entry = patterns.get(i);
|
||||
if (entry != null) {
|
||||
entry.addToBuffer(result, true, withWhiteSpace, null);
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the pattern.
|
||||
*/
|
||||
public void setPattern(String pattern) throws ParseException
|
||||
{
|
||||
patterns.clear();
|
||||
addPattern(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* adds a pattern to the current one.
|
||||
* @param pattern the new pattern to be added
|
||||
*/
|
||||
public void addPattern(String pattern) throws ParseException
|
||||
{
|
||||
if (pattern == null)
|
||||
return;
|
||||
|
||||
PatternEntry.Parser parser = new PatternEntry.Parser(pattern);
|
||||
|
||||
PatternEntry entry = parser.next();
|
||||
while (entry != null) {
|
||||
fixEntry(entry);
|
||||
entry = parser.next();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gets count of separate entries
|
||||
* @return the size of pattern entries
|
||||
*/
|
||||
public int getCount() {
|
||||
return patterns.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* gets count of separate entries
|
||||
* @param index the offset of the desired pattern entry
|
||||
* @return the requested pattern entry
|
||||
*/
|
||||
public PatternEntry getItemAt(int index) {
|
||||
return patterns.get(index);
|
||||
}
|
||||
|
||||
//============================================================
|
||||
// privates
|
||||
//============================================================
|
||||
ArrayList<PatternEntry> patterns = new ArrayList<>(); // a list of PatternEntries
|
||||
|
||||
private transient PatternEntry saveEntry = null;
|
||||
private transient PatternEntry lastEntry = null;
|
||||
|
||||
// This is really used as a local variable inside fixEntry, but we cache
|
||||
// it here to avoid newing it up every time the method is called.
|
||||
private transient StringBuffer excess = new StringBuffer();
|
||||
|
||||
//
|
||||
// When building a MergeCollation, we need to do lots of searches to see
|
||||
// whether a given entry is already in the table. Since we're using an
|
||||
// array, this would make the algorithm O(N*N). To speed things up, we
|
||||
// use this bit array to remember whether the array contains any entries
|
||||
// starting with each Unicode character. If not, we can avoid the search.
|
||||
// Using BitSet would make this easier, but it's significantly slower.
|
||||
//
|
||||
private transient byte[] statusArray = new byte[8192];
|
||||
private final byte BITARRAYMASK = (byte)0x1;
|
||||
private final int BYTEPOWER = 3;
|
||||
private final int BYTEMASK = (1 << BYTEPOWER) - 1;
|
||||
|
||||
/*
|
||||
If the strength is RESET, then just change the lastEntry to
|
||||
be the current. (If the current is not in patterns, signal an error).
|
||||
If not, then remove the current entry, and add it after lastEntry
|
||||
(which is usually at the end).
|
||||
*/
|
||||
private final void fixEntry(PatternEntry newEntry) throws ParseException
|
||||
{
|
||||
// check to see whether the new entry has the same characters as the previous
|
||||
// entry did (this can happen when a pattern declaring a difference between two
|
||||
// strings that are canonically equivalent is normalized). If so, and the strength
|
||||
// is anything other than IDENTICAL or RESET, throw an exception (you can't
|
||||
// declare a string to be unequal to itself). --rtg 5/24/99
|
||||
if (lastEntry != null && newEntry.chars.equals(lastEntry.chars)
|
||||
&& newEntry.extension.equals(lastEntry.extension)) {
|
||||
if (newEntry.strength != Collator.IDENTICAL
|
||||
&& newEntry.strength != PatternEntry.RESET) {
|
||||
throw new ParseException("The entries " + lastEntry + " and "
|
||||
+ newEntry + " are adjacent in the rules, but have conflicting "
|
||||
+ "strengths: A character can't be unequal to itself.", -1);
|
||||
} else {
|
||||
// otherwise, just skip this entry and behave as though you never saw it
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
boolean changeLastEntry = true;
|
||||
if (newEntry.strength != PatternEntry.RESET) {
|
||||
int oldIndex = -1;
|
||||
|
||||
if ((newEntry.chars.length() == 1)) {
|
||||
|
||||
char c = newEntry.chars.charAt(0);
|
||||
int statusIndex = c >> BYTEPOWER;
|
||||
byte bitClump = statusArray[statusIndex];
|
||||
byte setBit = (byte)(BITARRAYMASK << (c & BYTEMASK));
|
||||
|
||||
if (bitClump != 0 && (bitClump & setBit) != 0) {
|
||||
oldIndex = patterns.lastIndexOf(newEntry);
|
||||
} else {
|
||||
// We're going to add an element that starts with this
|
||||
// character, so go ahead and set its bit.
|
||||
statusArray[statusIndex] = (byte)(bitClump | setBit);
|
||||
}
|
||||
} else {
|
||||
oldIndex = patterns.lastIndexOf(newEntry);
|
||||
}
|
||||
if (oldIndex != -1) {
|
||||
patterns.remove(oldIndex);
|
||||
}
|
||||
|
||||
excess.setLength(0);
|
||||
int lastIndex = findLastEntry(lastEntry, excess);
|
||||
|
||||
if (excess.length() != 0) {
|
||||
newEntry.extension = excess + newEntry.extension;
|
||||
if (lastIndex != patterns.size()) {
|
||||
lastEntry = saveEntry;
|
||||
changeLastEntry = false;
|
||||
}
|
||||
}
|
||||
if (lastIndex == patterns.size()) {
|
||||
patterns.add(newEntry);
|
||||
saveEntry = newEntry;
|
||||
} else {
|
||||
patterns.add(lastIndex, newEntry);
|
||||
}
|
||||
}
|
||||
if (changeLastEntry) {
|
||||
lastEntry = newEntry;
|
||||
}
|
||||
}
|
||||
|
||||
private final int findLastEntry(PatternEntry entry,
|
||||
StringBuffer excessChars) throws ParseException
|
||||
{
|
||||
if (entry == null)
|
||||
return 0;
|
||||
|
||||
if (entry.strength != PatternEntry.RESET) {
|
||||
// Search backwards for string that contains this one;
|
||||
// most likely entry is last one
|
||||
|
||||
int oldIndex = -1;
|
||||
if ((entry.chars.length() == 1)) {
|
||||
int index = entry.chars.charAt(0) >> BYTEPOWER;
|
||||
if ((statusArray[index] &
|
||||
(BITARRAYMASK << (entry.chars.charAt(0) & BYTEMASK))) != 0) {
|
||||
oldIndex = patterns.lastIndexOf(entry);
|
||||
}
|
||||
} else {
|
||||
oldIndex = patterns.lastIndexOf(entry);
|
||||
}
|
||||
if ((oldIndex == -1))
|
||||
throw new ParseException("couldn't find last entry: "
|
||||
+ entry, oldIndex);
|
||||
return oldIndex + 1;
|
||||
} else {
|
||||
int i;
|
||||
for (i = patterns.size() - 1; i >= 0; --i) {
|
||||
PatternEntry e = patterns.get(i);
|
||||
if (e.chars.regionMatches(0,entry.chars,0,
|
||||
e.chars.length())) {
|
||||
excessChars.append(entry.chars.substring(e.chars.length(),
|
||||
entry.chars.length()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == -1)
|
||||
throw new ParseException("couldn't find: " + entry, i);
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
1642
jdkSrc/jdk8/java/text/MessageFormat.java
Normal file
1642
jdkSrc/jdk8/java/text/MessageFormat.java
Normal file
File diff suppressed because it is too large
Load Diff
179
jdkSrc/jdk8/java/text/Normalizer.java
Normal file
179
jdkSrc/jdk8/java/text/Normalizer.java
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved *
|
||||
* *
|
||||
* The original version of this source code and documentation is copyrighted *
|
||||
* and owned by IBM, These materials are provided under terms of a License *
|
||||
* Agreement between IBM and Sun. This technology is protected by multiple *
|
||||
* US and International patents. This notice and attribution to IBM may not *
|
||||
* to removed. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
import sun.text.normalizer.NormalizerBase;
|
||||
import sun.text.normalizer.NormalizerImpl;
|
||||
|
||||
/**
|
||||
* This class provides the method <code>normalize</code> which transforms Unicode
|
||||
* text into an equivalent composed or decomposed form, allowing for easier
|
||||
* sorting and searching of text.
|
||||
* The <code>normalize</code> method supports the standard normalization forms
|
||||
* described in
|
||||
* <a href="http://www.unicode.org/unicode/reports/tr15/tr15-23.html">
|
||||
* Unicode Standard Annex #15 — Unicode Normalization Forms</a>.
|
||||
* <p>
|
||||
* Characters with accents or other adornments can be encoded in
|
||||
* several different ways in Unicode. For example, take the character A-acute.
|
||||
* In Unicode, this can be encoded as a single character (the "composed" form):
|
||||
*
|
||||
* <pre>
|
||||
* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE</pre>
|
||||
*
|
||||
* or as two separate characters (the "decomposed" form):
|
||||
*
|
||||
* <pre>
|
||||
* U+0041 LATIN CAPITAL LETTER A
|
||||
* U+0301 COMBINING ACUTE ACCENT</pre>
|
||||
*
|
||||
* To a user of your program, however, both of these sequences should be
|
||||
* treated as the same "user-level" character "A with acute accent". When you
|
||||
* are searching or comparing text, you must ensure that these two sequences are
|
||||
* treated as equivalent. In addition, you must handle characters with more than
|
||||
* one accent. Sometimes the order of a character's combining accents is
|
||||
* significant, while in other cases accent sequences in different orders are
|
||||
* really equivalent.
|
||||
* <p>
|
||||
* Similarly, the string "ffi" can be encoded as three separate letters:
|
||||
*
|
||||
* <pre>
|
||||
* U+0066 LATIN SMALL LETTER F
|
||||
* U+0066 LATIN SMALL LETTER F
|
||||
* U+0069 LATIN SMALL LETTER I</pre>
|
||||
*
|
||||
* or as the single character
|
||||
*
|
||||
* <pre>
|
||||
* U+FB03 LATIN SMALL LIGATURE FFI</pre>
|
||||
*
|
||||
* The ffi ligature is not a distinct semantic character, and strictly speaking
|
||||
* it shouldn't be in Unicode at all, but it was included for compatibility
|
||||
* with existing character sets that already provided it. The Unicode standard
|
||||
* identifies such characters by giving them "compatibility" decompositions
|
||||
* into the corresponding semantic characters. When sorting and searching, you
|
||||
* will often want to use these mappings.
|
||||
* <p>
|
||||
* The <code>normalize</code> method helps solve these problems by transforming
|
||||
* text into the canonical composed and decomposed forms as shown in the first
|
||||
* example above. In addition, you can have it perform compatibility
|
||||
* decompositions so that you can treat compatibility characters the same as
|
||||
* their equivalents.
|
||||
* Finally, the <code>normalize</code> method rearranges accents into the
|
||||
* proper canonical order, so that you do not have to worry about accent
|
||||
* rearrangement on your own.
|
||||
* <p>
|
||||
* The W3C generally recommends to exchange texts in NFC.
|
||||
* Note also that most legacy character encodings use only precomposed forms and
|
||||
* often do not encode any combining marks by themselves. For conversion to such
|
||||
* character encodings the Unicode text needs to be normalized to NFC.
|
||||
* For more usage examples, see the Unicode Standard Annex.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public final class Normalizer {
|
||||
|
||||
private Normalizer() {};
|
||||
|
||||
/**
|
||||
* This enum provides constants of the four Unicode normalization forms
|
||||
* that are described in
|
||||
* <a href="http://www.unicode.org/unicode/reports/tr15/tr15-23.html">
|
||||
* Unicode Standard Annex #15 — Unicode Normalization Forms</a>
|
||||
* and two methods to access them.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public static enum Form {
|
||||
|
||||
/**
|
||||
* Canonical decomposition.
|
||||
*/
|
||||
NFD,
|
||||
|
||||
/**
|
||||
* Canonical decomposition, followed by canonical composition.
|
||||
*/
|
||||
NFC,
|
||||
|
||||
/**
|
||||
* Compatibility decomposition.
|
||||
*/
|
||||
NFKD,
|
||||
|
||||
/**
|
||||
* Compatibility decomposition, followed by canonical composition.
|
||||
*/
|
||||
NFKC
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a sequence of char values.
|
||||
* The sequence will be normalized according to the specified normalization
|
||||
* from.
|
||||
* @param src The sequence of char values to normalize.
|
||||
* @param form The normalization form; one of
|
||||
* {@link java.text.Normalizer.Form#NFC},
|
||||
* {@link java.text.Normalizer.Form#NFD},
|
||||
* {@link java.text.Normalizer.Form#NFKC},
|
||||
* {@link java.text.Normalizer.Form#NFKD}
|
||||
* @return The normalized String
|
||||
* @throws NullPointerException If <code>src</code> or <code>form</code>
|
||||
* is null.
|
||||
*/
|
||||
public static String normalize(CharSequence src, Form form) {
|
||||
return NormalizerBase.normalize(src.toString(), form);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the given sequence of char values is normalized.
|
||||
* @param src The sequence of char values to be checked.
|
||||
* @param form The normalization form; one of
|
||||
* {@link java.text.Normalizer.Form#NFC},
|
||||
* {@link java.text.Normalizer.Form#NFD},
|
||||
* {@link java.text.Normalizer.Form#NFKC},
|
||||
* {@link java.text.Normalizer.Form#NFKD}
|
||||
* @return true if the sequence of char values is normalized;
|
||||
* false otherwise.
|
||||
* @throws NullPointerException If <code>src</code> or <code>form</code>
|
||||
* is null.
|
||||
*/
|
||||
public static boolean isNormalized(CharSequence src, Form form) {
|
||||
return NormalizerBase.isNormalized(src.toString(), form);
|
||||
}
|
||||
}
|
||||
1234
jdkSrc/jdk8/java/text/NumberFormat.java
Normal file
1234
jdkSrc/jdk8/java/text/NumberFormat.java
Normal file
File diff suppressed because it is too large
Load Diff
83
jdkSrc/jdk8/java/text/ParseException.java
Normal file
83
jdkSrc/jdk8/java/text/ParseException.java
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is copyrighted
|
||||
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
|
||||
* materials are provided under terms of a License Agreement between Taligent
|
||||
* and Sun. This technology is protected by multiple US and International
|
||||
* patents. This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
/**
|
||||
* Signals that an error has been reached unexpectedly
|
||||
* while parsing.
|
||||
* @see java.lang.Exception
|
||||
* @see java.text.Format
|
||||
* @see java.text.FieldPosition
|
||||
* @author Mark Davis
|
||||
*/
|
||||
public
|
||||
class ParseException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 2703218443322787634L;
|
||||
|
||||
/**
|
||||
* Constructs a ParseException with the specified detail message and
|
||||
* offset.
|
||||
* A detail message is a String that describes this particular exception.
|
||||
*
|
||||
* @param s the detail message
|
||||
* @param errorOffset the position where the error is found while parsing.
|
||||
*/
|
||||
public ParseException(String s, int errorOffset) {
|
||||
super(s);
|
||||
this.errorOffset = errorOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position where the error was found.
|
||||
*
|
||||
* @return the position where the error was found
|
||||
*/
|
||||
public int getErrorOffset () {
|
||||
return errorOffset;
|
||||
}
|
||||
|
||||
//============ privates ============
|
||||
/**
|
||||
* The zero-based character offset into the string being parsed at which
|
||||
* the error was found during parsing.
|
||||
* @serial
|
||||
*/
|
||||
private int errorOffset;
|
||||
}
|
||||
150
jdkSrc/jdk8/java/text/ParsePosition.java
Normal file
150
jdkSrc/jdk8/java/text/ParsePosition.java
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is copyrighted
|
||||
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
|
||||
* materials are provided under terms of a License Agreement between Taligent
|
||||
* and Sun. This technology is protected by multiple US and International
|
||||
* patents. This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
|
||||
/**
|
||||
* <code>ParsePosition</code> is a simple class used by <code>Format</code>
|
||||
* and its subclasses to keep track of the current position during parsing.
|
||||
* The <code>parseObject</code> method in the various <code>Format</code>
|
||||
* classes requires a <code>ParsePosition</code> object as an argument.
|
||||
*
|
||||
* <p>
|
||||
* By design, as you parse through a string with different formats,
|
||||
* you can use the same <code>ParsePosition</code>, since the index parameter
|
||||
* records the current position.
|
||||
*
|
||||
* @author Mark Davis
|
||||
* @see java.text.Format
|
||||
*/
|
||||
|
||||
public class ParsePosition {
|
||||
|
||||
/**
|
||||
* Input: the place you start parsing.
|
||||
* <br>Output: position where the parse stopped.
|
||||
* This is designed to be used serially,
|
||||
* with each call setting index up for the next one.
|
||||
*/
|
||||
int index = 0;
|
||||
int errorIndex = -1;
|
||||
|
||||
/**
|
||||
* Retrieve the current parse position. On input to a parse method, this
|
||||
* is the index of the character at which parsing will begin; on output, it
|
||||
* is the index of the character following the last character parsed.
|
||||
*
|
||||
* @return the current parse position
|
||||
*/
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current parse position.
|
||||
*
|
||||
* @param index the current parse position
|
||||
*/
|
||||
public void setIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ParsePosition with the given initial index.
|
||||
*
|
||||
* @param index initial index
|
||||
*/
|
||||
public ParsePosition(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
/**
|
||||
* Set the index at which a parse error occurred. Formatters
|
||||
* should set this before returning an error code from their
|
||||
* parseObject method. The default value is -1 if this is not set.
|
||||
*
|
||||
* @param ei the index at which an error occurred
|
||||
* @since 1.2
|
||||
*/
|
||||
public void setErrorIndex(int ei)
|
||||
{
|
||||
errorIndex = ei;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the index at which an error occurred, or -1 if the
|
||||
* error index has not been set.
|
||||
*
|
||||
* @return the index at which an error occurred
|
||||
* @since 1.2
|
||||
*/
|
||||
public int getErrorIndex()
|
||||
{
|
||||
return errorIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides equals
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj == null) return false;
|
||||
if (!(obj instanceof ParsePosition))
|
||||
return false;
|
||||
ParsePosition other = (ParsePosition) obj;
|
||||
return (index == other.index && errorIndex == other.errorIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code for this ParsePosition.
|
||||
* @return a hash code value for this object
|
||||
*/
|
||||
public int hashCode() {
|
||||
return (errorIndex << 16) | index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string representation of this ParsePosition.
|
||||
* @return a string representation of this object
|
||||
*/
|
||||
public String toString() {
|
||||
return getClass().getName() +
|
||||
"[index=" + index +
|
||||
",errorIndex=" + errorIndex + ']';
|
||||
}
|
||||
}
|
||||
306
jdkSrc/jdk8/java/text/PatternEntry.java
Normal file
306
jdkSrc/jdk8/java/text/PatternEntry.java
Normal file
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996, 1997 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is copyrighted
|
||||
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
|
||||
* materials are provided under terms of a License Agreement between Taligent
|
||||
* and Sun. This technology is protected by multiple US and International
|
||||
* patents. This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.lang.Character;
|
||||
|
||||
/**
|
||||
* Utility class for normalizing and merging patterns for collation.
|
||||
* This is to be used with MergeCollation for adding patterns to an
|
||||
* existing rule table.
|
||||
* @see MergeCollation
|
||||
* @author Mark Davis, Helena Shih
|
||||
*/
|
||||
|
||||
class PatternEntry {
|
||||
/**
|
||||
* Gets the current extension, quoted
|
||||
*/
|
||||
public void appendQuotedExtension(StringBuffer toAddTo) {
|
||||
appendQuoted(extension,toAddTo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current chars, quoted
|
||||
*/
|
||||
public void appendQuotedChars(StringBuffer toAddTo) {
|
||||
appendQuoted(chars,toAddTo);
|
||||
}
|
||||
|
||||
/**
|
||||
* WARNING this is used for searching in a Vector.
|
||||
* Because Vector.indexOf doesn't take a comparator,
|
||||
* this method is ill-defined and ignores strength.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) return false;
|
||||
PatternEntry other = (PatternEntry) obj;
|
||||
boolean result = chars.equals(other.chars);
|
||||
return result;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return chars.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* For debugging.
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuffer result = new StringBuffer();
|
||||
addToBuffer(result, true, false, null);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the strength of the entry.
|
||||
*/
|
||||
final int getStrength() {
|
||||
return strength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expanding characters of the entry.
|
||||
*/
|
||||
final String getExtension() {
|
||||
return extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the core characters of the entry.
|
||||
*/
|
||||
final String getChars() {
|
||||
return chars;
|
||||
}
|
||||
|
||||
// ===== privates =====
|
||||
|
||||
void addToBuffer(StringBuffer toAddTo,
|
||||
boolean showExtension,
|
||||
boolean showWhiteSpace,
|
||||
PatternEntry lastEntry)
|
||||
{
|
||||
if (showWhiteSpace && toAddTo.length() > 0)
|
||||
if (strength == Collator.PRIMARY || lastEntry != null)
|
||||
toAddTo.append('\n');
|
||||
else
|
||||
toAddTo.append(' ');
|
||||
if (lastEntry != null) {
|
||||
toAddTo.append('&');
|
||||
if (showWhiteSpace)
|
||||
toAddTo.append(' ');
|
||||
lastEntry.appendQuotedChars(toAddTo);
|
||||
appendQuotedExtension(toAddTo);
|
||||
if (showWhiteSpace)
|
||||
toAddTo.append(' ');
|
||||
}
|
||||
switch (strength) {
|
||||
case Collator.IDENTICAL: toAddTo.append('='); break;
|
||||
case Collator.TERTIARY: toAddTo.append(','); break;
|
||||
case Collator.SECONDARY: toAddTo.append(';'); break;
|
||||
case Collator.PRIMARY: toAddTo.append('<'); break;
|
||||
case RESET: toAddTo.append('&'); break;
|
||||
case UNSET: toAddTo.append('?'); break;
|
||||
}
|
||||
if (showWhiteSpace)
|
||||
toAddTo.append(' ');
|
||||
appendQuoted(chars,toAddTo);
|
||||
if (showExtension && extension.length() != 0) {
|
||||
toAddTo.append('/');
|
||||
appendQuoted(extension,toAddTo);
|
||||
}
|
||||
}
|
||||
|
||||
static void appendQuoted(String chars, StringBuffer toAddTo) {
|
||||
boolean inQuote = false;
|
||||
char ch = chars.charAt(0);
|
||||
if (Character.isSpaceChar(ch)) {
|
||||
inQuote = true;
|
||||
toAddTo.append('\'');
|
||||
} else {
|
||||
if (PatternEntry.isSpecialChar(ch)) {
|
||||
inQuote = true;
|
||||
toAddTo.append('\'');
|
||||
} else {
|
||||
switch (ch) {
|
||||
case 0x0010: case '\f': case '\r':
|
||||
case '\t': case '\n': case '@':
|
||||
inQuote = true;
|
||||
toAddTo.append('\'');
|
||||
break;
|
||||
case '\'':
|
||||
inQuote = true;
|
||||
toAddTo.append('\'');
|
||||
break;
|
||||
default:
|
||||
if (inQuote) {
|
||||
inQuote = false; toAddTo.append('\'');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
toAddTo.append(chars);
|
||||
if (inQuote)
|
||||
toAddTo.append('\'');
|
||||
}
|
||||
|
||||
//========================================================================
|
||||
// Parsing a pattern into a list of PatternEntries....
|
||||
//========================================================================
|
||||
|
||||
PatternEntry(int strength,
|
||||
StringBuffer chars,
|
||||
StringBuffer extension)
|
||||
{
|
||||
this.strength = strength;
|
||||
this.chars = chars.toString();
|
||||
this.extension = (extension.length() > 0) ? extension.toString()
|
||||
: "";
|
||||
}
|
||||
|
||||
static class Parser {
|
||||
private String pattern;
|
||||
private int i;
|
||||
|
||||
public Parser(String pattern) {
|
||||
this.pattern = pattern;
|
||||
this.i = 0;
|
||||
}
|
||||
|
||||
public PatternEntry next() throws ParseException {
|
||||
int newStrength = UNSET;
|
||||
|
||||
newChars.setLength(0);
|
||||
newExtension.setLength(0);
|
||||
|
||||
boolean inChars = true;
|
||||
boolean inQuote = false;
|
||||
mainLoop:
|
||||
while (i < pattern.length()) {
|
||||
char ch = pattern.charAt(i);
|
||||
if (inQuote) {
|
||||
if (ch == '\'') {
|
||||
inQuote = false;
|
||||
} else {
|
||||
if (newChars.length() == 0) newChars.append(ch);
|
||||
else if (inChars) newChars.append(ch);
|
||||
else newExtension.append(ch);
|
||||
}
|
||||
} else switch (ch) {
|
||||
case '=': if (newStrength != UNSET) break mainLoop;
|
||||
newStrength = Collator.IDENTICAL; break;
|
||||
case ',': if (newStrength != UNSET) break mainLoop;
|
||||
newStrength = Collator.TERTIARY; break;
|
||||
case ';': if (newStrength != UNSET) break mainLoop;
|
||||
newStrength = Collator.SECONDARY; break;
|
||||
case '<': if (newStrength != UNSET) break mainLoop;
|
||||
newStrength = Collator.PRIMARY; break;
|
||||
case '&': if (newStrength != UNSET) break mainLoop;
|
||||
newStrength = RESET; break;
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\f':
|
||||
case '\r':
|
||||
case ' ': break; // skip whitespace TODO use Character
|
||||
case '/': inChars = false; break;
|
||||
case '\'':
|
||||
inQuote = true;
|
||||
ch = pattern.charAt(++i);
|
||||
if (newChars.length() == 0) newChars.append(ch);
|
||||
else if (inChars) newChars.append(ch);
|
||||
else newExtension.append(ch);
|
||||
break;
|
||||
default:
|
||||
if (newStrength == UNSET) {
|
||||
throw new ParseException
|
||||
("missing char (=,;<&) : " +
|
||||
pattern.substring(i,
|
||||
(i+10 < pattern.length()) ?
|
||||
i+10 : pattern.length()),
|
||||
i);
|
||||
}
|
||||
if (PatternEntry.isSpecialChar(ch) && (inQuote == false))
|
||||
throw new ParseException
|
||||
("Unquoted punctuation character : " + Integer.toString(ch, 16), i);
|
||||
if (inChars) {
|
||||
newChars.append(ch);
|
||||
} else {
|
||||
newExtension.append(ch);
|
||||
}
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (newStrength == UNSET)
|
||||
return null;
|
||||
if (newChars.length() == 0) {
|
||||
throw new ParseException
|
||||
("missing chars (=,;<&): " +
|
||||
pattern.substring(i,
|
||||
(i+10 < pattern.length()) ?
|
||||
i+10 : pattern.length()),
|
||||
i);
|
||||
}
|
||||
|
||||
return new PatternEntry(newStrength, newChars, newExtension);
|
||||
}
|
||||
|
||||
// We re-use these objects in order to improve performance
|
||||
private StringBuffer newChars = new StringBuffer();
|
||||
private StringBuffer newExtension = new StringBuffer();
|
||||
|
||||
}
|
||||
|
||||
static boolean isSpecialChar(char ch) {
|
||||
return ((ch == '\u0020') ||
|
||||
((ch <= '\u002F') && (ch >= '\u0022')) ||
|
||||
((ch <= '\u003F') && (ch >= '\u003A')) ||
|
||||
((ch <= '\u0060') && (ch >= '\u005B')) ||
|
||||
((ch <= '\u007E') && (ch >= '\u007B')));
|
||||
}
|
||||
|
||||
|
||||
static final int RESET = -2;
|
||||
static final int UNSET = -1;
|
||||
|
||||
int strength = UNSET;
|
||||
String chars = "";
|
||||
String extension = "";
|
||||
}
|
||||
301
jdkSrc/jdk8/java/text/RBCollationTables.java
Normal file
301
jdkSrc/jdk8/java/text/RBCollationTables.java
Normal file
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is copyrighted
|
||||
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
|
||||
* materials are provided under terms of a License Agreement between Taligent
|
||||
* and Sun. This technology is protected by multiple US and International
|
||||
* patents. This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.util.Vector;
|
||||
import sun.text.UCompactIntArray;
|
||||
import sun.text.IntHashtable;
|
||||
|
||||
/**
|
||||
* This class contains the static state of a RuleBasedCollator: The various
|
||||
* tables that are used by the collation routines. Several RuleBasedCollators
|
||||
* can share a single RBCollationTables object, easing memory requirements and
|
||||
* improving performance.
|
||||
*/
|
||||
final class RBCollationTables {
|
||||
//===========================================================================================
|
||||
// The following diagram shows the data structure of the RBCollationTables object.
|
||||
// Suppose we have the rule, where 'o-umlaut' is the unicode char 0x00F6.
|
||||
// "a, A < b, B < c, C, ch, cH, Ch, CH < d, D ... < o, O; 'o-umlaut'/E, 'O-umlaut'/E ...".
|
||||
// What the rule says is, sorts 'ch'ligatures and 'c' only with tertiary difference and
|
||||
// sorts 'o-umlaut' as if it's always expanded with 'e'.
|
||||
//
|
||||
// mapping table contracting list expanding list
|
||||
// (contains all unicode char
|
||||
// entries) ___ ____________ _________________________
|
||||
// ________ +>|_*_|->|'c' |v('c') | +>|v('o')|v('umlaut')|v('e')|
|
||||
// |_\u0001_|-> v('\u0001') | |_:_| |------------| | |-------------------------|
|
||||
// |_\u0002_|-> v('\u0002') | |_:_| |'ch'|v('ch')| | | : |
|
||||
// |____:___| | |_:_| |------------| | |-------------------------|
|
||||
// |____:___| | |'cH'|v('cH')| | | : |
|
||||
// |__'a'___|-> v('a') | |------------| | |-------------------------|
|
||||
// |__'b'___|-> v('b') | |'Ch'|v('Ch')| | | : |
|
||||
// |____:___| | |------------| | |-------------------------|
|
||||
// |____:___| | |'CH'|v('CH')| | | : |
|
||||
// |___'c'__|---------------- ------------ | |-------------------------|
|
||||
// |____:___| | | : |
|
||||
// |o-umlaut|---------------------------------------- |_________________________|
|
||||
// |____:___|
|
||||
//
|
||||
// Noted by Helena Shih on 6/23/97
|
||||
//============================================================================================
|
||||
|
||||
public RBCollationTables(String rules, int decmp) throws ParseException {
|
||||
this.rules = rules;
|
||||
|
||||
RBTableBuilder builder = new RBTableBuilder(new BuildAPI());
|
||||
builder.build(rules, decmp); // this object is filled in through
|
||||
// the BuildAPI object
|
||||
}
|
||||
|
||||
final class BuildAPI {
|
||||
/**
|
||||
* Private constructor. Prevents anyone else besides RBTableBuilder
|
||||
* from gaining direct access to the internals of this class.
|
||||
*/
|
||||
private BuildAPI() {
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is used by RBTableBuilder to fill in all the members of this
|
||||
* object. (Effectively, the builder class functions as a "friend" of this
|
||||
* class, but to avoid changing too much of the logic, it carries around "shadow"
|
||||
* copies of all these variables until the end of the build process and then
|
||||
* copies them en masse into the actual tables object once all the construction
|
||||
* logic is complete. This function does that "copying en masse".
|
||||
* @param f2ary The value for frenchSec (the French-secondary flag)
|
||||
* @param swap The value for SE Asian swapping rule
|
||||
* @param map The collator's character-mapping table (the value for mapping)
|
||||
* @param cTbl The collator's contracting-character table (the value for contractTable)
|
||||
* @param eTbl The collator's expanding-character table (the value for expandTable)
|
||||
* @param cFlgs The hash table of characters that participate in contracting-
|
||||
* character sequences (the value for contractFlags)
|
||||
* @param mso The value for maxSecOrder
|
||||
* @param mto The value for maxTerOrder
|
||||
*/
|
||||
void fillInTables(boolean f2ary,
|
||||
boolean swap,
|
||||
UCompactIntArray map,
|
||||
Vector<Vector<EntryPair>> cTbl,
|
||||
Vector<int[]> eTbl,
|
||||
IntHashtable cFlgs,
|
||||
short mso,
|
||||
short mto) {
|
||||
frenchSec = f2ary;
|
||||
seAsianSwapping = swap;
|
||||
mapping = map;
|
||||
contractTable = cTbl;
|
||||
expandTable = eTbl;
|
||||
contractFlags = cFlgs;
|
||||
maxSecOrder = mso;
|
||||
maxTerOrder = mto;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the table-based rules for the collation object.
|
||||
* @return returns the collation rules that the table collation object
|
||||
* was created from.
|
||||
*/
|
||||
public String getRules()
|
||||
{
|
||||
return rules;
|
||||
}
|
||||
|
||||
public boolean isFrenchSec() {
|
||||
return frenchSec;
|
||||
}
|
||||
|
||||
public boolean isSEAsianSwapping() {
|
||||
return seAsianSwapping;
|
||||
}
|
||||
|
||||
// ==============================================================
|
||||
// internal (for use by CollationElementIterator)
|
||||
// ==============================================================
|
||||
|
||||
/**
|
||||
* Get the entry of hash table of the contracting string in the collation
|
||||
* table.
|
||||
* @param ch the starting character of the contracting string
|
||||
*/
|
||||
Vector<EntryPair> getContractValues(int ch)
|
||||
{
|
||||
int index = mapping.elementAt(ch);
|
||||
return getContractValuesImpl(index - CONTRACTCHARINDEX);
|
||||
}
|
||||
|
||||
//get contract values from contractTable by index
|
||||
private Vector<EntryPair> getContractValuesImpl(int index)
|
||||
{
|
||||
if (index >= 0)
|
||||
{
|
||||
return contractTable.elementAt(index);
|
||||
}
|
||||
else // not found
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this character appears anywhere in a contracting
|
||||
* character sequence. (Used by CollationElementIterator.setOffset().)
|
||||
*/
|
||||
boolean usedInContractSeq(int c) {
|
||||
return contractFlags.get(c) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum length of any expansion sequences that end
|
||||
* with the specified comparison order.
|
||||
*
|
||||
* @param order a collation order returned by previous or next.
|
||||
* @return the maximum length of any expansion seuences ending
|
||||
* with the specified order.
|
||||
*
|
||||
* @see CollationElementIterator#getMaxExpansion
|
||||
*/
|
||||
int getMaxExpansion(int order) {
|
||||
int result = 1;
|
||||
|
||||
if (expandTable != null) {
|
||||
// Right now this does a linear search through the entire
|
||||
// expansion table. If a collator had a large number of expansions,
|
||||
// this could cause a performance problem, but in practise that
|
||||
// rarely happens
|
||||
for (int i = 0; i < expandTable.size(); i++) {
|
||||
int[] valueList = expandTable.elementAt(i);
|
||||
int length = valueList.length;
|
||||
|
||||
if (length > result && valueList[length-1] == order) {
|
||||
result = length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entry of hash table of the expanding string in the collation
|
||||
* table.
|
||||
* @param idx the index of the expanding string value list
|
||||
*/
|
||||
final int[] getExpandValueList(int idx) {
|
||||
return expandTable.elementAt(idx - EXPANDCHARINDEX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the comarison order of a character from the collation table.
|
||||
* @return the comparison order of a character.
|
||||
*/
|
||||
int getUnicodeOrder(int ch) {
|
||||
return mapping.elementAt(ch);
|
||||
}
|
||||
|
||||
short getMaxSecOrder() {
|
||||
return maxSecOrder;
|
||||
}
|
||||
|
||||
short getMaxTerOrder() {
|
||||
return maxTerOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse a string.
|
||||
*/
|
||||
//shemran/Note: this is used for secondary order value reverse, no
|
||||
// need to consider supplementary pair.
|
||||
static void reverse (StringBuffer result, int from, int to)
|
||||
{
|
||||
int i = from;
|
||||
char swap;
|
||||
|
||||
int j = to - 1;
|
||||
while (i < j) {
|
||||
swap = result.charAt(i);
|
||||
result.setCharAt(i, result.charAt(j));
|
||||
result.setCharAt(j, swap);
|
||||
i++;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
|
||||
final static int getEntry(Vector<EntryPair> list, String name, boolean fwd) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
EntryPair pair = list.elementAt(i);
|
||||
if (pair.fwd == fwd && pair.entryName.equals(name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return UNMAPPED;
|
||||
}
|
||||
|
||||
// ==============================================================
|
||||
// constants
|
||||
// ==============================================================
|
||||
//sherman/Todo: is the value big enough?????
|
||||
final static int EXPANDCHARINDEX = 0x7E000000; // Expand index follows
|
||||
final static int CONTRACTCHARINDEX = 0x7F000000; // contract indexes follow
|
||||
final static int UNMAPPED = 0xFFFFFFFF;
|
||||
|
||||
final static int PRIMARYORDERMASK = 0xffff0000;
|
||||
final static int SECONDARYORDERMASK = 0x0000ff00;
|
||||
final static int TERTIARYORDERMASK = 0x000000ff;
|
||||
final static int PRIMARYDIFFERENCEONLY = 0xffff0000;
|
||||
final static int SECONDARYDIFFERENCEONLY = 0xffffff00;
|
||||
final static int PRIMARYORDERSHIFT = 16;
|
||||
final static int SECONDARYORDERSHIFT = 8;
|
||||
|
||||
// ==============================================================
|
||||
// instance variables
|
||||
// ==============================================================
|
||||
private String rules = null;
|
||||
private boolean frenchSec = false;
|
||||
private boolean seAsianSwapping = false;
|
||||
|
||||
private UCompactIntArray mapping = null;
|
||||
private Vector<Vector<EntryPair>> contractTable = null;
|
||||
private Vector<int[]> expandTable = null;
|
||||
private IntHashtable contractFlags = null;
|
||||
|
||||
private short maxSecOrder = 0;
|
||||
private short maxTerOrder = 0;
|
||||
}
|
||||
618
jdkSrc/jdk8/java/text/RBTableBuilder.java
Normal file
618
jdkSrc/jdk8/java/text/RBTableBuilder.java
Normal file
@@ -0,0 +1,618 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is copyrighted
|
||||
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
|
||||
* materials are provided under terms of a License Agreement between Taligent
|
||||
* and Sun. This technology is protected by multiple US and International
|
||||
* patents. This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.util.Vector;
|
||||
import sun.text.UCompactIntArray;
|
||||
import sun.text.IntHashtable;
|
||||
import sun.text.ComposedCharIter;
|
||||
import sun.text.CollatorUtilities;
|
||||
import sun.text.normalizer.NormalizerImpl;
|
||||
|
||||
/**
|
||||
* This class contains all the code to parse a RuleBasedCollator pattern
|
||||
* and build a RBCollationTables object from it. A particular instance
|
||||
* of tis class exists only during the actual build process-- once an
|
||||
* RBCollationTables object has been built, the RBTableBuilder object
|
||||
* goes away. This object carries all of the state which is only needed
|
||||
* during the build process, plus a "shadow" copy of all of the state
|
||||
* that will go into the tables object itself. This object communicates
|
||||
* with RBCollationTables through a separate class, RBCollationTables.BuildAPI,
|
||||
* this is an inner class of RBCollationTables and provides a separate
|
||||
* private API for communication with RBTableBuilder.
|
||||
* This class isn't just an inner class of RBCollationTables itself because
|
||||
* of its large size. For source-code readability, it seemed better for the
|
||||
* builder to have its own source file.
|
||||
*/
|
||||
final class RBTableBuilder {
|
||||
|
||||
public RBTableBuilder(RBCollationTables.BuildAPI tables) {
|
||||
this.tables = tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a table-based collation object with the given rules.
|
||||
* This is the main function that actually builds the tables and
|
||||
* stores them back in the RBCollationTables object. It is called
|
||||
* ONLY by the RBCollationTables constructor.
|
||||
* @see RuleBasedCollator#RuleBasedCollator
|
||||
* @exception ParseException If the rules format is incorrect.
|
||||
*/
|
||||
|
||||
public void build(String pattern, int decmp) throws ParseException
|
||||
{
|
||||
boolean isSource = true;
|
||||
int i = 0;
|
||||
String expChars;
|
||||
String groupChars;
|
||||
if (pattern.length() == 0)
|
||||
throw new ParseException("Build rules empty.", 0);
|
||||
|
||||
// This array maps Unicode characters to their collation ordering
|
||||
mapping = new UCompactIntArray(RBCollationTables.UNMAPPED);
|
||||
// Normalize the build rules. Find occurances of all decomposed characters
|
||||
// and normalize the rules before feeding into the builder. By "normalize",
|
||||
// we mean that all precomposed Unicode characters must be converted into
|
||||
// a base character and one or more combining characters (such as accents).
|
||||
// When there are multiple combining characters attached to a base character,
|
||||
// the combining characters must be in their canonical order
|
||||
//
|
||||
// sherman/Note:
|
||||
//(1)decmp will be NO_DECOMPOSITION only in ko locale to prevent decompose
|
||||
//hangual syllables to jamos, so we can actually just call decompose with
|
||||
//normalizer's IGNORE_HANGUL option turned on
|
||||
//
|
||||
//(2)just call the "special version" in NormalizerImpl directly
|
||||
//pattern = Normalizer.decompose(pattern, false, Normalizer.IGNORE_HANGUL, true);
|
||||
//
|
||||
//Normalizer.Mode mode = CollatorUtilities.toNormalizerMode(decmp);
|
||||
//pattern = Normalizer.normalize(pattern, mode, 0, true);
|
||||
|
||||
pattern = NormalizerImpl.canonicalDecomposeWithSingleQuotation(pattern);
|
||||
|
||||
// Build the merged collation entries
|
||||
// Since rules can be specified in any order in the string
|
||||
// (e.g. "c , C < d , D < e , E .... C < CH")
|
||||
// this splits all of the rules in the string out into separate
|
||||
// objects and then sorts them. In the above example, it merges the
|
||||
// "C < CH" rule in just before the "C < D" rule.
|
||||
//
|
||||
|
||||
mPattern = new MergeCollation(pattern);
|
||||
|
||||
int order = 0;
|
||||
|
||||
// Now walk though each entry and add it to my own tables
|
||||
for (i = 0; i < mPattern.getCount(); ++i)
|
||||
{
|
||||
PatternEntry entry = mPattern.getItemAt(i);
|
||||
if (entry != null) {
|
||||
groupChars = entry.getChars();
|
||||
if (groupChars.length() > 1) {
|
||||
switch(groupChars.charAt(groupChars.length()-1)) {
|
||||
case '@':
|
||||
frenchSec = true;
|
||||
groupChars = groupChars.substring(0, groupChars.length()-1);
|
||||
break;
|
||||
case '!':
|
||||
seAsianSwapping = true;
|
||||
groupChars = groupChars.substring(0, groupChars.length()-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
order = increment(entry.getStrength(), order);
|
||||
expChars = entry.getExtension();
|
||||
|
||||
if (expChars.length() != 0) {
|
||||
addExpandOrder(groupChars, expChars, order);
|
||||
} else if (groupChars.length() > 1) {
|
||||
char ch = groupChars.charAt(0);
|
||||
if (Character.isHighSurrogate(ch) && groupChars.length() == 2) {
|
||||
addOrder(Character.toCodePoint(ch, groupChars.charAt(1)), order);
|
||||
} else {
|
||||
addContractOrder(groupChars, order);
|
||||
}
|
||||
} else {
|
||||
char ch = groupChars.charAt(0);
|
||||
addOrder(ch, order);
|
||||
}
|
||||
}
|
||||
}
|
||||
addComposedChars();
|
||||
|
||||
commit();
|
||||
mapping.compact();
|
||||
/*
|
||||
System.out.println("mappingSize=" + mapping.getKSize());
|
||||
for (int j = 0; j < 0xffff; j++) {
|
||||
int value = mapping.elementAt(j);
|
||||
if (value != RBCollationTables.UNMAPPED)
|
||||
System.out.println("index=" + Integer.toString(j, 16)
|
||||
+ ", value=" + Integer.toString(value, 16));
|
||||
}
|
||||
*/
|
||||
tables.fillInTables(frenchSec, seAsianSwapping, mapping, contractTable, expandTable,
|
||||
contractFlags, maxSecOrder, maxTerOrder);
|
||||
}
|
||||
|
||||
/** Add expanding entries for pre-composed unicode characters so that this
|
||||
* collator can be used reasonably well with decomposition turned off.
|
||||
*/
|
||||
private void addComposedChars() throws ParseException {
|
||||
// Iterate through all of the pre-composed characters in Unicode
|
||||
ComposedCharIter iter = new ComposedCharIter();
|
||||
int c;
|
||||
while ((c = iter.next()) != ComposedCharIter.DONE) {
|
||||
if (getCharOrder(c) == RBCollationTables.UNMAPPED) {
|
||||
//
|
||||
// We don't already have an ordering for this pre-composed character.
|
||||
//
|
||||
// First, see if the decomposed string is already in our
|
||||
// tables as a single contracting-string ordering.
|
||||
// If so, just map the precomposed character to that order.
|
||||
//
|
||||
// TODO: What we should really be doing here is trying to find the
|
||||
// longest initial substring of the decomposition that is present
|
||||
// in the tables as a contracting character sequence, and find its
|
||||
// ordering. Then do this recursively with the remaining chars
|
||||
// so that we build a list of orderings, and add that list to
|
||||
// the expansion table.
|
||||
// That would be more correct but also significantly slower, so
|
||||
// I'm not totally sure it's worth doing.
|
||||
//
|
||||
String s = iter.decomposition();
|
||||
|
||||
//sherman/Note: if this is 1 character decomposed string, the
|
||||
//only thing need to do is to check if this decomposed character
|
||||
//has an entry in our order table, this order is not necessary
|
||||
//to be a contraction order, if it does have one, add an entry
|
||||
//for the precomposed character by using the same order, the
|
||||
//previous impl unnecessarily adds a single character expansion
|
||||
//entry.
|
||||
if (s.length() == 1) {
|
||||
int order = getCharOrder(s.charAt(0));
|
||||
if (order != RBCollationTables.UNMAPPED) {
|
||||
addOrder(c, order);
|
||||
}
|
||||
continue;
|
||||
} else if (s.length() == 2) {
|
||||
char ch0 = s.charAt(0);
|
||||
if (Character.isHighSurrogate(ch0)) {
|
||||
int order = getCharOrder(s.codePointAt(0));
|
||||
if (order != RBCollationTables.UNMAPPED) {
|
||||
addOrder(c, order);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
int contractOrder = getContractOrder(s);
|
||||
if (contractOrder != RBCollationTables.UNMAPPED) {
|
||||
addOrder(c, contractOrder);
|
||||
} else {
|
||||
//
|
||||
// We don't have a contracting ordering for the entire string
|
||||
// that results from the decomposition, but if we have orders
|
||||
// for each individual character, we can add an expanding
|
||||
// table entry for the pre-composed character
|
||||
//
|
||||
boolean allThere = true;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
if (getCharOrder(s.charAt(i)) == RBCollationTables.UNMAPPED) {
|
||||
allThere = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allThere) {
|
||||
addExpandOrder(c, s, RBCollationTables.UNMAPPED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up for unmapped values in the expanded character table.
|
||||
*
|
||||
* When the expanding character tables are built by addExpandOrder,
|
||||
* it doesn't know what the final ordering of each character
|
||||
* in the expansion will be. Instead, it just puts the raw character
|
||||
* code into the table, adding CHARINDEX as a flag. Now that we've
|
||||
* finished building the mapping table, we can go back and look up
|
||||
* that character to see what its real collation order is and
|
||||
* stick that into the expansion table. That lets us avoid doing
|
||||
* a two-stage lookup later.
|
||||
*/
|
||||
private final void commit()
|
||||
{
|
||||
if (expandTable != null) {
|
||||
for (int i = 0; i < expandTable.size(); i++) {
|
||||
int[] valueList = expandTable.elementAt(i);
|
||||
for (int j = 0; j < valueList.length; j++) {
|
||||
int order = valueList[j];
|
||||
if (order < RBCollationTables.EXPANDCHARINDEX && order > CHARINDEX) {
|
||||
// found a expanding character that isn't filled in yet
|
||||
int ch = order - CHARINDEX;
|
||||
|
||||
// Get the real values for the non-filled entry
|
||||
int realValue = getCharOrder(ch);
|
||||
|
||||
if (realValue == RBCollationTables.UNMAPPED) {
|
||||
// The real value is still unmapped, maybe it's ignorable
|
||||
valueList[j] = IGNORABLEMASK & ch;
|
||||
} else {
|
||||
// just fill in the value
|
||||
valueList[j] = realValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Increment of the last order based on the comparison level.
|
||||
*/
|
||||
private final int increment(int aStrength, int lastValue)
|
||||
{
|
||||
switch(aStrength)
|
||||
{
|
||||
case Collator.PRIMARY:
|
||||
// increment priamry order and mask off secondary and tertiary difference
|
||||
lastValue += PRIMARYORDERINCREMENT;
|
||||
lastValue &= RBCollationTables.PRIMARYORDERMASK;
|
||||
isOverIgnore = true;
|
||||
break;
|
||||
case Collator.SECONDARY:
|
||||
// increment secondary order and mask off tertiary difference
|
||||
lastValue += SECONDARYORDERINCREMENT;
|
||||
lastValue &= RBCollationTables.SECONDARYDIFFERENCEONLY;
|
||||
// record max # of ignorable chars with secondary difference
|
||||
if (!isOverIgnore)
|
||||
maxSecOrder++;
|
||||
break;
|
||||
case Collator.TERTIARY:
|
||||
// increment tertiary order
|
||||
lastValue += TERTIARYORDERINCREMENT;
|
||||
// record max # of ignorable chars with tertiary difference
|
||||
if (!isOverIgnore)
|
||||
maxTerOrder++;
|
||||
break;
|
||||
}
|
||||
return lastValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a character and its designated order into the collation table.
|
||||
*/
|
||||
private final void addOrder(int ch, int anOrder)
|
||||
{
|
||||
// See if the char already has an order in the mapping table
|
||||
int order = mapping.elementAt(ch);
|
||||
|
||||
if (order >= RBCollationTables.CONTRACTCHARINDEX) {
|
||||
// There's already an entry for this character that points to a contracting
|
||||
// character table. Instead of adding the character directly to the mapping
|
||||
// table, we must add it to the contract table instead.
|
||||
int length = 1;
|
||||
if (Character.isSupplementaryCodePoint(ch)) {
|
||||
length = Character.toChars(ch, keyBuf, 0);
|
||||
} else {
|
||||
keyBuf[0] = (char)ch;
|
||||
}
|
||||
addContractOrder(new String(keyBuf, 0, length), anOrder);
|
||||
} else {
|
||||
// add the entry to the mapping table,
|
||||
// the same later entry replaces the previous one
|
||||
mapping.setElementAt(ch, anOrder);
|
||||
}
|
||||
}
|
||||
|
||||
private final void addContractOrder(String groupChars, int anOrder) {
|
||||
addContractOrder(groupChars, anOrder, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the contracting string into the collation table.
|
||||
*/
|
||||
private final void addContractOrder(String groupChars, int anOrder,
|
||||
boolean fwd)
|
||||
{
|
||||
if (contractTable == null) {
|
||||
contractTable = new Vector<>(INITIALTABLESIZE);
|
||||
}
|
||||
|
||||
//initial character
|
||||
int ch = groupChars.codePointAt(0);
|
||||
/*
|
||||
char ch0 = groupChars.charAt(0);
|
||||
int ch = Character.isHighSurrogate(ch0)?
|
||||
Character.toCodePoint(ch0, groupChars.charAt(1)):ch0;
|
||||
*/
|
||||
// See if the initial character of the string already has a contract table.
|
||||
int entry = mapping.elementAt(ch);
|
||||
Vector<EntryPair> entryTable = getContractValuesImpl(entry - RBCollationTables.CONTRACTCHARINDEX);
|
||||
|
||||
if (entryTable == null) {
|
||||
// We need to create a new table of contract entries for this base char
|
||||
int tableIndex = RBCollationTables.CONTRACTCHARINDEX + contractTable.size();
|
||||
entryTable = new Vector<>(INITIALTABLESIZE);
|
||||
contractTable.addElement(entryTable);
|
||||
|
||||
// Add the initial character's current ordering first. then
|
||||
// update its mapping to point to this contract table
|
||||
entryTable.addElement(new EntryPair(groupChars.substring(0,Character.charCount(ch)), entry));
|
||||
mapping.setElementAt(ch, tableIndex);
|
||||
}
|
||||
|
||||
// Now add (or replace) this string in the table
|
||||
int index = RBCollationTables.getEntry(entryTable, groupChars, fwd);
|
||||
if (index != RBCollationTables.UNMAPPED) {
|
||||
EntryPair pair = entryTable.elementAt(index);
|
||||
pair.value = anOrder;
|
||||
} else {
|
||||
EntryPair pair = entryTable.lastElement();
|
||||
|
||||
// NOTE: This little bit of logic is here to speed CollationElementIterator
|
||||
// .nextContractChar(). This code ensures that the longest sequence in
|
||||
// this list is always the _last_ one in the list. This keeps
|
||||
// nextContractChar() from having to search the entire list for the longest
|
||||
// sequence.
|
||||
if (groupChars.length() > pair.entryName.length()) {
|
||||
entryTable.addElement(new EntryPair(groupChars, anOrder, fwd));
|
||||
} else {
|
||||
entryTable.insertElementAt(new EntryPair(groupChars, anOrder,
|
||||
fwd), entryTable.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// If this was a forward mapping for a contracting string, also add a
|
||||
// reverse mapping for it, so that CollationElementIterator.previous
|
||||
// can work right
|
||||
if (fwd && groupChars.length() > 1) {
|
||||
addContractFlags(groupChars);
|
||||
addContractOrder(new StringBuffer(groupChars).reverse().toString(),
|
||||
anOrder, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the given string has been specified as a contracting string
|
||||
* in this collation table, return its ordering.
|
||||
* Otherwise return UNMAPPED.
|
||||
*/
|
||||
private int getContractOrder(String groupChars)
|
||||
{
|
||||
int result = RBCollationTables.UNMAPPED;
|
||||
if (contractTable != null) {
|
||||
int ch = groupChars.codePointAt(0);
|
||||
/*
|
||||
char ch0 = groupChars.charAt(0);
|
||||
int ch = Character.isHighSurrogate(ch0)?
|
||||
Character.toCodePoint(ch0, groupChars.charAt(1)):ch0;
|
||||
*/
|
||||
Vector<EntryPair> entryTable = getContractValues(ch);
|
||||
if (entryTable != null) {
|
||||
int index = RBCollationTables.getEntry(entryTable, groupChars, true);
|
||||
if (index != RBCollationTables.UNMAPPED) {
|
||||
EntryPair pair = entryTable.elementAt(index);
|
||||
result = pair.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private final int getCharOrder(int ch) {
|
||||
int order = mapping.elementAt(ch);
|
||||
|
||||
if (order >= RBCollationTables.CONTRACTCHARINDEX) {
|
||||
Vector<EntryPair> groupList = getContractValuesImpl(order - RBCollationTables.CONTRACTCHARINDEX);
|
||||
EntryPair pair = groupList.firstElement();
|
||||
order = pair.value;
|
||||
}
|
||||
return order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entry of hash table of the contracting string in the collation
|
||||
* table.
|
||||
* @param ch the starting character of the contracting string
|
||||
*/
|
||||
private Vector<EntryPair> getContractValues(int ch)
|
||||
{
|
||||
int index = mapping.elementAt(ch);
|
||||
return getContractValuesImpl(index - RBCollationTables.CONTRACTCHARINDEX);
|
||||
}
|
||||
|
||||
private Vector<EntryPair> getContractValuesImpl(int index)
|
||||
{
|
||||
if (index >= 0)
|
||||
{
|
||||
return contractTable.elementAt(index);
|
||||
}
|
||||
else // not found
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the expanding string into the collation table.
|
||||
*/
|
||||
private final void addExpandOrder(String contractChars,
|
||||
String expandChars,
|
||||
int anOrder) throws ParseException
|
||||
{
|
||||
// Create an expansion table entry
|
||||
int tableIndex = addExpansion(anOrder, expandChars);
|
||||
|
||||
// And add its index into the main mapping table
|
||||
if (contractChars.length() > 1) {
|
||||
char ch = contractChars.charAt(0);
|
||||
if (Character.isHighSurrogate(ch) && contractChars.length() == 2) {
|
||||
char ch2 = contractChars.charAt(1);
|
||||
if (Character.isLowSurrogate(ch2)) {
|
||||
//only add into table when it is a legal surrogate
|
||||
addOrder(Character.toCodePoint(ch, ch2), tableIndex);
|
||||
}
|
||||
} else {
|
||||
addContractOrder(contractChars, tableIndex);
|
||||
}
|
||||
} else {
|
||||
addOrder(contractChars.charAt(0), tableIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private final void addExpandOrder(int ch, String expandChars, int anOrder)
|
||||
throws ParseException
|
||||
{
|
||||
int tableIndex = addExpansion(anOrder, expandChars);
|
||||
addOrder(ch, tableIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new entry in the expansion table that contains the orderings
|
||||
* for the given characers. If anOrder is valid, it is added to the
|
||||
* beginning of the expanded list of orders.
|
||||
*/
|
||||
private int addExpansion(int anOrder, String expandChars) {
|
||||
if (expandTable == null) {
|
||||
expandTable = new Vector<>(INITIALTABLESIZE);
|
||||
}
|
||||
|
||||
// If anOrder is valid, we want to add it at the beginning of the list
|
||||
int offset = (anOrder == RBCollationTables.UNMAPPED) ? 0 : 1;
|
||||
|
||||
int[] valueList = new int[expandChars.length() + offset];
|
||||
if (offset == 1) {
|
||||
valueList[0] = anOrder;
|
||||
}
|
||||
|
||||
int j = offset;
|
||||
for (int i = 0; i < expandChars.length(); i++) {
|
||||
char ch0 = expandChars.charAt(i);
|
||||
char ch1;
|
||||
int ch;
|
||||
if (Character.isHighSurrogate(ch0)) {
|
||||
if (++i == expandChars.length() ||
|
||||
!Character.isLowSurrogate(ch1=expandChars.charAt(i))) {
|
||||
//ether we are missing the low surrogate or the next char
|
||||
//is not a legal low surrogate, so stop loop
|
||||
break;
|
||||
}
|
||||
ch = Character.toCodePoint(ch0, ch1);
|
||||
|
||||
} else {
|
||||
ch = ch0;
|
||||
}
|
||||
|
||||
int mapValue = getCharOrder(ch);
|
||||
|
||||
if (mapValue != RBCollationTables.UNMAPPED) {
|
||||
valueList[j++] = mapValue;
|
||||
} else {
|
||||
// can't find it in the table, will be filled in by commit().
|
||||
valueList[j++] = CHARINDEX + ch;
|
||||
}
|
||||
}
|
||||
if (j < valueList.length) {
|
||||
//we had at least one supplementary character, the size of valueList
|
||||
//is bigger than it really needs...
|
||||
int[] tmpBuf = new int[j];
|
||||
while (--j >= 0) {
|
||||
tmpBuf[j] = valueList[j];
|
||||
}
|
||||
valueList = tmpBuf;
|
||||
}
|
||||
// Add the expanding char list into the expansion table.
|
||||
int tableIndex = RBCollationTables.EXPANDCHARINDEX + expandTable.size();
|
||||
expandTable.addElement(valueList);
|
||||
|
||||
return tableIndex;
|
||||
}
|
||||
|
||||
private void addContractFlags(String chars) {
|
||||
char c0;
|
||||
int c;
|
||||
int len = chars.length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
c0 = chars.charAt(i);
|
||||
c = Character.isHighSurrogate(c0)
|
||||
?Character.toCodePoint(c0, chars.charAt(++i))
|
||||
:c0;
|
||||
contractFlags.put(c, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================================
|
||||
// constants
|
||||
// ==============================================================
|
||||
final static int CHARINDEX = 0x70000000; // need look up in .commit()
|
||||
|
||||
private final static int IGNORABLEMASK = 0x0000ffff;
|
||||
private final static int PRIMARYORDERINCREMENT = 0x00010000;
|
||||
private final static int SECONDARYORDERINCREMENT = 0x00000100;
|
||||
private final static int TERTIARYORDERINCREMENT = 0x00000001;
|
||||
private final static int INITIALTABLESIZE = 20;
|
||||
private final static int MAXKEYSIZE = 5;
|
||||
|
||||
// ==============================================================
|
||||
// instance variables
|
||||
// ==============================================================
|
||||
|
||||
// variables used by the build process
|
||||
private RBCollationTables.BuildAPI tables = null;
|
||||
private MergeCollation mPattern = null;
|
||||
private boolean isOverIgnore = false;
|
||||
private char[] keyBuf = new char[MAXKEYSIZE];
|
||||
private IntHashtable contractFlags = new IntHashtable(100);
|
||||
|
||||
// "shadow" copies of the instance variables in RBCollationTables
|
||||
// (the values in these variables are copied back into RBCollationTables
|
||||
// at the end of the build process)
|
||||
private boolean frenchSec = false;
|
||||
private boolean seAsianSwapping = false;
|
||||
|
||||
private UCompactIntArray mapping = null;
|
||||
private Vector<Vector<EntryPair>> contractTable = null;
|
||||
private Vector<int[]> expandTable = null;
|
||||
|
||||
private short maxSecOrder = 0;
|
||||
private short maxTerOrder = 0;
|
||||
}
|
||||
123
jdkSrc/jdk8/java/text/RuleBasedCollationKey.java
Normal file
123
jdkSrc/jdk8/java/text/RuleBasedCollationKey.java
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is copyrighted
|
||||
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
|
||||
* materials are provided under terms of a License Agreement between Taligent
|
||||
* and Sun. This technology is protected by multiple US and International
|
||||
* patents. This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
/**
|
||||
* A RuleBasedCollationKey is a concrete implementation of CollationKey class.
|
||||
* The RuleBasedCollationKey class is used by the RuleBasedCollator class.
|
||||
*/
|
||||
|
||||
final class RuleBasedCollationKey extends CollationKey {
|
||||
/**
|
||||
* Compare this RuleBasedCollationKey to target. The collation rules of the
|
||||
* Collator object which created these keys are applied. <strong>Note:</strong>
|
||||
* RuleBasedCollationKeys created by different Collators can not be compared.
|
||||
* @param target target RuleBasedCollationKey
|
||||
* @return Returns an integer value. Value is less than zero if this is less
|
||||
* than target, value is zero if this and target are equal and value is greater than
|
||||
* zero if this is greater than target.
|
||||
* @see java.text.Collator#compare
|
||||
*/
|
||||
public int compareTo(CollationKey target)
|
||||
{
|
||||
int result = key.compareTo(((RuleBasedCollationKey)(target)).key);
|
||||
if (result <= Collator.LESS)
|
||||
return Collator.LESS;
|
||||
else if (result >= Collator.GREATER)
|
||||
return Collator.GREATER;
|
||||
return Collator.EQUAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare this RuleBasedCollationKey and the target for equality.
|
||||
* The collation rules of the Collator object which created these keys are applied.
|
||||
* <strong>Note:</strong> RuleBasedCollationKeys created by different Collators can not be
|
||||
* compared.
|
||||
* @param target the RuleBasedCollationKey to compare to.
|
||||
* @return Returns true if two objects are equal, false otherwise.
|
||||
*/
|
||||
public boolean equals(Object target) {
|
||||
if (this == target) return true;
|
||||
if (target == null || !getClass().equals(target.getClass())) {
|
||||
return false;
|
||||
}
|
||||
RuleBasedCollationKey other = (RuleBasedCollationKey)target;
|
||||
return key.equals(other.key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a hash code for this RuleBasedCollationKey. The hash value is calculated on the
|
||||
* key itself, not the String from which the key was created. Thus
|
||||
* if x and y are RuleBasedCollationKeys, then x.hashCode(x) == y.hashCode() if
|
||||
* x.equals(y) is true. This allows language-sensitive comparison in a hash table.
|
||||
* See the CollatinKey class description for an example.
|
||||
* @return the hash value based on the string's collation order.
|
||||
*/
|
||||
public int hashCode() {
|
||||
return (key.hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the RuleBasedCollationKey to a sequence of bits. If two RuleBasedCollationKeys
|
||||
* could be legitimately compared, then one could compare the byte arrays
|
||||
* for each of those keys to obtain the same result. Byte arrays are
|
||||
* organized most significant byte first.
|
||||
*/
|
||||
public byte[] toByteArray() {
|
||||
|
||||
char[] src = key.toCharArray();
|
||||
byte[] dest = new byte[ 2*src.length ];
|
||||
int j = 0;
|
||||
for( int i=0; i<src.length; i++ ) {
|
||||
dest[j++] = (byte)(src[i] >>> 8);
|
||||
dest[j++] = (byte)(src[i] & 0x00ff);
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* A RuleBasedCollationKey can only be generated by Collator objects.
|
||||
*/
|
||||
RuleBasedCollationKey(String source, String key) {
|
||||
super(source);
|
||||
this.key = key;
|
||||
}
|
||||
private String key = null;
|
||||
|
||||
}
|
||||
769
jdkSrc/jdk8/java/text/RuleBasedCollator.java
Normal file
769
jdkSrc/jdk8/java/text/RuleBasedCollator.java
Normal file
@@ -0,0 +1,769 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is copyrighted
|
||||
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
|
||||
* materials are provided under terms of a License Agreement between Taligent
|
||||
* and Sun. This technology is protected by multiple US and International
|
||||
* patents. This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.text.Normalizer;
|
||||
import java.util.Vector;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* The <code>RuleBasedCollator</code> class is a concrete subclass of
|
||||
* <code>Collator</code> that provides a simple, data-driven, table
|
||||
* collator. With this class you can create a customized table-based
|
||||
* <code>Collator</code>. <code>RuleBasedCollator</code> maps
|
||||
* characters to sort keys.
|
||||
*
|
||||
* <p>
|
||||
* <code>RuleBasedCollator</code> has the following restrictions
|
||||
* for efficiency (other subclasses may be used for more complex languages) :
|
||||
* <ol>
|
||||
* <li>If a special collation rule controlled by a <modifier> is
|
||||
specified it applies to the whole collator object.
|
||||
* <li>All non-mentioned characters are at the end of the
|
||||
* collation order.
|
||||
* </ol>
|
||||
*
|
||||
* <p>
|
||||
* The collation table is composed of a list of collation rules, where each
|
||||
* rule is of one of three forms:
|
||||
* <pre>
|
||||
* <modifier>
|
||||
* <relation> <text-argument>
|
||||
* <reset> <text-argument>
|
||||
* </pre>
|
||||
* The definitions of the rule elements is as follows:
|
||||
* <UL>
|
||||
* <LI><strong>Text-Argument</strong>: A text-argument is any sequence of
|
||||
* characters, excluding special characters (that is, common
|
||||
* whitespace characters [0009-000D, 0020] and rule syntax characters
|
||||
* [0021-002F, 003A-0040, 005B-0060, 007B-007E]). If those
|
||||
* characters are desired, you can put them in single quotes
|
||||
* (e.g. ampersand => '&'). Note that unquoted white space characters
|
||||
* are ignored; e.g. <code>b c</code> is treated as <code>bc</code>.
|
||||
* <LI><strong>Modifier</strong>: There are currently two modifiers that
|
||||
* turn on special collation rules.
|
||||
* <UL>
|
||||
* <LI>'@' : Turns on backwards sorting of accents (secondary
|
||||
* differences), as in French.
|
||||
* <LI>'!' : Turns on Thai/Lao vowel-consonant swapping. If this
|
||||
* rule is in force when a Thai vowel of the range
|
||||
* \U0E40-\U0E44 precedes a Thai consonant of the range
|
||||
* \U0E01-\U0E2E OR a Lao vowel of the range \U0EC0-\U0EC4
|
||||
* precedes a Lao consonant of the range \U0E81-\U0EAE then
|
||||
* the vowel is placed after the consonant for collation
|
||||
* purposes.
|
||||
* </UL>
|
||||
* <p>'@' : Indicates that accents are sorted backwards, as in French.
|
||||
* <LI><strong>Relation</strong>: The relations are the following:
|
||||
* <UL>
|
||||
* <LI>'<' : Greater, as a letter difference (primary)
|
||||
* <LI>';' : Greater, as an accent difference (secondary)
|
||||
* <LI>',' : Greater, as a case difference (tertiary)
|
||||
* <LI>'=' : Equal
|
||||
* </UL>
|
||||
* <LI><strong>Reset</strong>: There is a single reset
|
||||
* which is used primarily for contractions and expansions, but which
|
||||
* can also be used to add a modification at the end of a set of rules.
|
||||
* <p>'&' : Indicates that the next rule follows the position to where
|
||||
* the reset text-argument would be sorted.
|
||||
* </UL>
|
||||
*
|
||||
* <p>
|
||||
* This sounds more complicated than it is in practice. For example, the
|
||||
* following are equivalent ways of expressing the same thing:
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* a < b < c
|
||||
* a < b & b < c
|
||||
* a < c & a < b
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
* Notice that the order is important, as the subsequent item goes immediately
|
||||
* after the text-argument. The following are not equivalent:
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* a < b & a < c
|
||||
* a < c & a < b
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
* Either the text-argument must already be present in the sequence, or some
|
||||
* initial substring of the text-argument must be present. (e.g. "a < b & ae <
|
||||
* e" is valid since "a" is present in the sequence before "ae" is reset). In
|
||||
* this latter case, "ae" is not entered and treated as a single character;
|
||||
* instead, "e" is sorted as if it were expanded to two characters: "a"
|
||||
* followed by an "e". This difference appears in natural languages: in
|
||||
* traditional Spanish "ch" is treated as though it contracts to a single
|
||||
* character (expressed as "c < ch < d"), while in traditional German
|
||||
* a-umlaut is treated as though it expanded to two characters
|
||||
* (expressed as "a,A < b,B ... &ae;\u00e3&AE;\u00c3").
|
||||
* [\u00e3 and \u00c3 are, of course, the escape sequences for a-umlaut.]
|
||||
* <p>
|
||||
* <strong>Ignorable Characters</strong>
|
||||
* <p>
|
||||
* For ignorable characters, the first rule must start with a relation (the
|
||||
* examples we have used above are really fragments; "a < b" really should be
|
||||
* "< a < b"). If, however, the first relation is not "<", then all the all
|
||||
* text-arguments up to the first "<" are ignorable. For example, ", - < a < b"
|
||||
* makes "-" an ignorable character, as we saw earlier in the word
|
||||
* "black-birds". In the samples for different languages, you see that most
|
||||
* accents are ignorable.
|
||||
*
|
||||
* <p><strong>Normalization and Accents</strong>
|
||||
* <p>
|
||||
* <code>RuleBasedCollator</code> automatically processes its rule table to
|
||||
* include both pre-composed and combining-character versions of
|
||||
* accented characters. Even if the provided rule string contains only
|
||||
* base characters and separate combining accent characters, the pre-composed
|
||||
* accented characters matching all canonical combinations of characters from
|
||||
* the rule string will be entered in the table.
|
||||
* <p>
|
||||
* This allows you to use a RuleBasedCollator to compare accented strings
|
||||
* even when the collator is set to NO_DECOMPOSITION. There are two caveats,
|
||||
* however. First, if the strings to be collated contain combining
|
||||
* sequences that may not be in canonical order, you should set the collator to
|
||||
* CANONICAL_DECOMPOSITION or FULL_DECOMPOSITION to enable sorting of
|
||||
* combining sequences. Second, if the strings contain characters with
|
||||
* compatibility decompositions (such as full-width and half-width forms),
|
||||
* you must use FULL_DECOMPOSITION, since the rule tables only include
|
||||
* canonical mappings.
|
||||
*
|
||||
* <p><strong>Errors</strong>
|
||||
* <p>
|
||||
* The following are errors:
|
||||
* <UL>
|
||||
* <LI>A text-argument contains unquoted punctuation symbols
|
||||
* (e.g. "a < b-c < d").
|
||||
* <LI>A relation or reset character not followed by a text-argument
|
||||
* (e.g. "a < ,b").
|
||||
* <LI>A reset where the text-argument (or an initial substring of the
|
||||
* text-argument) is not already in the sequence.
|
||||
* (e.g. "a < b & e < f")
|
||||
* </UL>
|
||||
* If you produce one of these errors, a <code>RuleBasedCollator</code> throws
|
||||
* a <code>ParseException</code>.
|
||||
*
|
||||
* <p><strong>Examples</strong>
|
||||
* <p>Simple: "< a < b < c < d"
|
||||
* <p>Norwegian: "< a, A < b, B < c, C < d, D < e, E < f, F
|
||||
* < g, G < h, H < i, I < j, J < k, K < l, L
|
||||
* < m, M < n, N < o, O < p, P < q, Q < r, R
|
||||
* < s, S < t, T < u, U < v, V < w, W < x, X
|
||||
* < y, Y < z, Z
|
||||
* < \u00E6, \u00C6
|
||||
* < \u00F8, \u00D8
|
||||
* < \u00E5 = a\u030A, \u00C5 = A\u030A;
|
||||
* aa, AA"
|
||||
*
|
||||
* <p>
|
||||
* To create a <code>RuleBasedCollator</code> object with specialized
|
||||
* rules tailored to your needs, you construct the <code>RuleBasedCollator</code>
|
||||
* with the rules contained in a <code>String</code> object. For example:
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* String simple = "< a< b< c< d";
|
||||
* RuleBasedCollator mySimple = new RuleBasedCollator(simple);
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
* Or:
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* String Norwegian = "< a, A < b, B < c, C < d, D < e, E < f, F < g, G < h, H < i, I" +
|
||||
* "< j, J < k, K < l, L < m, M < n, N < o, O < p, P < q, Q < r, R" +
|
||||
* "< s, S < t, T < u, U < v, V < w, W < x, X < y, Y < z, Z" +
|
||||
* "< \u00E6, \u00C6" + // Latin letter ae & AE
|
||||
* "< \u00F8, \u00D8" + // Latin letter o & O with stroke
|
||||
* "< \u00E5 = a\u030A," + // Latin letter a with ring above
|
||||
* " \u00C5 = A\u030A;" + // Latin letter A with ring above
|
||||
* " aa, AA";
|
||||
* RuleBasedCollator myNorwegian = new RuleBasedCollator(Norwegian);
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* <p>
|
||||
* A new collation rules string can be created by concatenating rules
|
||||
* strings. For example, the rules returned by {@link #getRules()} could
|
||||
* be concatenated to combine multiple <code>RuleBasedCollator</code>s.
|
||||
*
|
||||
* <p>
|
||||
* The following example demonstrates how to change the order of
|
||||
* non-spacing accents,
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* // old rule
|
||||
* String oldRules = "=\u0301;\u0300;\u0302;\u0308" // main accents
|
||||
* + ";\u0327;\u0303;\u0304;\u0305" // main accents
|
||||
* + ";\u0306;\u0307;\u0309;\u030A" // main accents
|
||||
* + ";\u030B;\u030C;\u030D;\u030E" // main accents
|
||||
* + ";\u030F;\u0310;\u0311;\u0312" // main accents
|
||||
* + "< a , A ; ae, AE ; \u00e6 , \u00c6"
|
||||
* + "< b , B < c, C < e, E & C < d, D";
|
||||
* // change the order of accent characters
|
||||
* String addOn = "& \u0300 ; \u0308 ; \u0302";
|
||||
* RuleBasedCollator myCollator = new RuleBasedCollator(oldRules + addOn);
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* @see Collator
|
||||
* @see CollationElementIterator
|
||||
* @author Helena Shih, Laura Werner, Richard Gillam
|
||||
*/
|
||||
public class RuleBasedCollator extends Collator{
|
||||
// IMPLEMENTATION NOTES: The implementation of the collation algorithm is
|
||||
// divided across three classes: RuleBasedCollator, RBCollationTables, and
|
||||
// CollationElementIterator. RuleBasedCollator contains the collator's
|
||||
// transient state and includes the code that uses the other classes to
|
||||
// implement comparison and sort-key building. RuleBasedCollator also
|
||||
// contains the logic to handle French secondary accent sorting.
|
||||
// A RuleBasedCollator has two CollationElementIterators. State doesn't
|
||||
// need to be preserved in these objects between calls to compare() or
|
||||
// getCollationKey(), but the objects persist anyway to avoid wasting extra
|
||||
// creation time. compare() and getCollationKey() are synchronized to ensure
|
||||
// thread safety with this scheme. The CollationElementIterator is responsible
|
||||
// for generating collation elements from strings and returning one element at
|
||||
// a time (sometimes there's a one-to-many or many-to-one mapping between
|
||||
// characters and collation elements-- this class handles that).
|
||||
// CollationElementIterator depends on RBCollationTables, which contains the
|
||||
// collator's static state. RBCollationTables contains the actual data
|
||||
// tables specifying the collation order of characters for a particular locale
|
||||
// or use. It also contains the base logic that CollationElementIterator
|
||||
// uses to map from characters to collation elements. A single RBCollationTables
|
||||
// object is shared among all RuleBasedCollators for the same locale, and
|
||||
// thus by all the CollationElementIterators they create.
|
||||
|
||||
/**
|
||||
* RuleBasedCollator constructor. This takes the table rules and builds
|
||||
* a collation table out of them. Please see RuleBasedCollator class
|
||||
* description for more details on the collation rule syntax.
|
||||
* @see java.util.Locale
|
||||
* @param rules the collation rules to build the collation table from.
|
||||
* @exception ParseException A format exception
|
||||
* will be thrown if the build process of the rules fails. For
|
||||
* example, build rule "a < ? < d" will cause the constructor to
|
||||
* throw the ParseException because the '?' is not quoted.
|
||||
*/
|
||||
public RuleBasedCollator(String rules) throws ParseException {
|
||||
this(rules, Collator.CANONICAL_DECOMPOSITION);
|
||||
}
|
||||
|
||||
/**
|
||||
* RuleBasedCollator constructor. This takes the table rules and builds
|
||||
* a collation table out of them. Please see RuleBasedCollator class
|
||||
* description for more details on the collation rule syntax.
|
||||
* @see java.util.Locale
|
||||
* @param rules the collation rules to build the collation table from.
|
||||
* @param decomp the decomposition strength used to build the
|
||||
* collation table and to perform comparisons.
|
||||
* @exception ParseException A format exception
|
||||
* will be thrown if the build process of the rules fails. For
|
||||
* example, build rule "a < ? < d" will cause the constructor to
|
||||
* throw the ParseException because the '?' is not quoted.
|
||||
*/
|
||||
RuleBasedCollator(String rules, int decomp) throws ParseException {
|
||||
setStrength(Collator.TERTIARY);
|
||||
setDecomposition(decomp);
|
||||
tables = new RBCollationTables(rules, decomp);
|
||||
}
|
||||
|
||||
/**
|
||||
* "Copy constructor." Used in clone() for performance.
|
||||
*/
|
||||
private RuleBasedCollator(RuleBasedCollator that) {
|
||||
setStrength(that.getStrength());
|
||||
setDecomposition(that.getDecomposition());
|
||||
tables = that.tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the table-based rules for the collation object.
|
||||
* @return returns the collation rules that the table collation object
|
||||
* was created from.
|
||||
*/
|
||||
public String getRules()
|
||||
{
|
||||
return tables.getRules();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a CollationElementIterator for the given String.
|
||||
*
|
||||
* @param source the string to be collated
|
||||
* @return a {@code CollationElementIterator} object
|
||||
* @see java.text.CollationElementIterator
|
||||
*/
|
||||
public CollationElementIterator getCollationElementIterator(String source) {
|
||||
return new CollationElementIterator( source, this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a CollationElementIterator for the given CharacterIterator.
|
||||
*
|
||||
* @param source the character iterator to be collated
|
||||
* @return a {@code CollationElementIterator} object
|
||||
* @see java.text.CollationElementIterator
|
||||
* @since 1.2
|
||||
*/
|
||||
public CollationElementIterator getCollationElementIterator(
|
||||
CharacterIterator source) {
|
||||
return new CollationElementIterator( source, this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the character data stored in two different strings based on the
|
||||
* collation rules. Returns information about whether a string is less
|
||||
* than, greater than or equal to another string in a language.
|
||||
* This can be overriden in a subclass.
|
||||
*
|
||||
* @exception NullPointerException if <code>source</code> or <code>target</code> is null.
|
||||
*/
|
||||
public synchronized int compare(String source, String target)
|
||||
{
|
||||
if (source == null || target == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
// The basic algorithm here is that we use CollationElementIterators
|
||||
// to step through both the source and target strings. We compare each
|
||||
// collation element in the source string against the corresponding one
|
||||
// in the target, checking for differences.
|
||||
//
|
||||
// If a difference is found, we set <result> to LESS or GREATER to
|
||||
// indicate whether the source string is less or greater than the target.
|
||||
//
|
||||
// However, it's not that simple. If we find a tertiary difference
|
||||
// (e.g. 'A' vs. 'a') near the beginning of a string, it can be
|
||||
// overridden by a primary difference (e.g. "A" vs. "B") later in
|
||||
// the string. For example, "AA" < "aB", even though 'A' > 'a'.
|
||||
//
|
||||
// To keep track of this, we use strengthResult to keep track of the
|
||||
// strength of the most significant difference that has been found
|
||||
// so far. When we find a difference whose strength is greater than
|
||||
// strengthResult, it overrides the last difference (if any) that
|
||||
// was found.
|
||||
|
||||
int result = Collator.EQUAL;
|
||||
|
||||
if (sourceCursor == null) {
|
||||
sourceCursor = getCollationElementIterator(source);
|
||||
} else {
|
||||
sourceCursor.setText(source);
|
||||
}
|
||||
if (targetCursor == null) {
|
||||
targetCursor = getCollationElementIterator(target);
|
||||
} else {
|
||||
targetCursor.setText(target);
|
||||
}
|
||||
|
||||
int sOrder = 0, tOrder = 0;
|
||||
|
||||
boolean initialCheckSecTer = getStrength() >= Collator.SECONDARY;
|
||||
boolean checkSecTer = initialCheckSecTer;
|
||||
boolean checkTertiary = getStrength() >= Collator.TERTIARY;
|
||||
|
||||
boolean gets = true, gett = true;
|
||||
|
||||
while(true) {
|
||||
// Get the next collation element in each of the strings, unless
|
||||
// we've been requested to skip it.
|
||||
if (gets) sOrder = sourceCursor.next(); else gets = true;
|
||||
if (gett) tOrder = targetCursor.next(); else gett = true;
|
||||
|
||||
// If we've hit the end of one of the strings, jump out of the loop
|
||||
if ((sOrder == CollationElementIterator.NULLORDER)||
|
||||
(tOrder == CollationElementIterator.NULLORDER))
|
||||
break;
|
||||
|
||||
int pSOrder = CollationElementIterator.primaryOrder(sOrder);
|
||||
int pTOrder = CollationElementIterator.primaryOrder(tOrder);
|
||||
|
||||
// If there's no difference at this position, we can skip it
|
||||
if (sOrder == tOrder) {
|
||||
if (tables.isFrenchSec() && pSOrder != 0) {
|
||||
if (!checkSecTer) {
|
||||
// in french, a secondary difference more to the right is stronger,
|
||||
// so accents have to be checked with each base element
|
||||
checkSecTer = initialCheckSecTer;
|
||||
// but tertiary differences are less important than the first
|
||||
// secondary difference, so checking tertiary remains disabled
|
||||
checkTertiary = false;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Compare primary differences first.
|
||||
if ( pSOrder != pTOrder )
|
||||
{
|
||||
if (sOrder == 0) {
|
||||
// The entire source element is ignorable.
|
||||
// Skip to the next source element, but don't fetch another target element.
|
||||
gett = false;
|
||||
continue;
|
||||
}
|
||||
if (tOrder == 0) {
|
||||
gets = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// The source and target elements aren't ignorable, but it's still possible
|
||||
// for the primary component of one of the elements to be ignorable....
|
||||
|
||||
if (pSOrder == 0) // primary order in source is ignorable
|
||||
{
|
||||
// The source's primary is ignorable, but the target's isn't. We treat ignorables
|
||||
// as a secondary difference, so remember that we found one.
|
||||
if (checkSecTer) {
|
||||
result = Collator.GREATER; // (strength is SECONDARY)
|
||||
checkSecTer = false;
|
||||
}
|
||||
// Skip to the next source element, but don't fetch another target element.
|
||||
gett = false;
|
||||
}
|
||||
else if (pTOrder == 0)
|
||||
{
|
||||
// record differences - see the comment above.
|
||||
if (checkSecTer) {
|
||||
result = Collator.LESS; // (strength is SECONDARY)
|
||||
checkSecTer = false;
|
||||
}
|
||||
// Skip to the next source element, but don't fetch another target element.
|
||||
gets = false;
|
||||
} else {
|
||||
// Neither of the orders is ignorable, and we already know that the primary
|
||||
// orders are different because of the (pSOrder != pTOrder) test above.
|
||||
// Record the difference and stop the comparison.
|
||||
if (pSOrder < pTOrder) {
|
||||
return Collator.LESS; // (strength is PRIMARY)
|
||||
} else {
|
||||
return Collator.GREATER; // (strength is PRIMARY)
|
||||
}
|
||||
}
|
||||
} else { // else of if ( pSOrder != pTOrder )
|
||||
// primary order is the same, but complete order is different. So there
|
||||
// are no base elements at this point, only ignorables (Since the strings are
|
||||
// normalized)
|
||||
|
||||
if (checkSecTer) {
|
||||
// a secondary or tertiary difference may still matter
|
||||
short secSOrder = CollationElementIterator.secondaryOrder(sOrder);
|
||||
short secTOrder = CollationElementIterator.secondaryOrder(tOrder);
|
||||
if (secSOrder != secTOrder) {
|
||||
// there is a secondary difference
|
||||
result = (secSOrder < secTOrder) ? Collator.LESS : Collator.GREATER;
|
||||
// (strength is SECONDARY)
|
||||
checkSecTer = false;
|
||||
// (even in french, only the first secondary difference within
|
||||
// a base character matters)
|
||||
} else {
|
||||
if (checkTertiary) {
|
||||
// a tertiary difference may still matter
|
||||
short terSOrder = CollationElementIterator.tertiaryOrder(sOrder);
|
||||
short terTOrder = CollationElementIterator.tertiaryOrder(tOrder);
|
||||
if (terSOrder != terTOrder) {
|
||||
// there is a tertiary difference
|
||||
result = (terSOrder < terTOrder) ? Collator.LESS : Collator.GREATER;
|
||||
// (strength is TERTIARY)
|
||||
checkTertiary = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // if (checkSecTer)
|
||||
|
||||
} // if ( pSOrder != pTOrder )
|
||||
} // while()
|
||||
|
||||
if (sOrder != CollationElementIterator.NULLORDER) {
|
||||
// (tOrder must be CollationElementIterator::NULLORDER,
|
||||
// since this point is only reached when sOrder or tOrder is NULLORDER.)
|
||||
// The source string has more elements, but the target string hasn't.
|
||||
do {
|
||||
if (CollationElementIterator.primaryOrder(sOrder) != 0) {
|
||||
// We found an additional non-ignorable base character in the source string.
|
||||
// This is a primary difference, so the source is greater
|
||||
return Collator.GREATER; // (strength is PRIMARY)
|
||||
}
|
||||
else if (CollationElementIterator.secondaryOrder(sOrder) != 0) {
|
||||
// Additional secondary elements mean the source string is greater
|
||||
if (checkSecTer) {
|
||||
result = Collator.GREATER; // (strength is SECONDARY)
|
||||
checkSecTer = false;
|
||||
}
|
||||
}
|
||||
} while ((sOrder = sourceCursor.next()) != CollationElementIterator.NULLORDER);
|
||||
}
|
||||
else if (tOrder != CollationElementIterator.NULLORDER) {
|
||||
// The target string has more elements, but the source string hasn't.
|
||||
do {
|
||||
if (CollationElementIterator.primaryOrder(tOrder) != 0)
|
||||
// We found an additional non-ignorable base character in the target string.
|
||||
// This is a primary difference, so the source is less
|
||||
return Collator.LESS; // (strength is PRIMARY)
|
||||
else if (CollationElementIterator.secondaryOrder(tOrder) != 0) {
|
||||
// Additional secondary elements in the target mean the source string is less
|
||||
if (checkSecTer) {
|
||||
result = Collator.LESS; // (strength is SECONDARY)
|
||||
checkSecTer = false;
|
||||
}
|
||||
}
|
||||
} while ((tOrder = targetCursor.next()) != CollationElementIterator.NULLORDER);
|
||||
}
|
||||
|
||||
// For IDENTICAL comparisons, we use a bitwise character comparison
|
||||
// as a tiebreaker if all else is equal
|
||||
if (result == 0 && getStrength() == IDENTICAL) {
|
||||
int mode = getDecomposition();
|
||||
Normalizer.Form form;
|
||||
if (mode == CANONICAL_DECOMPOSITION) {
|
||||
form = Normalizer.Form.NFD;
|
||||
} else if (mode == FULL_DECOMPOSITION) {
|
||||
form = Normalizer.Form.NFKD;
|
||||
} else {
|
||||
return source.compareTo(target);
|
||||
}
|
||||
|
||||
String sourceDecomposition = Normalizer.normalize(source, form);
|
||||
String targetDecomposition = Normalizer.normalize(target, form);
|
||||
return sourceDecomposition.compareTo(targetDecomposition);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the string into a series of characters that can be compared
|
||||
* with CollationKey.compareTo. This overrides java.text.Collator.getCollationKey.
|
||||
* It can be overriden in a subclass.
|
||||
*/
|
||||
public synchronized CollationKey getCollationKey(String source)
|
||||
{
|
||||
//
|
||||
// The basic algorithm here is to find all of the collation elements for each
|
||||
// character in the source string, convert them to a char representation,
|
||||
// and put them into the collation key. But it's trickier than that.
|
||||
// Each collation element in a string has three components: primary (A vs B),
|
||||
// secondary (A vs A-acute), and tertiary (A' vs a); and a primary difference
|
||||
// at the end of a string takes precedence over a secondary or tertiary
|
||||
// difference earlier in the string.
|
||||
//
|
||||
// To account for this, we put all of the primary orders at the beginning of the
|
||||
// string, followed by the secondary and tertiary orders, separated by nulls.
|
||||
//
|
||||
// Here's a hypothetical example, with the collation element represented as
|
||||
// a three-digit number, one digit for primary, one for secondary, etc.
|
||||
//
|
||||
// String: A a B \u00e9 <--(e-acute)
|
||||
// Collation Elements: 101 100 201 510
|
||||
//
|
||||
// Collation Key: 1125<null>0001<null>1010
|
||||
//
|
||||
// To make things even trickier, secondary differences (accent marks) are compared
|
||||
// starting at the *end* of the string in languages with French secondary ordering.
|
||||
// But when comparing the accent marks on a single base character, they are compared
|
||||
// from the beginning. To handle this, we reverse all of the accents that belong
|
||||
// to each base character, then we reverse the entire string of secondary orderings
|
||||
// at the end. Taking the same example above, a French collator might return
|
||||
// this instead:
|
||||
//
|
||||
// Collation Key: 1125<null>1000<null>1010
|
||||
//
|
||||
if (source == null)
|
||||
return null;
|
||||
|
||||
if (primResult == null) {
|
||||
primResult = new StringBuffer();
|
||||
secResult = new StringBuffer();
|
||||
terResult = new StringBuffer();
|
||||
} else {
|
||||
primResult.setLength(0);
|
||||
secResult.setLength(0);
|
||||
terResult.setLength(0);
|
||||
}
|
||||
int order = 0;
|
||||
boolean compareSec = (getStrength() >= Collator.SECONDARY);
|
||||
boolean compareTer = (getStrength() >= Collator.TERTIARY);
|
||||
int secOrder = CollationElementIterator.NULLORDER;
|
||||
int terOrder = CollationElementIterator.NULLORDER;
|
||||
int preSecIgnore = 0;
|
||||
|
||||
if (sourceCursor == null) {
|
||||
sourceCursor = getCollationElementIterator(source);
|
||||
} else {
|
||||
sourceCursor.setText(source);
|
||||
}
|
||||
|
||||
// walk through each character
|
||||
while ((order = sourceCursor.next()) !=
|
||||
CollationElementIterator.NULLORDER)
|
||||
{
|
||||
secOrder = CollationElementIterator.secondaryOrder(order);
|
||||
terOrder = CollationElementIterator.tertiaryOrder(order);
|
||||
if (!CollationElementIterator.isIgnorable(order))
|
||||
{
|
||||
primResult.append((char) (CollationElementIterator.primaryOrder(order)
|
||||
+ COLLATIONKEYOFFSET));
|
||||
|
||||
if (compareSec) {
|
||||
//
|
||||
// accumulate all of the ignorable/secondary characters attached
|
||||
// to a given base character
|
||||
//
|
||||
if (tables.isFrenchSec() && preSecIgnore < secResult.length()) {
|
||||
//
|
||||
// We're doing reversed secondary ordering and we've hit a base
|
||||
// (non-ignorable) character. Reverse any secondary orderings
|
||||
// that applied to the last base character. (see block comment above.)
|
||||
//
|
||||
RBCollationTables.reverse(secResult, preSecIgnore, secResult.length());
|
||||
}
|
||||
// Remember where we are in the secondary orderings - this is how far
|
||||
// back to go if we need to reverse them later.
|
||||
secResult.append((char)(secOrder+ COLLATIONKEYOFFSET));
|
||||
preSecIgnore = secResult.length();
|
||||
}
|
||||
if (compareTer) {
|
||||
terResult.append((char)(terOrder+ COLLATIONKEYOFFSET));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (compareSec && secOrder != 0)
|
||||
secResult.append((char)
|
||||
(secOrder + tables.getMaxSecOrder() + COLLATIONKEYOFFSET));
|
||||
if (compareTer && terOrder != 0)
|
||||
terResult.append((char)
|
||||
(terOrder + tables.getMaxTerOrder() + COLLATIONKEYOFFSET));
|
||||
}
|
||||
}
|
||||
if (tables.isFrenchSec())
|
||||
{
|
||||
if (preSecIgnore < secResult.length()) {
|
||||
// If we've accumulated any secondary characters after the last base character,
|
||||
// reverse them.
|
||||
RBCollationTables.reverse(secResult, preSecIgnore, secResult.length());
|
||||
}
|
||||
// And now reverse the entire secResult to get French secondary ordering.
|
||||
RBCollationTables.reverse(secResult, 0, secResult.length());
|
||||
}
|
||||
primResult.append((char)0);
|
||||
secResult.append((char)0);
|
||||
secResult.append(terResult.toString());
|
||||
primResult.append(secResult.toString());
|
||||
|
||||
if (getStrength() == IDENTICAL) {
|
||||
primResult.append((char)0);
|
||||
int mode = getDecomposition();
|
||||
if (mode == CANONICAL_DECOMPOSITION) {
|
||||
primResult.append(Normalizer.normalize(source, Normalizer.Form.NFD));
|
||||
} else if (mode == FULL_DECOMPOSITION) {
|
||||
primResult.append(Normalizer.normalize(source, Normalizer.Form.NFKD));
|
||||
} else {
|
||||
primResult.append(source);
|
||||
}
|
||||
}
|
||||
return new RuleBasedCollationKey(source, primResult.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard override; no change in semantics.
|
||||
*/
|
||||
public Object clone() {
|
||||
// if we know we're not actually a subclass of RuleBasedCollator
|
||||
// (this class really should have been made final), bypass
|
||||
// Object.clone() and use our "copy constructor". This is faster.
|
||||
if (getClass() == RuleBasedCollator.class) {
|
||||
return new RuleBasedCollator(this);
|
||||
}
|
||||
else {
|
||||
RuleBasedCollator result = (RuleBasedCollator) super.clone();
|
||||
result.primResult = null;
|
||||
result.secResult = null;
|
||||
result.terResult = null;
|
||||
result.sourceCursor = null;
|
||||
result.targetCursor = null;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the equality of two collation objects.
|
||||
* @param obj the table-based collation object to be compared with this.
|
||||
* @return true if the current table-based collation object is the same
|
||||
* as the table-based collation object obj; false otherwise.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) return false;
|
||||
if (!super.equals(obj)) return false; // super does class check
|
||||
RuleBasedCollator other = (RuleBasedCollator) obj;
|
||||
// all other non-transient information is also contained in rules.
|
||||
return (getRules().equals(other.getRules()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the hash code for the table-based collation object
|
||||
*/
|
||||
public int hashCode() {
|
||||
return getRules().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows CollationElementIterator access to the tables object
|
||||
*/
|
||||
RBCollationTables getTables() {
|
||||
return tables;
|
||||
}
|
||||
|
||||
// ==============================================================
|
||||
// private
|
||||
// ==============================================================
|
||||
|
||||
final static int CHARINDEX = 0x70000000; // need look up in .commit()
|
||||
final static int EXPANDCHARINDEX = 0x7E000000; // Expand index follows
|
||||
final static int CONTRACTCHARINDEX = 0x7F000000; // contract indexes follow
|
||||
final static int UNMAPPED = 0xFFFFFFFF;
|
||||
|
||||
private final static int COLLATIONKEYOFFSET = 1;
|
||||
|
||||
private RBCollationTables tables = null;
|
||||
|
||||
// Internal objects that are cached across calls so that they don't have to
|
||||
// be created/destroyed on every call to compare() and getCollationKey()
|
||||
private StringBuffer primResult = null;
|
||||
private StringBuffer secResult = null;
|
||||
private StringBuffer terResult = null;
|
||||
private CollationElementIterator sourceCursor = null;
|
||||
private CollationElementIterator targetCursor = null;
|
||||
}
|
||||
2442
jdkSrc/jdk8/java/text/SimpleDateFormat.java
Normal file
2442
jdkSrc/jdk8/java/text/SimpleDateFormat.java
Normal file
File diff suppressed because it is too large
Load Diff
281
jdkSrc/jdk8/java/text/StringCharacterIterator.java
Normal file
281
jdkSrc/jdk8/java/text/StringCharacterIterator.java
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation
|
||||
* is copyrighted and owned by Taligent, Inc., a wholly-owned
|
||||
* subsidiary of IBM. These materials are provided under terms
|
||||
* of a License Agreement between Taligent and Sun. This technology
|
||||
* is protected by multiple US and International patents.
|
||||
*
|
||||
* This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
/**
|
||||
* <code>StringCharacterIterator</code> implements the
|
||||
* <code>CharacterIterator</code> protocol for a <code>String</code>.
|
||||
* The <code>StringCharacterIterator</code> class iterates over the
|
||||
* entire <code>String</code>.
|
||||
*
|
||||
* @see CharacterIterator
|
||||
*/
|
||||
|
||||
public final class StringCharacterIterator implements CharacterIterator
|
||||
{
|
||||
private String text;
|
||||
private int begin;
|
||||
private int end;
|
||||
// invariant: begin <= pos <= end
|
||||
private int pos;
|
||||
|
||||
/**
|
||||
* Constructs an iterator with an initial index of 0.
|
||||
*
|
||||
* @param text the {@code String} to be iterated over
|
||||
*/
|
||||
public StringCharacterIterator(String text)
|
||||
{
|
||||
this(text, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an iterator with the specified initial index.
|
||||
*
|
||||
* @param text The String to be iterated over
|
||||
* @param pos Initial iterator position
|
||||
*/
|
||||
public StringCharacterIterator(String text, int pos)
|
||||
{
|
||||
this(text, 0, text.length(), pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an iterator over the given range of the given string, with the
|
||||
* index set at the specified position.
|
||||
*
|
||||
* @param text The String to be iterated over
|
||||
* @param begin Index of the first character
|
||||
* @param end Index of the character following the last character
|
||||
* @param pos Initial iterator position
|
||||
*/
|
||||
public StringCharacterIterator(String text, int begin, int end, int pos) {
|
||||
if (text == null)
|
||||
throw new NullPointerException();
|
||||
this.text = text;
|
||||
|
||||
if (begin < 0 || begin > end || end > text.length())
|
||||
throw new IllegalArgumentException("Invalid substring range");
|
||||
|
||||
if (pos < begin || pos > end)
|
||||
throw new IllegalArgumentException("Invalid position");
|
||||
|
||||
this.begin = begin;
|
||||
this.end = end;
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset this iterator to point to a new string. This package-visible
|
||||
* method is used by other java.text classes that want to avoid allocating
|
||||
* new StringCharacterIterator objects every time their setText method
|
||||
* is called.
|
||||
*
|
||||
* @param text The String to be iterated over
|
||||
* @since 1.2
|
||||
*/
|
||||
public void setText(String text) {
|
||||
if (text == null)
|
||||
throw new NullPointerException();
|
||||
this.text = text;
|
||||
this.begin = 0;
|
||||
this.end = text.length();
|
||||
this.pos = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements CharacterIterator.first() for String.
|
||||
* @see CharacterIterator#first
|
||||
*/
|
||||
public char first()
|
||||
{
|
||||
pos = begin;
|
||||
return current();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements CharacterIterator.last() for String.
|
||||
* @see CharacterIterator#last
|
||||
*/
|
||||
public char last()
|
||||
{
|
||||
if (end != begin) {
|
||||
pos = end - 1;
|
||||
} else {
|
||||
pos = end;
|
||||
}
|
||||
return current();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements CharacterIterator.setIndex() for String.
|
||||
* @see CharacterIterator#setIndex
|
||||
*/
|
||||
public char setIndex(int p)
|
||||
{
|
||||
if (p < begin || p > end)
|
||||
throw new IllegalArgumentException("Invalid index");
|
||||
pos = p;
|
||||
return current();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements CharacterIterator.current() for String.
|
||||
* @see CharacterIterator#current
|
||||
*/
|
||||
public char current()
|
||||
{
|
||||
if (pos >= begin && pos < end) {
|
||||
return text.charAt(pos);
|
||||
}
|
||||
else {
|
||||
return DONE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements CharacterIterator.next() for String.
|
||||
* @see CharacterIterator#next
|
||||
*/
|
||||
public char next()
|
||||
{
|
||||
if (pos < end - 1) {
|
||||
pos++;
|
||||
return text.charAt(pos);
|
||||
}
|
||||
else {
|
||||
pos = end;
|
||||
return DONE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements CharacterIterator.previous() for String.
|
||||
* @see CharacterIterator#previous
|
||||
*/
|
||||
public char previous()
|
||||
{
|
||||
if (pos > begin) {
|
||||
pos--;
|
||||
return text.charAt(pos);
|
||||
}
|
||||
else {
|
||||
return DONE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements CharacterIterator.getBeginIndex() for String.
|
||||
* @see CharacterIterator#getBeginIndex
|
||||
*/
|
||||
public int getBeginIndex()
|
||||
{
|
||||
return begin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements CharacterIterator.getEndIndex() for String.
|
||||
* @see CharacterIterator#getEndIndex
|
||||
*/
|
||||
public int getEndIndex()
|
||||
{
|
||||
return end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements CharacterIterator.getIndex() for String.
|
||||
* @see CharacterIterator#getIndex
|
||||
*/
|
||||
public int getIndex()
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the equality of two StringCharacterIterator objects.
|
||||
* @param obj the StringCharacterIterator object to be compared with.
|
||||
* @return true if the given obj is the same as this
|
||||
* StringCharacterIterator object; false otherwise.
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!(obj instanceof StringCharacterIterator))
|
||||
return false;
|
||||
|
||||
StringCharacterIterator that = (StringCharacterIterator) obj;
|
||||
|
||||
if (hashCode() != that.hashCode())
|
||||
return false;
|
||||
if (!text.equals(that.text))
|
||||
return false;
|
||||
if (pos != that.pos || begin != that.begin || end != that.end)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a hashcode for this iterator.
|
||||
* @return A hash code
|
||||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
return text.hashCode() ^ pos ^ begin ^ end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of this iterator.
|
||||
* @return A copy of this
|
||||
*/
|
||||
public Object clone()
|
||||
{
|
||||
try {
|
||||
StringCharacterIterator other
|
||||
= (StringCharacterIterator) super.clone();
|
||||
return other;
|
||||
}
|
||||
catch (CloneNotSupportedException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
107
jdkSrc/jdk8/java/text/spi/BreakIteratorProvider.java
Normal file
107
jdkSrc/jdk8/java/text/spi/BreakIteratorProvider.java
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.text.spi;
|
||||
|
||||
import java.text.BreakIterator;
|
||||
import java.util.Locale;
|
||||
import java.util.spi.LocaleServiceProvider;
|
||||
|
||||
/**
|
||||
* An abstract class for service providers that
|
||||
* provide concrete implementations of the
|
||||
* {@link java.text.BreakIterator BreakIterator} class.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public abstract class BreakIteratorProvider extends LocaleServiceProvider {
|
||||
|
||||
/**
|
||||
* Sole constructor. (For invocation by subclass constructors, typically
|
||||
* implicit.)
|
||||
*/
|
||||
protected BreakIteratorProvider() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new <code>BreakIterator</code> instance
|
||||
* for <a href="../BreakIterator.html#word">word breaks</a>
|
||||
* for the given locale.
|
||||
* @param locale the desired locale
|
||||
* @return A break iterator for word breaks
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
* @exception IllegalArgumentException if <code>locale</code> isn't
|
||||
* one of the locales returned from
|
||||
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
|
||||
* getAvailableLocales()}.
|
||||
* @see java.text.BreakIterator#getWordInstance(java.util.Locale)
|
||||
*/
|
||||
public abstract BreakIterator getWordInstance(Locale locale);
|
||||
|
||||
/**
|
||||
* Returns a new <code>BreakIterator</code> instance
|
||||
* for <a href="../BreakIterator.html#line">line breaks</a>
|
||||
* for the given locale.
|
||||
* @param locale the desired locale
|
||||
* @return A break iterator for line breaks
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
* @exception IllegalArgumentException if <code>locale</code> isn't
|
||||
* one of the locales returned from
|
||||
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
|
||||
* getAvailableLocales()}.
|
||||
* @see java.text.BreakIterator#getLineInstance(java.util.Locale)
|
||||
*/
|
||||
public abstract BreakIterator getLineInstance(Locale locale);
|
||||
|
||||
/**
|
||||
* Returns a new <code>BreakIterator</code> instance
|
||||
* for <a href="../BreakIterator.html#character">character breaks</a>
|
||||
* for the given locale.
|
||||
* @param locale the desired locale
|
||||
* @return A break iterator for character breaks
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
* @exception IllegalArgumentException if <code>locale</code> isn't
|
||||
* one of the locales returned from
|
||||
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
|
||||
* getAvailableLocales()}.
|
||||
* @see java.text.BreakIterator#getCharacterInstance(java.util.Locale)
|
||||
*/
|
||||
public abstract BreakIterator getCharacterInstance(Locale locale);
|
||||
|
||||
/**
|
||||
* Returns a new <code>BreakIterator</code> instance
|
||||
* for <a href="../BreakIterator.html#sentence">sentence breaks</a>
|
||||
* for the given locale.
|
||||
* @param locale the desired locale
|
||||
* @return A break iterator for sentence breaks
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
* @exception IllegalArgumentException if <code>locale</code> isn't
|
||||
* one of the locales returned from
|
||||
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
|
||||
* getAvailableLocales()}.
|
||||
* @see java.text.BreakIterator#getSentenceInstance(java.util.Locale)
|
||||
*/
|
||||
public abstract BreakIterator getSentenceInstance(Locale locale);
|
||||
}
|
||||
61
jdkSrc/jdk8/java/text/spi/CollatorProvider.java
Normal file
61
jdkSrc/jdk8/java/text/spi/CollatorProvider.java
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.text.spi;
|
||||
|
||||
import java.text.Collator;
|
||||
import java.util.Locale;
|
||||
import java.util.spi.LocaleServiceProvider;
|
||||
|
||||
/**
|
||||
* An abstract class for service providers that
|
||||
* provide concrete implementations of the
|
||||
* {@link java.text.Collator Collator} class.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public abstract class CollatorProvider extends LocaleServiceProvider {
|
||||
|
||||
/**
|
||||
* Sole constructor. (For invocation by subclass constructors, typically
|
||||
* implicit.)
|
||||
*/
|
||||
protected CollatorProvider() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new <code>Collator</code> instance for the specified locale.
|
||||
* @param locale the desired locale.
|
||||
* @return the <code>Collator</code> for the desired locale.
|
||||
* @exception NullPointerException if
|
||||
* <code>locale</code> is null
|
||||
* @exception IllegalArgumentException if <code>locale</code> isn't
|
||||
* one of the locales returned from
|
||||
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
|
||||
* getAvailableLocales()}.
|
||||
* @see java.text.Collator#getInstance(java.util.Locale)
|
||||
*/
|
||||
public abstract Collator getInstance(Locale locale);
|
||||
}
|
||||
114
jdkSrc/jdk8/java/text/spi/DateFormatProvider.java
Normal file
114
jdkSrc/jdk8/java/text/spi/DateFormatProvider.java
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.text.spi;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.spi.LocaleServiceProvider;
|
||||
|
||||
/**
|
||||
* An abstract class for service providers that
|
||||
* provide concrete implementations of the
|
||||
* {@link java.text.DateFormat DateFormat} class.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public abstract class DateFormatProvider extends LocaleServiceProvider {
|
||||
|
||||
/**
|
||||
* Sole constructor. (For invocation by subclass constructors, typically
|
||||
* implicit.)
|
||||
*/
|
||||
protected DateFormatProvider() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new <code>DateFormat</code> instance which formats time
|
||||
* with the given formatting style for the specified locale.
|
||||
* @param style the given formatting style. Either one of
|
||||
* {@link java.text.DateFormat#SHORT DateFormat.SHORT},
|
||||
* {@link java.text.DateFormat#MEDIUM DateFormat.MEDIUM},
|
||||
* {@link java.text.DateFormat#LONG DateFormat.LONG}, or
|
||||
* {@link java.text.DateFormat#FULL DateFormat.FULL}.
|
||||
* @param locale the desired locale.
|
||||
* @exception IllegalArgumentException if <code>style</code> is invalid,
|
||||
* or if <code>locale</code> isn't
|
||||
* one of the locales returned from
|
||||
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
|
||||
* getAvailableLocales()}.
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
* @return a time formatter.
|
||||
* @see java.text.DateFormat#getTimeInstance(int, java.util.Locale)
|
||||
*/
|
||||
public abstract DateFormat getTimeInstance(int style, Locale locale);
|
||||
|
||||
/**
|
||||
* Returns a new <code>DateFormat</code> instance which formats date
|
||||
* with the given formatting style for the specified locale.
|
||||
* @param style the given formatting style. Either one of
|
||||
* {@link java.text.DateFormat#SHORT DateFormat.SHORT},
|
||||
* {@link java.text.DateFormat#MEDIUM DateFormat.MEDIUM},
|
||||
* {@link java.text.DateFormat#LONG DateFormat.LONG}, or
|
||||
* {@link java.text.DateFormat#FULL DateFormat.FULL}.
|
||||
* @param locale the desired locale.
|
||||
* @exception IllegalArgumentException if <code>style</code> is invalid,
|
||||
* or if <code>locale</code> isn't
|
||||
* one of the locales returned from
|
||||
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
|
||||
* getAvailableLocales()}.
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
* @return a date formatter.
|
||||
* @see java.text.DateFormat#getDateInstance(int, java.util.Locale)
|
||||
*/
|
||||
public abstract DateFormat getDateInstance(int style, Locale locale);
|
||||
|
||||
/**
|
||||
* Returns a new <code>DateFormat</code> instance which formats date and time
|
||||
* with the given formatting style for the specified locale.
|
||||
* @param dateStyle the given date formatting style. Either one of
|
||||
* {@link java.text.DateFormat#SHORT DateFormat.SHORT},
|
||||
* {@link java.text.DateFormat#MEDIUM DateFormat.MEDIUM},
|
||||
* {@link java.text.DateFormat#LONG DateFormat.LONG}, or
|
||||
* {@link java.text.DateFormat#FULL DateFormat.FULL}.
|
||||
* @param timeStyle the given time formatting style. Either one of
|
||||
* {@link java.text.DateFormat#SHORT DateFormat.SHORT},
|
||||
* {@link java.text.DateFormat#MEDIUM DateFormat.MEDIUM},
|
||||
* {@link java.text.DateFormat#LONG DateFormat.LONG}, or
|
||||
* {@link java.text.DateFormat#FULL DateFormat.FULL}.
|
||||
* @param locale the desired locale.
|
||||
* @exception IllegalArgumentException if <code>dateStyle</code> or
|
||||
* <code>timeStyle</code> is invalid,
|
||||
* or if <code>locale</code> isn't
|
||||
* one of the locales returned from
|
||||
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
|
||||
* getAvailableLocales()}.
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
* @return a date/time formatter.
|
||||
* @see java.text.DateFormat#getDateTimeInstance(int, int, java.util.Locale)
|
||||
*/
|
||||
public abstract DateFormat
|
||||
getDateTimeInstance(int dateStyle, int timeStyle, Locale locale);
|
||||
}
|
||||
62
jdkSrc/jdk8/java/text/spi/DateFormatSymbolsProvider.java
Normal file
62
jdkSrc/jdk8/java/text/spi/DateFormatSymbolsProvider.java
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.text.spi;
|
||||
|
||||
import java.text.DateFormatSymbols;
|
||||
import java.util.Locale;
|
||||
import java.util.spi.LocaleServiceProvider;
|
||||
|
||||
/**
|
||||
* An abstract class for service providers that
|
||||
* provide instances of the
|
||||
* {@link java.text.DateFormatSymbols DateFormatSymbols} class.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public abstract class DateFormatSymbolsProvider extends LocaleServiceProvider {
|
||||
|
||||
/**
|
||||
* Sole constructor. (For invocation by subclass constructors, typically
|
||||
* implicit.)
|
||||
*/
|
||||
protected DateFormatSymbolsProvider() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new <code>DateFormatSymbols</code> instance for the
|
||||
* specified locale.
|
||||
*
|
||||
* @param locale the desired locale
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
* @exception IllegalArgumentException if <code>locale</code> isn't
|
||||
* one of the locales returned from
|
||||
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
|
||||
* getAvailableLocales()}.
|
||||
* @return a <code>DateFormatSymbols</code> instance.
|
||||
* @see java.text.DateFormatSymbols#getInstance(java.util.Locale)
|
||||
*/
|
||||
public abstract DateFormatSymbols getInstance(Locale locale);
|
||||
}
|
||||
72
jdkSrc/jdk8/java/text/spi/DecimalFormatSymbolsProvider.java
Normal file
72
jdkSrc/jdk8/java/text/spi/DecimalFormatSymbolsProvider.java
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.text.spi;
|
||||
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.util.Locale;
|
||||
import java.util.spi.LocaleServiceProvider;
|
||||
|
||||
/**
|
||||
* An abstract class for service providers that
|
||||
* provide instances of the
|
||||
* {@link java.text.DecimalFormatSymbols DecimalFormatSymbols} class.
|
||||
*
|
||||
* <p>The requested {@code Locale} may contain an <a
|
||||
* href="../../util/Locale.html#def_locale_extension"> extension</a> for
|
||||
* specifying the desired numbering system. For example, {@code "ar-u-nu-arab"}
|
||||
* (in the BCP 47 language tag form) specifies Arabic with the Arabic-Indic
|
||||
* digits and symbols, while {@code "ar-u-nu-latn"} specifies Arabic with the
|
||||
* Latin digits and symbols. Refer to the <em>Unicode Locale Data Markup
|
||||
* Language (LDML)</em> specification for numbering systems.
|
||||
*
|
||||
* @since 1.6
|
||||
* @see Locale#forLanguageTag(String)
|
||||
* @see Locale#getExtension(char)
|
||||
*/
|
||||
public abstract class DecimalFormatSymbolsProvider extends LocaleServiceProvider {
|
||||
|
||||
/**
|
||||
* Sole constructor. (For invocation by subclass constructors, typically
|
||||
* implicit.)
|
||||
*/
|
||||
protected DecimalFormatSymbolsProvider() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new <code>DecimalFormatSymbols</code> instance for the
|
||||
* specified locale.
|
||||
*
|
||||
* @param locale the desired locale
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
* @exception IllegalArgumentException if <code>locale</code> isn't
|
||||
* one of the locales returned from
|
||||
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
|
||||
* getAvailableLocales()}.
|
||||
* @return a <code>DecimalFormatSymbols</code> instance.
|
||||
* @see java.text.DecimalFormatSymbols#getInstance(java.util.Locale)
|
||||
*/
|
||||
public abstract DecimalFormatSymbols getInstance(Locale locale);
|
||||
}
|
||||
113
jdkSrc/jdk8/java/text/spi/NumberFormatProvider.java
Normal file
113
jdkSrc/jdk8/java/text/spi/NumberFormatProvider.java
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.text.spi;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.spi.LocaleServiceProvider;
|
||||
|
||||
/**
|
||||
* An abstract class for service providers that
|
||||
* provide concrete implementations of the
|
||||
* {@link java.text.NumberFormat NumberFormat} class.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public abstract class NumberFormatProvider extends LocaleServiceProvider {
|
||||
|
||||
/**
|
||||
* Sole constructor. (For invocation by subclass constructors, typically
|
||||
* implicit.)
|
||||
*/
|
||||
protected NumberFormatProvider() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new <code>NumberFormat</code> instance which formats
|
||||
* monetary values for the specified locale.
|
||||
*
|
||||
* @param locale the desired locale.
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
* @exception IllegalArgumentException if <code>locale</code> isn't
|
||||
* one of the locales returned from
|
||||
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
|
||||
* getAvailableLocales()}.
|
||||
* @return a currency formatter
|
||||
* @see java.text.NumberFormat#getCurrencyInstance(java.util.Locale)
|
||||
*/
|
||||
public abstract NumberFormat getCurrencyInstance(Locale locale);
|
||||
|
||||
/**
|
||||
* Returns a new <code>NumberFormat</code> instance which formats
|
||||
* integer values for the specified locale.
|
||||
* The returned number format is configured to
|
||||
* round floating point numbers to the nearest integer using
|
||||
* half-even rounding (see {@link java.math.RoundingMode#HALF_EVEN HALF_EVEN})
|
||||
* for formatting, and to parse only the integer part of
|
||||
* an input string (see {@link
|
||||
* java.text.NumberFormat#isParseIntegerOnly isParseIntegerOnly}).
|
||||
*
|
||||
* @param locale the desired locale
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
* @exception IllegalArgumentException if <code>locale</code> isn't
|
||||
* one of the locales returned from
|
||||
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
|
||||
* getAvailableLocales()}.
|
||||
* @return a number format for integer values
|
||||
* @see java.text.NumberFormat#getIntegerInstance(java.util.Locale)
|
||||
*/
|
||||
public abstract NumberFormat getIntegerInstance(Locale locale);
|
||||
|
||||
/**
|
||||
* Returns a new general-purpose <code>NumberFormat</code> instance for
|
||||
* the specified locale.
|
||||
*
|
||||
* @param locale the desired locale
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
* @exception IllegalArgumentException if <code>locale</code> isn't
|
||||
* one of the locales returned from
|
||||
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
|
||||
* getAvailableLocales()}.
|
||||
* @return a general-purpose number formatter
|
||||
* @see java.text.NumberFormat#getNumberInstance(java.util.Locale)
|
||||
*/
|
||||
public abstract NumberFormat getNumberInstance(Locale locale);
|
||||
|
||||
/**
|
||||
* Returns a new <code>NumberFormat</code> instance which formats
|
||||
* percentage values for the specified locale.
|
||||
*
|
||||
* @param locale the desired locale
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
* @exception IllegalArgumentException if <code>locale</code> isn't
|
||||
* one of the locales returned from
|
||||
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
|
||||
* getAvailableLocales()}.
|
||||
* @return a percent formatter
|
||||
* @see java.text.NumberFormat#getPercentInstance(java.util.Locale)
|
||||
*/
|
||||
public abstract NumberFormat getPercentInstance(Locale locale);
|
||||
}
|
||||
Reference in New Issue
Block a user