| // © 2017 and later: Unicode, Inc. and others. |
| // License & terms of use: http://www.unicode.org/copyright.html#License |
| package com.ibm.icu.text; |
| |
| import java.util.Locale; |
| |
| import com.ibm.icu.impl.CaseMapImpl; |
| import com.ibm.icu.impl.UCaseProps; |
| import com.ibm.icu.lang.UCharacter; |
| import com.ibm.icu.util.ULocale; |
| |
| /** |
| * Low-level case mapping options and methods. Immutable. |
| * "Setters" return instances with the union of the current and new options set. |
| * |
| * This class is not intended for public subclassing. |
| * |
| * @stable ICU 59 |
| */ |
| public abstract class CaseMap { |
| /** |
| * @internal |
| * @deprecated This API is ICU internal only. |
| */ |
| @Deprecated |
| protected int internalOptions; |
| |
| private CaseMap(int opt) { internalOptions = opt; } |
| |
| private static int getCaseLocale(Locale locale) { |
| if (locale == null) { |
| locale = Locale.getDefault(); |
| } |
| return UCaseProps.getCaseLocale(locale); |
| } |
| |
| /** |
| * @return Lowercasing object with default options. |
| * @stable ICU 59 |
| */ |
| public static Lower toLower() { return Lower.DEFAULT; } |
| /** |
| * @return Uppercasing object with default options. |
| * @stable ICU 59 |
| */ |
| public static Upper toUpper() { return Upper.DEFAULT; } |
| /** |
| * @return Titlecasing object with default options. |
| * @stable ICU 59 |
| */ |
| public static Title toTitle() { return Title.DEFAULT; } |
| /** |
| * @return Case folding object with default options. |
| * @stable ICU 59 |
| */ |
| public static Fold fold() { return Fold.DEFAULT; } |
| |
| /** |
| * Returns an instance that behaves like this one but |
| * omits unchanged text when case-mapping with {@link Edits}. |
| * |
| * @return an options object with this option. |
| * @stable ICU 59 |
| */ |
| public abstract CaseMap omitUnchangedText(); |
| |
| /** |
| * Lowercasing options and methods. Immutable. |
| * |
| * @see #toLower() |
| * @stable ICU 59 |
| */ |
| public static final class Lower extends CaseMap { |
| private static final Lower DEFAULT = new Lower(0); |
| private static final Lower OMIT_UNCHANGED = new Lower(CaseMapImpl.OMIT_UNCHANGED_TEXT); |
| private Lower(int opt) { super(opt); } |
| |
| /** |
| * {@inheritDoc} |
| * @stable ICU 59 |
| */ |
| @Override |
| public Lower omitUnchangedText() { |
| return OMIT_UNCHANGED; |
| } |
| |
| /** |
| * Lowercases a string. |
| * Casing is locale-dependent and context-sensitive. |
| * The result may be longer or shorter than the original. |
| * |
| * @param locale The locale ID. Can be null for {@link Locale#getDefault}. |
| * (See {@link ULocale#toLocale}.) |
| * @param src The original string. |
| * @return the result string. |
| * |
| * @see UCharacter#toLowerCase(Locale, String) |
| * @stable ICU 60 |
| */ |
| public String apply(Locale locale, CharSequence src) { |
| return CaseMapImpl.toLower(getCaseLocale(locale), internalOptions, src); |
| } |
| |
| /** |
| * Lowercases a string and optionally records edits (see {@link #omitUnchangedText}). |
| * Casing is locale-dependent and context-sensitive. |
| * The result may be longer or shorter than the original. |
| * |
| * @param locale The locale ID. Can be null for {@link Locale#getDefault}. |
| * (See {@link ULocale#toLocale}.) |
| * @param src The original string. |
| * @param dest A buffer for the result string. Must not be null. |
| * @param edits Records edits for index mapping, working with styled text, |
| * and getting only changes (if any). |
| * This function calls edits.reset() first. edits can be null. |
| * @return dest with the result string (or only changes) appended. |
| * |
| * @see UCharacter#toLowerCase(Locale, String) |
| * @stable ICU 59 |
| */ |
| public <A extends Appendable> A apply( |
| Locale locale, CharSequence src, A dest, Edits edits) { |
| return CaseMapImpl.toLower(getCaseLocale(locale), internalOptions, src, dest, edits); |
| } |
| } |
| |
| /** |
| * Uppercasing options and methods. Immutable. |
| * |
| * @see #toUpper() |
| * @stable ICU 59 |
| */ |
| public static final class Upper extends CaseMap { |
| private static final Upper DEFAULT = new Upper(0); |
| private static final Upper OMIT_UNCHANGED = new Upper(CaseMapImpl.OMIT_UNCHANGED_TEXT); |
| private Upper(int opt) { super(opt); } |
| |
| /** |
| * {@inheritDoc} |
| * @stable ICU 59 |
| */ |
| @Override |
| public Upper omitUnchangedText() { |
| return OMIT_UNCHANGED; |
| } |
| |
| /** |
| * Uppercases a string. |
| * Casing is locale-dependent and context-sensitive. |
| * The result may be longer or shorter than the original. |
| * |
| * @param locale The locale ID. Can be null for {@link Locale#getDefault}. |
| * (See {@link ULocale#toLocale}.) |
| * @param src The original string. |
| * @return the result string. |
| * |
| * @see UCharacter#toUpperCase(Locale, String) |
| * @stable ICU 60 |
| */ |
| public String apply(Locale locale, CharSequence src) { |
| return CaseMapImpl.toUpper(getCaseLocale(locale), internalOptions, src); |
| } |
| |
| /** |
| * Uppercases a string and optionally records edits (see {@link #omitUnchangedText}). |
| * Casing is locale-dependent and context-sensitive. |
| * The result may be longer or shorter than the original. |
| * |
| * @param locale The locale ID. Can be null for {@link Locale#getDefault}. |
| * (See {@link ULocale#toLocale}.) |
| * @param src The original string. |
| * @param dest A buffer for the result string. Must not be null. |
| * @param edits Records edits for index mapping, working with styled text, |
| * and getting only changes (if any). |
| * This function calls edits.reset() first. edits can be null. |
| * @return dest with the result string (or only changes) appended. |
| * |
| * @see UCharacter#toUpperCase(Locale, String) |
| * @stable ICU 59 |
| */ |
| public <A extends Appendable> A apply( |
| Locale locale, CharSequence src, A dest, Edits edits) { |
| return CaseMapImpl.toUpper(getCaseLocale(locale), internalOptions, src, dest, edits); |
| } |
| } |
| |
| /** |
| * Titlecasing options and methods. Immutable. |
| * |
| * @see #toTitle() |
| * @stable ICU 59 |
| */ |
| public static final class Title extends CaseMap { |
| private static final Title DEFAULT = new Title(0); |
| private static final Title OMIT_UNCHANGED = new Title(CaseMapImpl.OMIT_UNCHANGED_TEXT); |
| private Title(int opt) { super(opt); } |
| |
| /** |
| * Returns an instance that behaves like this one but |
| * titlecases the string as a whole rather than each word. |
| * (Titlecases only the character at index 0, possibly adjusted.) |
| * |
| * <p>It is an error to specify multiple titlecasing iterator options together, |
| * including both an option and an explicit BreakIterator. |
| * |
| * @return an options object with this option. |
| * @see #adjustToCased() |
| * @stable ICU 60 |
| */ |
| public Title wholeString() { |
| return new Title(CaseMapImpl.addTitleIteratorOption( |
| internalOptions, CaseMapImpl.TITLECASE_WHOLE_STRING)); |
| } |
| |
| /** |
| * Returns an instance that behaves like this one but |
| * titlecases sentences rather than words. |
| * (Titlecases only the first character of each sentence, possibly adjusted.) |
| * |
| * <p>It is an error to specify multiple titlecasing iterator options together, |
| * including both an option and an explicit BreakIterator. |
| * |
| * @return an options object with this option. |
| * @see #adjustToCased() |
| * @stable ICU 60 |
| */ |
| public Title sentences() { |
| return new Title(CaseMapImpl.addTitleIteratorOption( |
| internalOptions, CaseMapImpl.TITLECASE_SENTENCES)); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * @stable ICU 59 |
| */ |
| @Override |
| public Title omitUnchangedText() { |
| if (internalOptions == 0 || internalOptions == CaseMapImpl.OMIT_UNCHANGED_TEXT) { |
| return OMIT_UNCHANGED; |
| } |
| return new Title(internalOptions | CaseMapImpl.OMIT_UNCHANGED_TEXT); |
| } |
| |
| /** |
| * Returns an instance that behaves like this one but |
| * does not lowercase non-initial parts of words when titlecasing. |
| * |
| * <p>By default, titlecasing will titlecase the character at each |
| * (possibly adjusted) BreakIterator index and |
| * lowercase all other characters up to the next iterator index. |
| * With this option, the other characters will not be modified. |
| * |
| * @return an options object with this option. |
| * @see UCharacter#TITLECASE_NO_LOWERCASE |
| * @see #adjustToCased() |
| * @stable ICU 59 |
| */ |
| public Title noLowercase() { |
| return new Title(internalOptions | UCharacter.TITLECASE_NO_LOWERCASE); |
| } |
| |
| /** |
| * Returns an instance that behaves like this one but |
| * does not adjust the titlecasing BreakIterator indexes; |
| * titlecases exactly the characters at breaks from the iterator. |
| * |
| * <p>By default, titlecasing will take each break iterator index, |
| * adjust it to the next relevant character (see {@link #adjustToCased()}), |
| * and titlecase that one. |
| * |
| * <p>Other characters are lowercased. |
| * |
| * @return an options object with this option. |
| * @see UCharacter#TITLECASE_NO_BREAK_ADJUSTMENT |
| * @stable ICU 59 |
| */ |
| public Title noBreakAdjustment() { |
| return new Title(CaseMapImpl.addTitleAdjustmentOption( |
| internalOptions, UCharacter.TITLECASE_NO_BREAK_ADJUSTMENT)); |
| } |
| |
| /** |
| * Returns an instance that behaves like this one but |
| * adjusts each titlecasing BreakIterator index to the next cased character. |
| * (See the Unicode Standard, chapter 3, Default Case Conversion, R3 toTitlecase(X).) |
| * |
| * <p>This used to be the default index adjustment in ICU. |
| * Since ICU 60, the default index adjustment is to the next character that is |
| * a letter, number, symbol, or private use code point. |
| * (Uncased modifier letters are skipped.) |
| * The difference in behavior is small for word titlecasing, |
| * but the new adjustment is much better for whole-string and sentence titlecasing: |
| * It yields "49ers" and "«丰(abc)»" instead of "49Ers" and "«丰(Abc)»". |
| * |
| * <p>It is an error to specify multiple titlecasing adjustment options together. |
| * |
| * @return an options object with this option. |
| * @see #noBreakAdjustment() |
| * @stable ICU 60 |
| */ |
| public Title adjustToCased() { |
| return new Title(CaseMapImpl.addTitleAdjustmentOption( |
| internalOptions, CaseMapImpl.TITLECASE_ADJUST_TO_CASED)); |
| } |
| |
| /** |
| * Titlecases a string. |
| * Casing is locale-dependent and context-sensitive. |
| * The result may be longer or shorter than the original. |
| * |
| * <p>Titlecasing uses a break iterator to find the first characters of words |
| * that are to be titlecased. It titlecases those characters and lowercases |
| * all others. (This can be modified with options bits.) |
| * |
| * @param locale The locale ID. Can be null for {@link Locale#getDefault}. |
| * (See {@link ULocale#toLocale}.) |
| * @param iter A break iterator to find the first characters of words that are to be titlecased. |
| * It is set to the source string (setText()) |
| * and used one or more times for iteration (first() and next()). |
| * If null, then a word break iterator for the locale is used |
| * (or something equivalent). |
| * @param src The original string. |
| * @return the result string. |
| * |
| * @see UCharacter#toUpperCase(Locale, String) |
| * @stable ICU 60 |
| */ |
| public String apply(Locale locale, BreakIterator iter, CharSequence src) { |
| if (iter == null && locale == null) { |
| locale = Locale.getDefault(); |
| } |
| iter = CaseMapImpl.getTitleBreakIterator(locale, internalOptions, iter); |
| iter.setText(src); |
| return CaseMapImpl.toTitle(getCaseLocale(locale), internalOptions, iter, src); |
| } |
| |
| /** |
| * Titlecases a string and optionally records edits (see {@link #omitUnchangedText}). |
| * Casing is locale-dependent and context-sensitive. |
| * The result may be longer or shorter than the original. |
| * |
| * <p>Titlecasing uses a break iterator to find the first characters of words |
| * that are to be titlecased. It titlecases those characters and lowercases |
| * all others. (This can be modified with options bits.) |
| * |
| * @param locale The locale ID. Can be null for {@link Locale#getDefault}. |
| * (See {@link ULocale#toLocale}.) |
| * @param iter A break iterator to find the first characters of words that are to be titlecased. |
| * It is set to the source string (setText()) |
| * and used one or more times for iteration (first() and next()). |
| * If null, then a word break iterator for the locale is used |
| * (or something equivalent). |
| * @param src The original string. |
| * @param dest A buffer for the result string. Must not be null. |
| * @param edits Records edits for index mapping, working with styled text, |
| * and getting only changes (if any). |
| * This function calls edits.reset() first. edits can be null. |
| * @return dest with the result string (or only changes) appended. |
| * |
| * @see UCharacter#toTitleCase(Locale, String, BreakIterator, int) |
| * @stable ICU 59 |
| */ |
| public <A extends Appendable> A apply( |
| Locale locale, BreakIterator iter, CharSequence src, A dest, Edits edits) { |
| if (iter == null && locale == null) { |
| locale = Locale.getDefault(); |
| } |
| iter = CaseMapImpl.getTitleBreakIterator(locale, internalOptions, iter); |
| iter.setText(src); |
| return CaseMapImpl.toTitle( |
| getCaseLocale(locale), internalOptions, iter, src, dest, edits); |
| } |
| } |
| |
| /** |
| * Case folding options and methods. Immutable. |
| * |
| * @see #fold() |
| * @stable ICU 59 |
| */ |
| public static final class Fold extends CaseMap { |
| private static final Fold DEFAULT = new Fold(0); |
| private static final Fold TURKIC = new Fold(UCharacter.FOLD_CASE_EXCLUDE_SPECIAL_I); |
| private static final Fold OMIT_UNCHANGED = new Fold(CaseMapImpl.OMIT_UNCHANGED_TEXT); |
| private static final Fold TURKIC_OMIT_UNCHANGED = new Fold( |
| UCharacter.FOLD_CASE_EXCLUDE_SPECIAL_I | CaseMapImpl.OMIT_UNCHANGED_TEXT); |
| private Fold(int opt) { super(opt); } |
| |
| /** |
| * {@inheritDoc} |
| * @stable ICU 59 |
| */ |
| @Override |
| public Fold omitUnchangedText() { |
| return (internalOptions & UCharacter.FOLD_CASE_EXCLUDE_SPECIAL_I) == 0 ? |
| OMIT_UNCHANGED : TURKIC_OMIT_UNCHANGED; |
| } |
| |
| /** |
| * Returns an instance that behaves like this one but |
| * handles dotted I and dotless i appropriately for Turkic languages (tr, az). |
| * |
| * <p>Uses the Unicode CaseFolding.txt mappings marked with 'T' that |
| * are to be excluded for default mappings and |
| * included for the Turkic-specific mappings. |
| * |
| * @return an options object with this option. |
| * @see UCharacter#FOLD_CASE_EXCLUDE_SPECIAL_I |
| * @stable ICU 59 |
| */ |
| public Fold turkic() { |
| return (internalOptions & CaseMapImpl.OMIT_UNCHANGED_TEXT) == 0 ? |
| TURKIC : TURKIC_OMIT_UNCHANGED; |
| } |
| |
| /** |
| * Case-folds a string. |
| * The result may be longer or shorter than the original. |
| * |
| * <p>Case-folding is locale-independent and not context-sensitive, |
| * but there is an option for whether to include or exclude mappings for dotted I |
| * and dotless i that are marked with 'T' in CaseFolding.txt. |
| * |
| * @param src The original string. |
| * @return the result string. |
| * |
| * @see UCharacter#foldCase(String, int) |
| * @stable ICU 60 |
| */ |
| public String apply(CharSequence src) { |
| return CaseMapImpl.fold(internalOptions, src); |
| } |
| |
| /** |
| * Case-folds a string and optionally records edits (see {@link #omitUnchangedText}). |
| * The result may be longer or shorter than the original. |
| * |
| * <p>Case-folding is locale-independent and not context-sensitive, |
| * but there is an option for whether to include or exclude mappings for dotted I |
| * and dotless i that are marked with 'T' in CaseFolding.txt. |
| * |
| * @param src The original string. |
| * @param dest A buffer for the result string. Must not be null. |
| * @param edits Records edits for index mapping, working with styled text, |
| * and getting only changes (if any). |
| * This function calls edits.reset() first. edits can be null. |
| * @return dest with the result string (or only changes) appended. |
| * |
| * @see UCharacter#foldCase(String, int) |
| * @stable ICU 59 |
| */ |
| public <A extends Appendable> A apply(CharSequence src, A dest, Edits edits) { |
| return CaseMapImpl.fold(internalOptions, src, dest, edits); |
| } |
| } |
| } |