/* GENERATED SOURCE. DO NOT MODIFY. */ // © 2022 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html package android.icu.impl.personname; import java.util.Locale; import android.icu.lang.UCharacter; import android.icu.text.BreakIterator; import android.icu.text.CaseMap; import android.icu.text.PersonName; import android.icu.text.SimpleFormatter; /** * Parent class for classes that implement field-modifier behavior. */ abstract class FieldModifierImpl { public abstract String modifyField(String fieldValue); public static FieldModifierImpl forName(PersonName.FieldModifier modifierID, PersonNameFormatterImpl formatterImpl) { switch (modifierID) { case INFORMAL: return NOOP_MODIFIER; case PREFIX: return NULL_MODIFIER; case CORE: return NOOP_MODIFIER; case ALL_CAPS: return new AllCapsModifier(formatterImpl.getLocale()); case INITIAL_CAP: return new InitialCapModifier(formatterImpl.getLocale()); case INITIAL: return new InitialModifier(formatterImpl.getLocale(), formatterImpl.getInitialPattern(), formatterImpl.getInitialSequencePattern()); case RETAIN: // "retain" is handled by InitialMofidier and PersonNamePattern.NameFieldImpl return NOOP_MODIFIER; case MONOGRAM: return MONOGRAM_MODIFIER; case GENITIVE: // no built-in implementation for deriving genitive from nominative; PersonName object must supply return NOOP_MODIFIER; case VOCATIVE: // no built-in implementation for deriving vocative from nominative; PersonName object must supply return NOOP_MODIFIER; default: throw new IllegalArgumentException("Invalid modifier ID " + modifierID); } } /** * A field modifier that just returns the field value unmodified. This is used to implement the default * behavior of the "informal" and "core" modifiers ("real" informal or core variants have to be supplied or * calculated by the PersonName object). */ private static final FieldModifierImpl NOOP_MODIFIER = new FieldModifierImpl() { @Override public String modifyField(String fieldValue) { return fieldValue; } }; /** * A field modifier that just returns the empty string. This is used to implement the default behavior of the * "prefix" modifier ("real" prefix variants have to be supplied to calculated by the PersonName object). */ private static final FieldModifierImpl NULL_MODIFIER = new FieldModifierImpl() { @Override public String modifyField(String fieldValue) { return ""; } }; /** * A field modifier that returns the field value converted to ALL CAPS. This is the default behavior * for the "allCaps" modifier. */ private static class AllCapsModifier extends FieldModifierImpl { private final Locale locale; public AllCapsModifier(Locale locale) { this.locale = locale; } @Override public String modifyField(String fieldValue) { return UCharacter.toUpperCase(locale, fieldValue); } } /** * A field modifier that returns the field value with the first letter of each word capitalized. This is * the default behavior of the "initialCap" modifier. */ private static class InitialCapModifier extends FieldModifierImpl { private final Locale locale; private static final CaseMap.Title TO_TITLE_WHOLE_STRING_NO_LOWERCASE = CaseMap.toTitle().wholeString().noLowercase(); public InitialCapModifier(Locale locale) { this.locale = locale; } @Override public String modifyField(String fieldValue) { return TO_TITLE_WHOLE_STRING_NO_LOWERCASE.apply(locale, null, fieldValue); } } /** * A field modifier that returns the field value converted into one or more initials. This is the first grapheme * cluster of each word in the field value, modified using the initialPattern/initial resource value from the * locale data, and strung together using the initialPattern/initialSequence resource value from the locale data. * (In English, these patterns put periods after each initial and connect them with spaces.) * This is default behavior of the "initial" modifier. */ static class InitialModifier extends FieldModifierImpl { private final Locale locale; private final SimpleFormatter initialFormatter; private final SimpleFormatter initialSequenceFormatter; private boolean retainPunctuation; public InitialModifier(Locale locale, String initialPattern, String initialSequencePattern) { this.locale = locale; this.initialFormatter = SimpleFormatter.compile(initialPattern); this.initialSequenceFormatter = SimpleFormatter.compile(initialSequencePattern); this.retainPunctuation = false; } public void setRetainPunctuation(boolean retain) { this.retainPunctuation = retain; } @Override public String modifyField(String fieldValue) { String separator = ""; String result = null; BreakIterator bi = BreakIterator.getWordInstance(locale); bi.setText(fieldValue); int wordStart = bi.first(); for (int wordEnd = bi.next(); wordEnd != BreakIterator.DONE; wordStart = wordEnd, wordEnd = bi.next()) { String word = fieldValue.substring(wordStart, wordEnd); if (Character.isLetter(word.charAt(0))) { String curInitial = getFirstGrapheme(word); if (result == null) { result = initialFormatter.format(curInitial); } else if (retainPunctuation) { result = result + separator + initialFormatter.format(curInitial); separator = ""; } else { result = initialSequenceFormatter.format(result, initialFormatter.format(curInitial)); } } else if (Character.isWhitespace(word.charAt(0))) { // coalesce a sequence of whitespace characters down to a single space separator = separator + word.charAt(0); } else { separator = separator + word; } } return result; } } /** * A field modifier that simply returns the first grapheme cluster in the field value. * This is the default implementation of the "monogram" modifier. */ private static final FieldModifierImpl MONOGRAM_MODIFIER = new FieldModifierImpl() { @Override public String modifyField(String fieldValue) { return getFirstGrapheme(fieldValue); } }; /** * A utility function that just returns the first grapheme cluster in the string. */ private static String getFirstGrapheme(String s) { // early out if the string is empty to avoid StringIndexOutOfBoundsException if (s.isEmpty()) { return ""; } // (currently, no locale overrides the grapheme-break rules, so we just use "root" instead of passing in the locale) BreakIterator bi = BreakIterator.getCharacterInstance(Locale.ROOT); bi.setText(s); return s.substring(0, bi.next()); } }