All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ibm.icu.impl.SimplePatternFormatter Maven / Gradle / Ivy

Go to download

International Component for Unicode for Java (ICU4J) is a mature, widely used Java library providing Unicode and Globalization support

There is a newer version: 76.1
Show newest version
/*
 *******************************************************************************
 * Copyright (C) 2014, International Business Machines Corporation and         *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 */
package com.ibm.icu.impl;

import java.util.ArrayList;
import java.util.List;

/**
 * Compiled version of a pattern such as "{1} was born in {0}".
 * 

* Using SimplePatternFormatter objects is both faster and safer than adhoc replacement * such as pattern.replace("{0}", "Colorado").replace("{1} "Fred");. * They are faster because they are precompiled; they are safer because they * account for curly braces escaped by apostrophe ('). * * Placeholders are of the form \{[0-9]+\}. If a curly brace is preceded * by a single quote, it becomes a curly brace instead of the start of a * placeholder. Two single quotes resolve to one single quote. *

* SimplePatternFormatter objects are immutable and can be safely cached like strings. *

* Example: *

 * SimplePatternFormatter fmt = SimplePatternFormatter.compile("{1} '{born} in {0}");
 * 
 * // Output: "paul {born} in england"
 * System.out.println(fmt.format("england", "paul"));
 * 
*/ public class SimplePatternFormatter { private final String patternWithoutPlaceholders; private final int placeholderCount; // [0] first offset; [1] first placeholderId; [2] second offset; // [3] second placeholderId etc. private final int[] placeholderIdsOrderedByOffset; private SimplePatternFormatter(String pattern, PlaceholdersBuilder builder) { this.patternWithoutPlaceholders = pattern; this.placeholderIdsOrderedByOffset = builder.getPlaceholderIdsOrderedByOffset(); this.placeholderCount = builder.getPlaceholderCount(); } /** * Compiles a string. * @param pattern The string. * @return the new SimplePatternFormatter object. */ public static SimplePatternFormatter compile(CharSequence pattern) { PlaceholdersBuilder placeholdersBuilder = new PlaceholdersBuilder(); PlaceholderIdBuilder idBuilder = new PlaceholderIdBuilder(); StringBuilder newPattern = new StringBuilder(); State state = State.INIT; for (int i = 0; i < pattern.length(); i++) { char ch = pattern.charAt(i); switch (state) { case INIT: if (ch == 0x27) { state = State.APOSTROPHE; } else if (ch == '{') { state = State.PLACEHOLDER; idBuilder.reset(); } else { newPattern.append(ch); } break; case APOSTROPHE: if (ch == 0x27) { newPattern.append("'"); } else if (ch == '{') { newPattern.append("{"); } else { newPattern.append("'"); newPattern.append(ch); } state = State.INIT; break; case PLACEHOLDER: if (ch >= '0' && ch <= '9') { idBuilder.add(ch); } else if (ch == '}' && idBuilder.isValid()) { placeholdersBuilder.add(idBuilder.getId(), newPattern.length()); state = State.INIT; } else { newPattern.append('{'); idBuilder.appendTo(newPattern); newPattern.append(ch); state = State.INIT; } break; default: throw new IllegalStateException(); } } switch (state) { case INIT: break; case APOSTROPHE: newPattern.append("'"); break; case PLACEHOLDER: newPattern.append('{'); idBuilder.appendTo(newPattern); break; default: throw new IllegalStateException(); } return new SimplePatternFormatter(newPattern.toString(), placeholdersBuilder); } /** * Returns the max placeholder ID + 1. */ public int getPlaceholderCount() { return placeholderCount; } /** * Formats the given values. */ public String format(CharSequence... values) { return format(new StringBuilder(), null, values).toString(); } /** * Formats the given values. * * @param appendTo the result appended here. * @param offsets position of first value in appendTo stored in offfsets[0]; * second in offsets[1]; third in offsets[2] etc. An offset of -1 means that the * corresponding value is not in appendTo. offsets.length and values.length may * differ. If caller is not interested in offsets, caller may pass null here. * @param values the values * @return appendTo */ public StringBuilder format( StringBuilder appendTo, int[] offsets, CharSequence... values) { if (values.length < placeholderCount) { throw new IllegalArgumentException("Too few values."); } int offsetLen = offsets == null ? 0 : offsets.length; for (int i = 0; i < offsetLen; i++) { offsets[i] = -1; } if (placeholderIdsOrderedByOffset.length == 0) { appendTo.append(patternWithoutPlaceholders); return appendTo; } appendTo.append( patternWithoutPlaceholders, 0, placeholderIdsOrderedByOffset[0]); setPlaceholderOffset( placeholderIdsOrderedByOffset[1], appendTo.length(), offsets, offsetLen); appendTo.append(values[placeholderIdsOrderedByOffset[1]]); for (int i = 2; i < placeholderIdsOrderedByOffset.length; i += 2) { appendTo.append( patternWithoutPlaceholders, placeholderIdsOrderedByOffset[i - 2], placeholderIdsOrderedByOffset[i]); setPlaceholderOffset( placeholderIdsOrderedByOffset[i + 1], appendTo.length(), offsets, offsetLen); appendTo.append(values[placeholderIdsOrderedByOffset[i + 1]]); } appendTo.append( patternWithoutPlaceholders, placeholderIdsOrderedByOffset[placeholderIdsOrderedByOffset.length - 2], patternWithoutPlaceholders.length()); return appendTo; } /** * Formats this object using values {0}, {1} etc. Note that this is * not the same as the original pattern string used to build this object. */ @Override public String toString() { String[] values = new String[this.getPlaceholderCount()]; for (int i = 0; i < values.length; i++) { values[i] = String.format("{%d}", i); } return format(new StringBuilder(), null, values).toString(); } private static void setPlaceholderOffset( int placeholderId, int offset, int[] offsets, int offsetLen) { if (placeholderId < offsetLen) { offsets[placeholderId] = offset; } } private static enum State { INIT, APOSTROPHE, PLACEHOLDER, } private static class PlaceholderIdBuilder { private int id = 0; private int idLen = 0; public void reset() { id = 0; idLen = 0; } public int getId() { return id; } public void appendTo(StringBuilder appendTo) { if (idLen > 0) { appendTo.append(id); } } public boolean isValid() { return idLen > 0; } public void add(char ch) { id = id * 10 + ch - '0'; idLen++; } } private static class PlaceholdersBuilder { private List placeholderIdsOrderedByOffset = new ArrayList(); private int placeholderCount = 0; public void add(int placeholderId, int offset) { placeholderIdsOrderedByOffset.add(offset); placeholderIdsOrderedByOffset.add(placeholderId); if (placeholderId >= placeholderCount) { placeholderCount = placeholderId + 1; } } public int getPlaceholderCount() { return placeholderCount; } public int[] getPlaceholderIdsOrderedByOffset() { int[] result = new int[placeholderIdsOrderedByOffset.size()]; for (int i = 0; i < result.length; i++) { result[i] = placeholderIdsOrderedByOffset.get(i).intValue(); } return result; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy