mirror of
https://github.com/Eaglercraft-Archive/Eaglercraftx-1.8.8-src.git
synced 2025-06-28 10:58:15 -05:00
Update #0 - First Release
This commit is contained in:
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.lang3.text;
|
||||
|
||||
import java.text.FieldPosition;
|
||||
import java.text.Format;
|
||||
import java.text.ParseException;
|
||||
import java.text.ParsePosition;
|
||||
|
||||
/**
|
||||
* Formats using one formatter and parses using a different formatter. An
|
||||
* example of use for this would be a webapp where data is taken in one way and
|
||||
* stored in a database another way.
|
||||
*
|
||||
* @deprecated as of 3.6, use commons-text <a href=
|
||||
* "https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/CompositeFormat.html">
|
||||
* CompositeFormat</a> instead
|
||||
*/
|
||||
@Deprecated
|
||||
public class CompositeFormat extends Format {
|
||||
|
||||
/**
|
||||
* Required for serialization support.
|
||||
*
|
||||
* @see java.io.Serializable
|
||||
*/
|
||||
private static final long serialVersionUID = -4329119827877627683L;
|
||||
|
||||
/** The parser to use. */
|
||||
private final Format parser;
|
||||
/** The formatter to use. */
|
||||
private final Format formatter;
|
||||
|
||||
/**
|
||||
* Create a format that points its parseObject method to one implementation and
|
||||
* its format method to another.
|
||||
*
|
||||
* @param parser implementation
|
||||
* @param formatter implementation
|
||||
*/
|
||||
public CompositeFormat(final Format parser, final Format formatter) {
|
||||
this.parser = parser;
|
||||
this.formatter = formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the formatter Format instance.
|
||||
*
|
||||
* @param obj the object to format
|
||||
* @param toAppendTo the {@link StringBuffer} to append to
|
||||
* @param pos the FieldPosition to use (or ignore).
|
||||
* @return {@code toAppendTo}
|
||||
* @see Format#format(Object, StringBuffer, FieldPosition)
|
||||
*/
|
||||
@Override // Therefore has to use StringBuffer
|
||||
public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
|
||||
return formatter.format(obj, toAppendTo, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the parser Format instance.
|
||||
*
|
||||
* @param source the String source
|
||||
* @param pos the ParsePosition containing the position to parse from, will
|
||||
* be updated according to parsing success (index) or failure
|
||||
* (error index)
|
||||
* @return the parsed Object
|
||||
* @see Format#parseObject(String, ParsePosition)
|
||||
*/
|
||||
@Override
|
||||
public Object parseObject(final String source, final ParsePosition pos) {
|
||||
return parser.parseObject(source, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to the parser Format implementation.
|
||||
*
|
||||
* @return parser Format implementation
|
||||
*/
|
||||
public Format getParser() {
|
||||
return this.parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to the parser Format implementation.
|
||||
*
|
||||
* @return formatter Format implementation
|
||||
*/
|
||||
public Format getFormatter() {
|
||||
return this.formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to parse and then reformat a String.
|
||||
*
|
||||
* @param input String to reformat
|
||||
* @return A reformatted String
|
||||
* @throws ParseException thrown by parseObject(String) call
|
||||
*/
|
||||
public String reformat(final String input) throws ParseException {
|
||||
return format(parseObject(input));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,530 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.lang3.text;
|
||||
|
||||
import java.text.Format;
|
||||
import java.text.MessageFormat;
|
||||
import java.text.ParsePosition;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.commons.lang3.LocaleUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
/**
|
||||
* Extends {@code java.text.MessageFormat} to allow pluggable/additional
|
||||
* formatting options for embedded format elements. Client code should specify a
|
||||
* registry of {@code FormatFactory} instances associated with {@code String}
|
||||
* format names. This registry will be consulted when the format elements are
|
||||
* parsed from the message pattern. In this way custom patterns can be
|
||||
* specified, and the formats supported by {@code java.text.MessageFormat} can
|
||||
* be overridden at the format and/or format style level (see MessageFormat). A
|
||||
* "format element" embedded in the message pattern is specified (<b>()?</b>
|
||||
* signifies optionality):<br>
|
||||
* <code>{</code><i>argument-number</i><b>(</b>{@code ,}<i>format-name</i><b>
|
||||
* (</b>{@code ,}<i>format-style</i><b>)?)?</b><code>}</code>
|
||||
*
|
||||
* <p>
|
||||
* <i>format-name</i> and <i>format-style</i> values are trimmed of surrounding
|
||||
* whitespace in the manner of {@code java.text.MessageFormat}. If
|
||||
* <i>format-name</i> denotes {@code FormatFactory formatFactoryInstance} in
|
||||
* {@code registry}, a {@code Format} matching <i>format-name</i> and
|
||||
* <i>format-style</i> is requested from {@code formatFactoryInstance}. If this
|
||||
* is successful, the {@code Format} found is used for this format element.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>NOTICE:</b> The various subformat mutator methods are considered
|
||||
* unnecessary; they exist on the parent class to allow the type of
|
||||
* customization which it is the job of this class to provide in a configurable
|
||||
* fashion. These methods have thus been disabled and will throw
|
||||
* {@code UnsupportedOperationException} if called.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Limitations inherited from {@code java.text.MessageFormat}:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>When using "choice" subformats, support for nested formatting
|
||||
* instructions is limited to that provided by the base class.</li>
|
||||
* <li>Thread-safety of {@code Format}s, including {@code MessageFormat} and
|
||||
* thus {@code ExtendedMessageFormat}, is not guaranteed.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 2.4
|
||||
* @deprecated as of 3.6, use commons-text <a href=
|
||||
* "https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/ExtendedMessageFormat.html">
|
||||
* ExtendedMessageFormat</a> instead
|
||||
*/
|
||||
@Deprecated
|
||||
public class ExtendedMessageFormat extends MessageFormat {
|
||||
private static final long serialVersionUID = -2362048321261811743L;
|
||||
private static final int HASH_SEED = 31;
|
||||
|
||||
private static final String DUMMY_PATTERN = "";
|
||||
private static final char START_FMT = ',';
|
||||
private static final char END_FE = '}';
|
||||
private static final char START_FE = '{';
|
||||
private static final char QUOTE = '\'';
|
||||
|
||||
private String toPattern;
|
||||
private final Map<String, ? extends FormatFactory> registry;
|
||||
|
||||
/**
|
||||
* Create a new ExtendedMessageFormat for the default locale.
|
||||
*
|
||||
* @param pattern the pattern to use, not null
|
||||
* @throws IllegalArgumentException in case of a bad pattern.
|
||||
*/
|
||||
public ExtendedMessageFormat(final String pattern) {
|
||||
this(pattern, Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ExtendedMessageFormat.
|
||||
*
|
||||
* @param pattern the pattern to use, not null
|
||||
* @param locale the locale to use, not null
|
||||
* @throws IllegalArgumentException in case of a bad pattern.
|
||||
*/
|
||||
public ExtendedMessageFormat(final String pattern, final Locale locale) {
|
||||
this(pattern, locale, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ExtendedMessageFormat for the default locale.
|
||||
*
|
||||
* @param pattern the pattern to use, not null
|
||||
* @param registry the registry of format factories, may be null
|
||||
* @throws IllegalArgumentException in case of a bad pattern.
|
||||
*/
|
||||
public ExtendedMessageFormat(final String pattern, final Map<String, ? extends FormatFactory> registry) {
|
||||
this(pattern, Locale.getDefault(), registry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ExtendedMessageFormat.
|
||||
*
|
||||
* @param pattern the pattern to use, not null.
|
||||
* @param locale the locale to use.
|
||||
* @param registry the registry of format factories, may be null.
|
||||
* @throws IllegalArgumentException in case of a bad pattern.
|
||||
*/
|
||||
public ExtendedMessageFormat(final String pattern, final Locale locale,
|
||||
final Map<String, ? extends FormatFactory> registry) {
|
||||
super(DUMMY_PATTERN);
|
||||
setLocale(LocaleUtils.toLocale(locale));
|
||||
this.registry = registry;
|
||||
applyPattern(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toPattern() {
|
||||
return toPattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the specified pattern.
|
||||
*
|
||||
* @param pattern String
|
||||
*/
|
||||
@Override
|
||||
public final void applyPattern(final String pattern) {
|
||||
if (registry == null) {
|
||||
super.applyPattern(pattern);
|
||||
toPattern = super.toPattern();
|
||||
return;
|
||||
}
|
||||
final ArrayList<Format> foundFormats = new ArrayList<>();
|
||||
final ArrayList<String> foundDescriptions = new ArrayList<>();
|
||||
final StringBuilder stripCustom = new StringBuilder(pattern.length());
|
||||
|
||||
final ParsePosition pos = new ParsePosition(0);
|
||||
final char[] c = pattern.toCharArray();
|
||||
int fmtCount = 0;
|
||||
while (pos.getIndex() < pattern.length()) {
|
||||
switch (c[pos.getIndex()]) {
|
||||
case QUOTE:
|
||||
appendQuotedString(pattern, pos, stripCustom);
|
||||
break;
|
||||
case START_FE:
|
||||
fmtCount++;
|
||||
seekNonWs(pattern, pos);
|
||||
final int start = pos.getIndex();
|
||||
final int index = readArgumentIndex(pattern, next(pos));
|
||||
stripCustom.append(START_FE).append(index);
|
||||
seekNonWs(pattern, pos);
|
||||
Format format = null;
|
||||
String formatDescription = null;
|
||||
if (c[pos.getIndex()] == START_FMT) {
|
||||
formatDescription = parseFormatDescription(pattern, next(pos));
|
||||
format = getFormat(formatDescription);
|
||||
if (format == null) {
|
||||
stripCustom.append(START_FMT).append(formatDescription);
|
||||
}
|
||||
}
|
||||
foundFormats.add(format);
|
||||
foundDescriptions.add(format == null ? null : formatDescription);
|
||||
Validate.isTrue(foundFormats.size() == fmtCount);
|
||||
Validate.isTrue(foundDescriptions.size() == fmtCount);
|
||||
if (c[pos.getIndex()] != END_FE) {
|
||||
throw new IllegalArgumentException("Unreadable format element at position " + start);
|
||||
}
|
||||
//$FALL-THROUGH$
|
||||
default:
|
||||
stripCustom.append(c[pos.getIndex()]);
|
||||
next(pos);
|
||||
}
|
||||
}
|
||||
super.applyPattern(stripCustom.toString());
|
||||
toPattern = insertFormats(super.toPattern(), foundDescriptions);
|
||||
if (containsElements(foundFormats)) {
|
||||
final Format[] origFormats = getFormats();
|
||||
// only loop over what we know we have, as MessageFormat on Java 1.3
|
||||
// seems to provide an extra format element:
|
||||
int i = 0;
|
||||
for (final Iterator<Format> it = foundFormats.iterator(); it.hasNext(); i++) {
|
||||
final Format f = it.next();
|
||||
if (f != null) {
|
||||
origFormats[i] = f;
|
||||
}
|
||||
}
|
||||
super.setFormats(origFormats);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws UnsupportedOperationException - see class Javadoc for details.
|
||||
*
|
||||
* @param formatElementIndex format element index
|
||||
* @param newFormat the new format
|
||||
* @throws UnsupportedOperationException always thrown since this isn't
|
||||
* supported by ExtendMessageFormat
|
||||
*/
|
||||
@Override
|
||||
public void setFormat(final int formatElementIndex, final Format newFormat) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws UnsupportedOperationException - see class Javadoc for details.
|
||||
*
|
||||
* @param argumentIndex argument index
|
||||
* @param newFormat the new format
|
||||
* @throws UnsupportedOperationException always thrown since this isn't
|
||||
* supported by ExtendMessageFormat
|
||||
*/
|
||||
@Override
|
||||
public void setFormatByArgumentIndex(final int argumentIndex, final Format newFormat) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws UnsupportedOperationException - see class Javadoc for details.
|
||||
*
|
||||
* @param newFormats new formats
|
||||
* @throws UnsupportedOperationException always thrown since this isn't
|
||||
* supported by ExtendMessageFormat
|
||||
*/
|
||||
@Override
|
||||
public void setFormats(final Format[] newFormats) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws UnsupportedOperationException - see class Javadoc for details.
|
||||
*
|
||||
* @param newFormats new formats
|
||||
* @throws UnsupportedOperationException always thrown since this isn't
|
||||
* supported by ExtendMessageFormat
|
||||
*/
|
||||
@Override
|
||||
public void setFormatsByArgumentIndex(final Format[] newFormats) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this extended message format is equal to another object.
|
||||
*
|
||||
* @param obj the object to compare to
|
||||
* @return true if this object equals the other, otherwise false
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!super.equals(obj)) {
|
||||
return false;
|
||||
}
|
||||
if (ObjectUtils.notEqual(getClass(), obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
final ExtendedMessageFormat rhs = (ExtendedMessageFormat) obj;
|
||||
if (ObjectUtils.notEqual(toPattern, rhs.toPattern)) {
|
||||
return false;
|
||||
}
|
||||
return !ObjectUtils.notEqual(registry, rhs.registry);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = HASH_SEED * result + Objects.hashCode(registry);
|
||||
result = HASH_SEED * result + Objects.hashCode(toPattern);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a custom format from a format description.
|
||||
*
|
||||
* @param desc String
|
||||
* @return Format
|
||||
*/
|
||||
private Format getFormat(final String desc) {
|
||||
if (registry != null) {
|
||||
String name = desc;
|
||||
String args = null;
|
||||
final int i = desc.indexOf(START_FMT);
|
||||
if (i > 0) {
|
||||
name = desc.substring(0, i).trim();
|
||||
args = desc.substring(i + 1).trim();
|
||||
}
|
||||
final FormatFactory factory = registry.get(name);
|
||||
if (factory != null) {
|
||||
return factory.getFormat(name, args, getLocale());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the argument index from the current format element
|
||||
*
|
||||
* @param pattern pattern to parse
|
||||
* @param pos current parse position
|
||||
* @return argument index
|
||||
*/
|
||||
private int readArgumentIndex(final String pattern, final ParsePosition pos) {
|
||||
final int start = pos.getIndex();
|
||||
seekNonWs(pattern, pos);
|
||||
final StringBuilder result = new StringBuilder();
|
||||
boolean error = false;
|
||||
for (; !error && pos.getIndex() < pattern.length(); next(pos)) {
|
||||
char c = pattern.charAt(pos.getIndex());
|
||||
if (Character.isWhitespace(c)) {
|
||||
seekNonWs(pattern, pos);
|
||||
c = pattern.charAt(pos.getIndex());
|
||||
if (c != START_FMT && c != END_FE) {
|
||||
error = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ((c == START_FMT || c == END_FE) && result.length() > 0) {
|
||||
try {
|
||||
return Integer.parseInt(result.toString());
|
||||
} catch (final NumberFormatException e) { // NOPMD
|
||||
// we've already ensured only digits, so unless something
|
||||
// outlandishly large was specified we should be okay.
|
||||
}
|
||||
}
|
||||
error = !Character.isDigit(c);
|
||||
result.append(c);
|
||||
}
|
||||
if (error) {
|
||||
throw new IllegalArgumentException("Invalid format argument index at position " + start + ": "
|
||||
+ pattern.substring(start, pos.getIndex()));
|
||||
}
|
||||
throw new IllegalArgumentException("Unterminated format element at position " + start);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the format component of a format element.
|
||||
*
|
||||
* @param pattern string to parse
|
||||
* @param pos current parse position
|
||||
* @return Format description String
|
||||
*/
|
||||
private String parseFormatDescription(final String pattern, final ParsePosition pos) {
|
||||
final int start = pos.getIndex();
|
||||
seekNonWs(pattern, pos);
|
||||
final int text = pos.getIndex();
|
||||
int depth = 1;
|
||||
for (; pos.getIndex() < pattern.length(); next(pos)) {
|
||||
switch (pattern.charAt(pos.getIndex())) {
|
||||
case START_FE:
|
||||
depth++;
|
||||
break;
|
||||
case END_FE:
|
||||
depth--;
|
||||
if (depth == 0) {
|
||||
return pattern.substring(text, pos.getIndex());
|
||||
}
|
||||
break;
|
||||
case QUOTE:
|
||||
getQuotedString(pattern, pos);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unterminated format element at position " + start);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert formats back into the pattern for toPattern() support.
|
||||
*
|
||||
* @param pattern source
|
||||
* @param customPatterns The custom patterns to re-insert, if any
|
||||
* @return full pattern
|
||||
*/
|
||||
private String insertFormats(final String pattern, final ArrayList<String> customPatterns) {
|
||||
if (!containsElements(customPatterns)) {
|
||||
return pattern;
|
||||
}
|
||||
final StringBuilder sb = new StringBuilder(pattern.length() * 2);
|
||||
final ParsePosition pos = new ParsePosition(0);
|
||||
int fe = -1;
|
||||
int depth = 0;
|
||||
while (pos.getIndex() < pattern.length()) {
|
||||
final char c = pattern.charAt(pos.getIndex());
|
||||
switch (c) {
|
||||
case QUOTE:
|
||||
appendQuotedString(pattern, pos, sb);
|
||||
break;
|
||||
case START_FE:
|
||||
depth++;
|
||||
sb.append(START_FE).append(readArgumentIndex(pattern, next(pos)));
|
||||
// do not look for custom patterns when they are embedded, e.g. in a choice
|
||||
if (depth == 1) {
|
||||
fe++;
|
||||
final String customPattern = customPatterns.get(fe);
|
||||
if (customPattern != null) {
|
||||
sb.append(START_FMT).append(customPattern);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case END_FE:
|
||||
depth--;
|
||||
//$FALL-THROUGH$
|
||||
default:
|
||||
sb.append(c);
|
||||
next(pos);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume whitespace from the current parse position.
|
||||
*
|
||||
* @param pattern String to read
|
||||
* @param pos current position
|
||||
*/
|
||||
private void seekNonWs(final String pattern, final ParsePosition pos) {
|
||||
int len = 0;
|
||||
final char[] buffer = pattern.toCharArray();
|
||||
do {
|
||||
len = StrMatcher.splitMatcher().isMatch(buffer, pos.getIndex());
|
||||
pos.setIndex(pos.getIndex() + len);
|
||||
} while (len > 0 && pos.getIndex() < pattern.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to advance parse position by 1
|
||||
*
|
||||
* @param pos ParsePosition
|
||||
* @return {@code pos}
|
||||
*/
|
||||
private ParsePosition next(final ParsePosition pos) {
|
||||
pos.setIndex(pos.getIndex() + 1);
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume a quoted string, adding it to {@code appendTo} if specified.
|
||||
*
|
||||
* @param pattern pattern to parse
|
||||
* @param pos current parse position
|
||||
* @param appendTo optional StringBuilder to append
|
||||
* @return {@code appendTo}
|
||||
*/
|
||||
private StringBuilder appendQuotedString(final String pattern, final ParsePosition pos,
|
||||
final StringBuilder appendTo) {
|
||||
assert pattern.toCharArray()[pos.getIndex()] == QUOTE : "Quoted string must start with quote character";
|
||||
|
||||
// handle quote character at the beginning of the string
|
||||
if (appendTo != null) {
|
||||
appendTo.append(QUOTE);
|
||||
}
|
||||
next(pos);
|
||||
|
||||
final int start = pos.getIndex();
|
||||
final char[] c = pattern.toCharArray();
|
||||
final int lastHold = start;
|
||||
for (int i = pos.getIndex(); i < pattern.length(); i++) {
|
||||
if (c[pos.getIndex()] == QUOTE) {
|
||||
next(pos);
|
||||
return appendTo == null ? null : appendTo.append(c, lastHold, pos.getIndex() - lastHold);
|
||||
}
|
||||
next(pos);
|
||||
}
|
||||
throw new IllegalArgumentException("Unterminated quoted string at position " + start);
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume quoted string only
|
||||
*
|
||||
* @param pattern pattern to parse
|
||||
* @param pos current parse position
|
||||
*/
|
||||
private void getQuotedString(final String pattern, final ParsePosition pos) {
|
||||
appendQuotedString(pattern, pos, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Learn whether the specified Collection contains non-null elements.
|
||||
*
|
||||
* @param coll to check
|
||||
* @return {@code true} if some Object was found, {@code false} otherwise.
|
||||
*/
|
||||
private boolean containsElements(final Collection<?> coll) {
|
||||
if (coll == null || coll.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (final Object name : coll) {
|
||||
if (name != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.lang3.text;
|
||||
|
||||
import java.text.Format;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Format factory.
|
||||
*
|
||||
* @since 2.4
|
||||
* @deprecated as of 3.6, use commons-text <a href=
|
||||
* "https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/FormatFactory.html">
|
||||
* FormatFactory</a> instead
|
||||
*/
|
||||
@Deprecated
|
||||
public interface FormatFactory {
|
||||
|
||||
/**
|
||||
* Create or retrieve a format instance.
|
||||
*
|
||||
* @param name The format type name
|
||||
* @param arguments Arguments used to create the format instance. This allows
|
||||
* the {@code FormatFactory} to implement the "format style"
|
||||
* concept from {@code java.text.MessageFormat}.
|
||||
* @param locale The locale, may be null
|
||||
* @return The format instance
|
||||
*/
|
||||
Format getFormat(String name, String arguments, Locale locale);
|
||||
|
||||
}
|
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.lang3.text;
|
||||
|
||||
import static java.util.FormattableFlags.LEFT_JUSTIFY;
|
||||
|
||||
import java.util.Formattable;
|
||||
import java.util.Formatter;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.HString;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Provides utilities for working with the {@code Formattable} interface.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The {@link Formattable} interface provides basic control over formatting when
|
||||
* using a {@code Formatter}. It is primarily concerned with numeric precision
|
||||
* and padding, and is not designed to allow generalised alternate formats.
|
||||
* </p>
|
||||
*
|
||||
* @since 3.0
|
||||
* @deprecated as of 3.6, use commons-text <a href=
|
||||
* "https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/FormattableUtils.html">
|
||||
* FormattableUtils</a> instead
|
||||
*/
|
||||
@Deprecated
|
||||
public class FormattableUtils {
|
||||
|
||||
/**
|
||||
* A format that simply outputs the value as a string.
|
||||
*/
|
||||
private static final String SIMPLEST_FORMAT = "%s";
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* {@code FormattableUtils} instances should NOT be constructed in standard
|
||||
* programming. Instead, the methods of the class should be invoked statically.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This constructor is public to permit tools that require a JavaBean instance
|
||||
* to operate.
|
||||
* </p>
|
||||
*/
|
||||
public FormattableUtils() {
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the default formatted representation of the specified
|
||||
* {@code Formattable}.
|
||||
*
|
||||
* @param formattable the instance to convert to a string, not null
|
||||
* @return the resulting string, not null
|
||||
*/
|
||||
public static String toString(final Formattable formattable) {
|
||||
return HString.format(SIMPLEST_FORMAT, formattable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the common {@code Formattable} operations of truncate-pad-append,
|
||||
* with no ellipsis on precision overflow, and padding width underflow with
|
||||
* spaces.
|
||||
*
|
||||
* @param seq the string to handle, not null
|
||||
* @param formatter the destination formatter, not null
|
||||
* @param flags the flags for formatting, see {@code Formattable}
|
||||
* @param width the width of the output, see {@code Formattable}
|
||||
* @param precision the precision of the output, see {@code Formattable}
|
||||
* @return the {@code formatter} instance, not null
|
||||
*/
|
||||
public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width,
|
||||
final int precision) {
|
||||
return append(seq, formatter, flags, width, precision, ' ', null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the common {@link Formattable} operations of truncate-pad-append,
|
||||
* with no ellipsis on precision overflow.
|
||||
*
|
||||
* @param seq the string to handle, not null
|
||||
* @param formatter the destination formatter, not null
|
||||
* @param flags the flags for formatting, see {@code Formattable}
|
||||
* @param width the width of the output, see {@code Formattable}
|
||||
* @param precision the precision of the output, see {@code Formattable}
|
||||
* @param padChar the pad character to use
|
||||
* @return the {@code formatter} instance, not null
|
||||
*/
|
||||
public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width,
|
||||
final int precision, final char padChar) {
|
||||
return append(seq, formatter, flags, width, precision, padChar, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the common {@link Formattable} operations of truncate-pad-append,
|
||||
* padding width underflow with spaces.
|
||||
*
|
||||
* @param seq the string to handle, not null
|
||||
* @param formatter the destination formatter, not null
|
||||
* @param flags the flags for formatting, see {@code Formattable}
|
||||
* @param width the width of the output, see {@code Formattable}
|
||||
* @param precision the precision of the output, see {@code Formattable}
|
||||
* @param ellipsis the ellipsis to use when precision dictates truncation, null
|
||||
* or empty causes a hard truncation
|
||||
* @return the {@code formatter} instance, not null
|
||||
*/
|
||||
public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width,
|
||||
final int precision, final CharSequence ellipsis) {
|
||||
return append(seq, formatter, flags, width, precision, ' ', ellipsis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the common {@link Formattable} operations of truncate-pad-append.
|
||||
*
|
||||
* @param seq the string to handle, not null
|
||||
* @param formatter the destination formatter, not null
|
||||
* @param flags the flags for formatting, see {@code Formattable}
|
||||
* @param width the width of the output, see {@code Formattable}
|
||||
* @param precision the precision of the output, see {@code Formattable}
|
||||
* @param padChar the pad character to use
|
||||
* @param ellipsis the ellipsis to use when precision dictates truncation, null
|
||||
* or empty causes a hard truncation
|
||||
* @return the {@code formatter} instance, not null
|
||||
*/
|
||||
public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width,
|
||||
final int precision, final char padChar, final CharSequence ellipsis) {
|
||||
Validate.isTrue(ellipsis == null || precision < 0 || ellipsis.length() <= precision,
|
||||
"Specified ellipsis '%1$s' exceeds precision of %2$s", ellipsis, Integer.valueOf(precision));
|
||||
final StringBuilder buf = new StringBuilder(seq);
|
||||
if (precision >= 0 && precision < seq.length()) {
|
||||
final CharSequence _ellipsis = ObjectUtils.defaultIfNull(ellipsis, StringUtils.EMPTY);
|
||||
buf.replace(precision - _ellipsis.length(), seq.length(), _ellipsis.toString());
|
||||
}
|
||||
final boolean leftJustify = (flags & LEFT_JUSTIFY) == LEFT_JUSTIFY;
|
||||
for (int i = buf.length(); i < width; i++) {
|
||||
buf.insert(leftJustify ? i : 0, padChar);
|
||||
}
|
||||
formatter.format(buf.toString());
|
||||
return formatter;
|
||||
}
|
||||
|
||||
}
|
3143
sources/main/java/org/apache/commons/lang3/text/StrBuilder.java
Normal file
3143
sources/main/java/org/apache/commons/lang3/text/StrBuilder.java
Normal file
File diff suppressed because it is too large
Load Diff
186
sources/main/java/org/apache/commons/lang3/text/StrLookup.java
Normal file
186
sources/main/java/org/apache/commons/lang3/text/StrLookup.java
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.lang3.text;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Lookup a String key to a String value.
|
||||
* <p>
|
||||
* This class represents the simplest form of a string to string map. It has a
|
||||
* benefit over a map in that it can create the result on demand based on the
|
||||
* key.
|
||||
* <p>
|
||||
* This class comes complete with various factory methods. If these do not
|
||||
* suffice, you can subclass and implement your own matcher.
|
||||
* <p>
|
||||
* For example, it would be possible to implement a lookup that used the key as
|
||||
* a primary key, and looked up the value on demand from the database.
|
||||
*
|
||||
* @param <V> Unused.
|
||||
* @since 2.2
|
||||
* @deprecated as of 3.6, use commons-text <a href=
|
||||
* "https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/lookup/StringLookupFactory.html">
|
||||
* StringLookupFactory</a> instead
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class StrLookup<V> {
|
||||
|
||||
/**
|
||||
* Lookup that always returns null.
|
||||
*/
|
||||
private static final StrLookup<String> NONE_LOOKUP = new MapStrLookup<>(null);
|
||||
|
||||
/**
|
||||
* Lookup based on system properties.
|
||||
*/
|
||||
private static final StrLookup<String> SYSTEM_PROPERTIES_LOOKUP = new SystemPropertiesStrLookup();
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Returns a lookup which always returns null.
|
||||
*
|
||||
* @return a lookup that always returns null, not null
|
||||
*/
|
||||
public static StrLookup<?> noneLookup() {
|
||||
return NONE_LOOKUP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new lookup which uses a copy of the current
|
||||
* {@link System#getProperties() System properties}.
|
||||
* <p>
|
||||
* If a security manager blocked access to system properties, then null will be
|
||||
* returned from every lookup.
|
||||
* <p>
|
||||
* If a null key is used, this lookup will throw a NullPointerException.
|
||||
*
|
||||
* @return a lookup using system properties, not null
|
||||
*/
|
||||
public static StrLookup<String> systemPropertiesLookup() {
|
||||
return SYSTEM_PROPERTIES_LOOKUP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a lookup which looks up values using a map.
|
||||
* <p>
|
||||
* If the map is null, then null will be returned from every lookup. The map
|
||||
* result object is converted to a string using toString().
|
||||
*
|
||||
* @param <V> the type of the values supported by the lookup
|
||||
* @param map the map of keys to values, may be null
|
||||
* @return a lookup using the map, not null
|
||||
*/
|
||||
public static <V> StrLookup<V> mapLookup(final Map<String, V> map) {
|
||||
return new MapStrLookup<>(map);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
protected StrLookup() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a String key to a String value.
|
||||
* <p>
|
||||
* The internal implementation may use any mechanism to return the value. The
|
||||
* simplest implementation is to use a Map. However, virtually any
|
||||
* implementation is possible.
|
||||
* <p>
|
||||
* For example, it would be possible to implement a lookup that used the key as
|
||||
* a primary key, and looked up the value on demand from the database Or, a
|
||||
* numeric based implementation could be created that treats the key as an
|
||||
* integer, increments the value and return the result as a string - converting
|
||||
* 1 to 2, 15 to 16 etc.
|
||||
* <p>
|
||||
* The {@link #lookup(String)} method always returns a String, regardless of the
|
||||
* underlying data, by converting it as necessary. For example:
|
||||
*
|
||||
* <pre>
|
||||
* Map<String, Object> map = new HashMap<String, Object>();
|
||||
* map.put("number", Integer.valueOf(2));
|
||||
* assertEquals("2", StrLookup.mapLookup(map).lookup("number"));
|
||||
* </pre>
|
||||
*
|
||||
* @param key the key to be looked up, may be null
|
||||
* @return the matching value, null if no match
|
||||
*/
|
||||
public abstract String lookup(String key);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Lookup implementation that uses a Map.
|
||||
*/
|
||||
static class MapStrLookup<V> extends StrLookup<V> {
|
||||
|
||||
/** Map keys are variable names and value. */
|
||||
private final Map<String, V> map;
|
||||
|
||||
/**
|
||||
* Creates a new instance backed by a Map.
|
||||
*
|
||||
* @param map the map of keys to values, may be null
|
||||
*/
|
||||
MapStrLookup(final Map<String, V> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a String key to a String value using the map.
|
||||
* <p>
|
||||
* If the map is null, then null is returned. The map result object is converted
|
||||
* to a string using toString().
|
||||
*
|
||||
* @param key the key to be looked up, may be null
|
||||
* @return the matching value, null if no match
|
||||
*/
|
||||
@Override
|
||||
public String lookup(final String key) {
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
final Object obj = map.get(key);
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
return obj.toString();
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Lookup implementation based on system properties.
|
||||
*/
|
||||
private static class SystemPropertiesStrLookup extends StrLookup<String> {
|
||||
/**
|
||||
* {@inheritDoc} This implementation directly accesses system properties.
|
||||
*/
|
||||
@Override
|
||||
public String lookup(final String key) {
|
||||
if (!key.isEmpty()) {
|
||||
try {
|
||||
return System.getProperty(key);
|
||||
} catch (final SecurityException scex) {
|
||||
// Squelched. All lookup(String) will return null.
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
439
sources/main/java/org/apache/commons/lang3/text/StrMatcher.java
Normal file
439
sources/main/java/org/apache/commons/lang3/text/StrMatcher.java
Normal file
@ -0,0 +1,439 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.lang3.text;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.commons.lang3.ArraySorter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* A matcher class that can be queried to determine if a character array portion
|
||||
* matches.
|
||||
* <p>
|
||||
* This class comes complete with various factory methods. If these do not
|
||||
* suffice, you can subclass and implement your own matcher.
|
||||
*
|
||||
* @since 2.2
|
||||
* @deprecated as of 3.6, use commons-text <a href=
|
||||
* "https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/matcher/StringMatcherFactory.html">
|
||||
* StringMatcherFactory</a> instead
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class StrMatcher {
|
||||
|
||||
/**
|
||||
* Matches the comma character.
|
||||
*/
|
||||
private static final StrMatcher COMMA_MATCHER = new CharMatcher(',');
|
||||
/**
|
||||
* Matches the tab character.
|
||||
*/
|
||||
private static final StrMatcher TAB_MATCHER = new CharMatcher('\t');
|
||||
/**
|
||||
* Matches the space character.
|
||||
*/
|
||||
private static final StrMatcher SPACE_MATCHER = new CharMatcher(' ');
|
||||
/**
|
||||
* Matches the same characters as StringTokenizer, namely space, tab, newline,
|
||||
* formfeed.
|
||||
*/
|
||||
private static final StrMatcher SPLIT_MATCHER = new CharSetMatcher(" \t\n\r\f".toCharArray());
|
||||
/**
|
||||
* Matches the String trim() whitespace characters.
|
||||
*/
|
||||
private static final StrMatcher TRIM_MATCHER = new TrimMatcher();
|
||||
/**
|
||||
* Matches the double quote character.
|
||||
*/
|
||||
private static final StrMatcher SINGLE_QUOTE_MATCHER = new CharMatcher('\'');
|
||||
/**
|
||||
* Matches the double quote character.
|
||||
*/
|
||||
private static final StrMatcher DOUBLE_QUOTE_MATCHER = new CharMatcher('"');
|
||||
/**
|
||||
* Matches the single or double quote character.
|
||||
*/
|
||||
private static final StrMatcher QUOTE_MATCHER = new CharSetMatcher("'\"".toCharArray());
|
||||
/**
|
||||
* Matches no characters.
|
||||
*/
|
||||
private static final StrMatcher NONE_MATCHER = new NoMatcher();
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns a matcher which matches the comma character.
|
||||
*
|
||||
* @return a matcher for a comma
|
||||
*/
|
||||
public static StrMatcher commaMatcher() {
|
||||
return COMMA_MATCHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a matcher which matches the tab character.
|
||||
*
|
||||
* @return a matcher for a tab
|
||||
*/
|
||||
public static StrMatcher tabMatcher() {
|
||||
return TAB_MATCHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a matcher which matches the space character.
|
||||
*
|
||||
* @return a matcher for a space
|
||||
*/
|
||||
public static StrMatcher spaceMatcher() {
|
||||
return SPACE_MATCHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the same characters as StringTokenizer, namely space, tab, newline
|
||||
* and formfeed.
|
||||
*
|
||||
* @return the split matcher
|
||||
*/
|
||||
public static StrMatcher splitMatcher() {
|
||||
return SPLIT_MATCHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the String trim() whitespace characters.
|
||||
*
|
||||
* @return the trim matcher
|
||||
*/
|
||||
public static StrMatcher trimMatcher() {
|
||||
return TRIM_MATCHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a matcher which matches the single quote character.
|
||||
*
|
||||
* @return a matcher for a single quote
|
||||
*/
|
||||
public static StrMatcher singleQuoteMatcher() {
|
||||
return SINGLE_QUOTE_MATCHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a matcher which matches the double quote character.
|
||||
*
|
||||
* @return a matcher for a double quote
|
||||
*/
|
||||
public static StrMatcher doubleQuoteMatcher() {
|
||||
return DOUBLE_QUOTE_MATCHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a matcher which matches the single or double quote character.
|
||||
*
|
||||
* @return a matcher for a single or double quote
|
||||
*/
|
||||
public static StrMatcher quoteMatcher() {
|
||||
return QUOTE_MATCHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches no characters.
|
||||
*
|
||||
* @return a matcher that matches nothing
|
||||
*/
|
||||
public static StrMatcher noneMatcher() {
|
||||
return NONE_MATCHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that creates a matcher from a character.
|
||||
*
|
||||
* @param ch the character to match, must not be null
|
||||
* @return a new Matcher for the given char
|
||||
*/
|
||||
public static StrMatcher charMatcher(final char ch) {
|
||||
return new CharMatcher(ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that creates a matcher from a set of characters.
|
||||
*
|
||||
* @param chars the characters to match, null or empty matches nothing
|
||||
* @return a new matcher for the given char[]
|
||||
*/
|
||||
public static StrMatcher charSetMatcher(final char... chars) {
|
||||
if (chars == null || chars.length == 0) {
|
||||
return NONE_MATCHER;
|
||||
}
|
||||
if (chars.length == 1) {
|
||||
return new CharMatcher(chars[0]);
|
||||
}
|
||||
return new CharSetMatcher(chars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that creates a matcher from a string representing a set of
|
||||
* characters.
|
||||
*
|
||||
* @param chars the characters to match, null or empty matches nothing
|
||||
* @return a new Matcher for the given characters
|
||||
*/
|
||||
public static StrMatcher charSetMatcher(final String chars) {
|
||||
if (StringUtils.isEmpty(chars)) {
|
||||
return NONE_MATCHER;
|
||||
}
|
||||
if (chars.length() == 1) {
|
||||
return new CharMatcher(chars.charAt(0));
|
||||
}
|
||||
return new CharSetMatcher(chars.toCharArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that creates a matcher from a string.
|
||||
*
|
||||
* @param str the string to match, null or empty matches nothing
|
||||
* @return a new Matcher for the given String
|
||||
*/
|
||||
public static StrMatcher stringMatcher(final String str) {
|
||||
if (StringUtils.isEmpty(str)) {
|
||||
return NONE_MATCHER;
|
||||
}
|
||||
return new StringMatcher(str);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
protected StrMatcher() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of matching characters, zero for no match.
|
||||
* <p>
|
||||
* This method is called to check for a match. The parameter {@code pos}
|
||||
* represents the current position to be checked in the string {@code buffer} (a
|
||||
* character array which must not be changed). The API guarantees that
|
||||
* {@code pos} is a valid index for {@code buffer}.
|
||||
* <p>
|
||||
* The character array may be larger than the active area to be matched. Only
|
||||
* values in the buffer between the specified indices may be accessed.
|
||||
* <p>
|
||||
* The matching code may check one character or many. It may check characters
|
||||
* preceding {@code pos} as well as those after, so long as no checks exceed the
|
||||
* bounds specified.
|
||||
* <p>
|
||||
* It must return zero for no match, or a positive number if a match was found.
|
||||
* The number indicates the number of characters that matched.
|
||||
*
|
||||
* @param buffer the text content to match against, do not change
|
||||
* @param pos the starting position for the match, valid for buffer
|
||||
* @param bufferStart the first active index in the buffer, valid for buffer
|
||||
* @param bufferEnd the end index (exclusive) of the active buffer, valid for
|
||||
* buffer
|
||||
* @return the number of matching characters, zero for no match
|
||||
*/
|
||||
public abstract int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd);
|
||||
|
||||
/**
|
||||
* Returns the number of matching characters, zero for no match.
|
||||
* <p>
|
||||
* This method is called to check for a match. The parameter {@code pos}
|
||||
* represents the current position to be checked in the string {@code buffer} (a
|
||||
* character array which must not be changed). The API guarantees that
|
||||
* {@code pos} is a valid index for {@code buffer}.
|
||||
* <p>
|
||||
* The matching code may check one character or many. It may check characters
|
||||
* preceding {@code pos} as well as those after.
|
||||
* <p>
|
||||
* It must return zero for no match, or a positive number if a match was found.
|
||||
* The number indicates the number of characters that matched.
|
||||
*
|
||||
* @param buffer the text content to match against, do not change
|
||||
* @param pos the starting position for the match, valid for buffer
|
||||
* @return the number of matching characters, zero for no match
|
||||
* @since 2.4
|
||||
*/
|
||||
public int isMatch(final char[] buffer, final int pos) {
|
||||
return isMatch(buffer, pos, 0, buffer.length);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Class used to define a set of characters for matching purposes.
|
||||
*/
|
||||
static final class CharSetMatcher extends StrMatcher {
|
||||
/** The set of characters to match. */
|
||||
private final char[] chars;
|
||||
|
||||
/**
|
||||
* Constructor that creates a matcher from a character array.
|
||||
*
|
||||
* @param chars the characters to match, must not be null
|
||||
*/
|
||||
CharSetMatcher(final char[] chars) {
|
||||
this.chars = ArraySorter.sort(chars.clone());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the given character matches.
|
||||
*
|
||||
* @param buffer the text content to match against, do not change
|
||||
* @param pos the starting position for the match, valid for buffer
|
||||
* @param bufferStart the first active index in the buffer, valid for buffer
|
||||
* @param bufferEnd the end index of the active buffer, valid for buffer
|
||||
* @return the number of matching characters, zero for no match
|
||||
*/
|
||||
@Override
|
||||
public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) {
|
||||
return Arrays.binarySearch(chars, buffer[pos]) >= 0 ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Class used to define a character for matching purposes.
|
||||
*/
|
||||
static final class CharMatcher extends StrMatcher {
|
||||
/** The character to match. */
|
||||
private final char ch;
|
||||
|
||||
/**
|
||||
* Constructor that creates a matcher that matches a single character.
|
||||
*
|
||||
* @param ch the character to match
|
||||
*/
|
||||
CharMatcher(final char ch) {
|
||||
this.ch = ch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the given character matches.
|
||||
*
|
||||
* @param buffer the text content to match against, do not change
|
||||
* @param pos the starting position for the match, valid for buffer
|
||||
* @param bufferStart the first active index in the buffer, valid for buffer
|
||||
* @param bufferEnd the end index of the active buffer, valid for buffer
|
||||
* @return the number of matching characters, zero for no match
|
||||
*/
|
||||
@Override
|
||||
public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) {
|
||||
return ch == buffer[pos] ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Class used to define a set of characters for matching purposes.
|
||||
*/
|
||||
static final class StringMatcher extends StrMatcher {
|
||||
/** The string to match, as a character array. */
|
||||
private final char[] chars;
|
||||
|
||||
/**
|
||||
* Constructor that creates a matcher from a String.
|
||||
*
|
||||
* @param str the string to match, must not be null
|
||||
*/
|
||||
StringMatcher(final String str) {
|
||||
chars = str.toCharArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the given text matches the stored string.
|
||||
*
|
||||
* @param buffer the text content to match against, do not change
|
||||
* @param pos the starting position for the match, valid for buffer
|
||||
* @param bufferStart the first active index in the buffer, valid for buffer
|
||||
* @param bufferEnd the end index of the active buffer, valid for buffer
|
||||
* @return the number of matching characters, zero for no match
|
||||
*/
|
||||
@Override
|
||||
public int isMatch(final char[] buffer, int pos, final int bufferStart, final int bufferEnd) {
|
||||
final int len = chars.length;
|
||||
if (pos + len > bufferEnd) {
|
||||
return 0;
|
||||
}
|
||||
for (int i = 0; i < chars.length; i++, pos++) {
|
||||
if (chars[i] != buffer[pos]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + ' ' + Arrays.toString(chars);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Class used to match no characters.
|
||||
*/
|
||||
static final class NoMatcher extends StrMatcher {
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@code NoMatcher}.
|
||||
*/
|
||||
NoMatcher() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns {@code false}.
|
||||
*
|
||||
* @param buffer the text content to match against, do not change
|
||||
* @param pos the starting position for the match, valid for buffer
|
||||
* @param bufferStart the first active index in the buffer, valid for buffer
|
||||
* @param bufferEnd the end index of the active buffer, valid for buffer
|
||||
* @return the number of matching characters, zero for no match
|
||||
*/
|
||||
@Override
|
||||
public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Class used to match whitespace as per trim().
|
||||
*/
|
||||
static final class TrimMatcher extends StrMatcher {
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@code TrimMatcher}.
|
||||
*/
|
||||
TrimMatcher() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the given character matches.
|
||||
*
|
||||
* @param buffer the text content to match against, do not change
|
||||
* @param pos the starting position for the match, valid for buffer
|
||||
* @param bufferStart the first active index in the buffer, valid for buffer
|
||||
* @param bufferEnd the end index of the active buffer, valid for buffer
|
||||
* @return the number of matching characters, zero for no match
|
||||
*/
|
||||
@Override
|
||||
public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) {
|
||||
return buffer[pos] <= 32 ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
1262
sources/main/java/org/apache/commons/lang3/text/StrSubstitutor.java
Normal file
1262
sources/main/java/org/apache/commons/lang3/text/StrSubstitutor.java
Normal file
File diff suppressed because it is too large
Load Diff
1126
sources/main/java/org/apache/commons/lang3/text/StrTokenizer.java
Normal file
1126
sources/main/java/org/apache/commons/lang3/text/StrTokenizer.java
Normal file
File diff suppressed because it is too large
Load Diff
833
sources/main/java/org/apache/commons/lang3/text/WordUtils.java
Normal file
833
sources/main/java/org/apache/commons/lang3/text/WordUtils.java
Normal file
@ -0,0 +1,833 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.lang3.text;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Operations on Strings that contain words.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This class tries to handle {@code null} input gracefully. An exception will
|
||||
* not be thrown for a {@code null} input. Each method documents its behavior in
|
||||
* more detail.
|
||||
* </p>
|
||||
*
|
||||
* @since 2.0
|
||||
* @deprecated as of 3.6, use commons-text <a href=
|
||||
* "https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/WordUtils.html">
|
||||
* WordUtils</a> instead
|
||||
*/
|
||||
@Deprecated
|
||||
public class WordUtils {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* {@code WordUtils} instances should NOT be constructed in standard
|
||||
* programming. Instead, the class should be used as
|
||||
* {@code WordUtils.wrap("foo bar", 20);}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This constructor is public to permit tools that require a JavaBean instance
|
||||
* to operate.
|
||||
* </p>
|
||||
*/
|
||||
public WordUtils() {
|
||||
}
|
||||
|
||||
// Wrapping
|
||||
// --------------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* Wraps a single line of text, identifying words by {@code ' '}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* New lines will be separated by the system property line separator. Very long
|
||||
* words, such as URLs will <i>not</i> be wrapped.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Leading spaces on a new line are stripped. Trailing spaces are not stripped.
|
||||
* </p>
|
||||
*
|
||||
* <table border="1">
|
||||
* <caption>Examples</caption>
|
||||
* <tr>
|
||||
* <th>input</th>
|
||||
* <th>wrapLength</th>
|
||||
* <th>result</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>null</td>
|
||||
* <td>*</td>
|
||||
* <td>null</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>""</td>
|
||||
* <td>*</td>
|
||||
* <td>""</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>"Here is one line of text that is going to be wrapped after 20
|
||||
* columns."</td>
|
||||
* <td>20</td>
|
||||
* <td>"Here is one line of\ntext that is going\nto be wrapped after\n20
|
||||
* columns."</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>"Click here to jump to the commons website -
|
||||
* https://commons.apache.org"</td>
|
||||
* <td>20</td>
|
||||
* <td>"Click here to jump\nto the commons\nwebsite
|
||||
* -\nhttps://commons.apache.org"</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>"Click here, https://commons.apache.org, to jump to the commons
|
||||
* website"</td>
|
||||
* <td>20</td>
|
||||
* <td>"Click here,\nhttps://commons.apache.org,\nto jump to the\ncommons
|
||||
* website"</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* (assuming that '\n' is the systems line separator)
|
||||
*
|
||||
* @param str the String to be word wrapped, may be null
|
||||
* @param wrapLength the column to wrap the words at, less than 1 is treated as
|
||||
* 1
|
||||
* @return a line with newlines inserted, {@code null} if null input
|
||||
*/
|
||||
public static String wrap(final String str, final int wrapLength) {
|
||||
return wrap(str, wrapLength, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Wraps a single line of text, identifying words by {@code ' '}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Leading spaces on a new line are stripped. Trailing spaces are not stripped.
|
||||
* </p>
|
||||
*
|
||||
* <table border="1">
|
||||
* <caption>Examples</caption>
|
||||
* <tr>
|
||||
* <th>input</th>
|
||||
* <th>wrapLength</th>
|
||||
* <th>newLineString</th>
|
||||
* <th>wrapLongWords</th>
|
||||
* <th>result</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>null</td>
|
||||
* <td>*</td>
|
||||
* <td>*</td>
|
||||
* <td>true/false</td>
|
||||
* <td>null</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>""</td>
|
||||
* <td>*</td>
|
||||
* <td>*</td>
|
||||
* <td>true/false</td>
|
||||
* <td>""</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>"Here is one line of text that is going to be wrapped after 20
|
||||
* columns."</td>
|
||||
* <td>20</td>
|
||||
* <td>"\n"</td>
|
||||
* <td>true/false</td>
|
||||
* <td>"Here is one line of\ntext that is going\nto be wrapped after\n20
|
||||
* columns."</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>"Here is one line of text that is going to be wrapped after 20
|
||||
* columns."</td>
|
||||
* <td>20</td>
|
||||
* <td>"<br />"</td>
|
||||
* <td>true/false</td>
|
||||
* <td>"Here is one line of<br />text that is going<br />to be
|
||||
* wrapped after<br />20 columns."</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>"Here is one line of text that is going to be wrapped after 20
|
||||
* columns."</td>
|
||||
* <td>20</td>
|
||||
* <td>null</td>
|
||||
* <td>true/false</td>
|
||||
* <td>"Here is one line of" + systemNewLine + "text that is going" +
|
||||
* systemNewLine + "to be wrapped after" + systemNewLine + "20 columns."</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>"Click here to jump to the commons website -
|
||||
* https://commons.apache.org"</td>
|
||||
* <td>20</td>
|
||||
* <td>"\n"</td>
|
||||
* <td>false</td>
|
||||
* <td>"Click here to jump\nto the commons\nwebsite
|
||||
* -\nhttps://commons.apache.org"</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>"Click here to jump to the commons website -
|
||||
* https://commons.apache.org"</td>
|
||||
* <td>20</td>
|
||||
* <td>"\n"</td>
|
||||
* <td>true</td>
|
||||
* <td>"Click here to jump\nto the commons\nwebsite
|
||||
* -\nhttp://commons.apach\ne.org"</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* @param str the String to be word wrapped, may be null
|
||||
* @param wrapLength the column to wrap the words at, less than 1 is treated
|
||||
* as 1
|
||||
* @param newLineStr the string to insert for a new line, {@code null} uses
|
||||
* the system property line separator
|
||||
* @param wrapLongWords true if long words (such as URLs) should be wrapped
|
||||
* @return a line with newlines inserted, {@code null} if null input
|
||||
*/
|
||||
public static String wrap(final String str, final int wrapLength, final String newLineStr,
|
||||
final boolean wrapLongWords) {
|
||||
return wrap(str, wrapLength, newLineStr, wrapLongWords, " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Wraps a single line of text, identifying words by {@code wrapOn}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Leading spaces on a new line are stripped. Trailing spaces are not stripped.
|
||||
* </p>
|
||||
*
|
||||
* <table border="1">
|
||||
* <caption>Examples</caption>
|
||||
* <tr>
|
||||
* <th>input</th>
|
||||
* <th>wrapLength</th>
|
||||
* <th>newLineString</th>
|
||||
* <th>wrapLongWords</th>
|
||||
* <th>wrapOn</th>
|
||||
* <th>result</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>null</td>
|
||||
* <td>*</td>
|
||||
* <td>*</td>
|
||||
* <td>true/false</td>
|
||||
* <td>*</td>
|
||||
* <td>null</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>""</td>
|
||||
* <td>*</td>
|
||||
* <td>*</td>
|
||||
* <td>true/false</td>
|
||||
* <td>*</td>
|
||||
* <td>""</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>"Here is one line of text that is going to be wrapped after 20
|
||||
* columns."</td>
|
||||
* <td>20</td>
|
||||
* <td>"\n"</td>
|
||||
* <td>true/false</td>
|
||||
* <td>" "</td>
|
||||
* <td>"Here is one line of\ntext that is going\nto be wrapped after\n20
|
||||
* columns."</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>"Here is one line of text that is going to be wrapped after 20
|
||||
* columns."</td>
|
||||
* <td>20</td>
|
||||
* <td>"<br />"</td>
|
||||
* <td>true/false</td>
|
||||
* <td>" "</td>
|
||||
* <td>"Here is one line of<br />text that is going<br />to be
|
||||
* wrapped after<br />20 columns."</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>"Here is one line of text that is going to be wrapped after 20
|
||||
* columns."</td>
|
||||
* <td>20</td>
|
||||
* <td>null</td>
|
||||
* <td>true/false</td>
|
||||
* <td>" "</td>
|
||||
* <td>"Here is one line of" + systemNewLine + "text that is going" +
|
||||
* systemNewLine + "to be wrapped after" + systemNewLine + "20 columns."</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>"Click here to jump to the commons website -
|
||||
* https://commons.apache.org"</td>
|
||||
* <td>20</td>
|
||||
* <td>"\n"</td>
|
||||
* <td>false</td>
|
||||
* <td>" "</td>
|
||||
* <td>"Click here to jump\nto the commons\nwebsite
|
||||
* -\nhttps://commons.apache.org"</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>"Click here to jump to the commons website -
|
||||
* https://commons.apache.org"</td>
|
||||
* <td>20</td>
|
||||
* <td>"\n"</td>
|
||||
* <td>true</td>
|
||||
* <td>" "</td>
|
||||
* <td>"Click here to jump\nto the commons\nwebsite
|
||||
* -\nhttp://commons.apach\ne.org"</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>"flammable/inflammable"</td>
|
||||
* <td>20</td>
|
||||
* <td>"\n"</td>
|
||||
* <td>true</td>
|
||||
* <td>"/"</td>
|
||||
* <td>"flammable\ninflammable"</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* @param str the String to be word wrapped, may be null
|
||||
* @param wrapLength the column to wrap the words at, less than 1 is treated
|
||||
* as 1
|
||||
* @param newLineStr the string to insert for a new line, {@code null} uses
|
||||
* the system property line separator
|
||||
* @param wrapLongWords true if long words (such as URLs) should be wrapped
|
||||
* @param wrapOn regex expression to be used as a breakable characters,
|
||||
* if blank string is provided a space character will be
|
||||
* used
|
||||
* @return a line with newlines inserted, {@code null} if null input
|
||||
*/
|
||||
public static String wrap(final String str, int wrapLength, String newLineStr, final boolean wrapLongWords,
|
||||
String wrapOn) {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
if (newLineStr == null) {
|
||||
newLineStr = System.lineSeparator();
|
||||
}
|
||||
if (wrapLength < 1) {
|
||||
wrapLength = 1;
|
||||
}
|
||||
if (StringUtils.isBlank(wrapOn)) {
|
||||
wrapOn = " ";
|
||||
}
|
||||
final Pattern patternToWrapOn = Pattern.compile(wrapOn);
|
||||
final int inputLineLength = str.length();
|
||||
int offset = 0;
|
||||
final StringBuilder wrappedLine = new StringBuilder(inputLineLength + 32);
|
||||
|
||||
while (offset < inputLineLength) {
|
||||
int spaceToWrapAt = -1;
|
||||
Matcher matcher = patternToWrapOn.matcher(str.substring(offset,
|
||||
Math.min((int) Math.min(Integer.MAX_VALUE, offset + wrapLength + 1L), inputLineLength)));
|
||||
if (matcher.find()) {
|
||||
if (matcher.start() == 0) {
|
||||
offset += matcher.end();
|
||||
continue;
|
||||
}
|
||||
spaceToWrapAt = matcher.start() + offset;
|
||||
}
|
||||
|
||||
// only last line without leading spaces is left
|
||||
if (inputLineLength - offset <= wrapLength) {
|
||||
break;
|
||||
}
|
||||
|
||||
while (matcher.find()) {
|
||||
spaceToWrapAt = matcher.start() + offset;
|
||||
}
|
||||
|
||||
if (spaceToWrapAt >= offset) {
|
||||
// normal case
|
||||
wrappedLine.append(str, offset, spaceToWrapAt);
|
||||
wrappedLine.append(newLineStr);
|
||||
offset = spaceToWrapAt + 1;
|
||||
|
||||
} else // really long word or URL
|
||||
if (wrapLongWords) {
|
||||
// wrap really long word one line at a time
|
||||
wrappedLine.append(str, offset, wrapLength + offset);
|
||||
wrappedLine.append(newLineStr);
|
||||
offset += wrapLength;
|
||||
} else {
|
||||
// do not wrap really long word, just extend beyond limit
|
||||
matcher = patternToWrapOn.matcher(str.substring(offset + wrapLength));
|
||||
if (matcher.find()) {
|
||||
spaceToWrapAt = matcher.start() + offset + wrapLength;
|
||||
}
|
||||
|
||||
if (spaceToWrapAt >= 0) {
|
||||
wrappedLine.append(str, offset, spaceToWrapAt);
|
||||
wrappedLine.append(newLineStr);
|
||||
offset = spaceToWrapAt + 1;
|
||||
} else {
|
||||
wrappedLine.append(str, offset, str.length());
|
||||
offset = inputLineLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Whatever is left in line is short enough to just pass through
|
||||
wrappedLine.append(str, offset, str.length());
|
||||
|
||||
return wrappedLine.toString();
|
||||
}
|
||||
|
||||
// Capitalizing
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* Capitalizes all the whitespace separated words in a String. Only the first
|
||||
* character of each word is changed. To convert the rest of each word to
|
||||
* lowercase at the same time, use {@link #capitalizeFully(String)}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Whitespace is defined by {@link Character#isWhitespace(char)}. A {@code null}
|
||||
* input String returns {@code null}. Capitalization uses the Unicode title
|
||||
* case, normally equivalent to upper case.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.capitalize(null) = null
|
||||
* WordUtils.capitalize("") = ""
|
||||
* WordUtils.capitalize("i am FINE") = "I Am FINE"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to capitalize, may be null
|
||||
* @return capitalized String, {@code null} if null String input
|
||||
* @see #uncapitalize(String)
|
||||
* @see #capitalizeFully(String)
|
||||
*/
|
||||
public static String capitalize(final String str) {
|
||||
return capitalize(str, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Capitalizes all the delimiter separated words in a String. Only the first
|
||||
* character of each word is changed. To convert the rest of each word to
|
||||
* lowercase at the same time, use {@link #capitalizeFully(String, char[])}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The delimiters represent a set of characters understood to separate words.
|
||||
* The first string character and the first non-delimiter character after a
|
||||
* delimiter will be capitalized.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* A {@code null} input String returns {@code null}. Capitalization uses the
|
||||
* Unicode title case, normally equivalent to upper case.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.capitalize(null, *) = null
|
||||
* WordUtils.capitalize("", *) = ""
|
||||
* WordUtils.capitalize(*, new char[0]) = *
|
||||
* WordUtils.capitalize("i am fine", null) = "I Am Fine"
|
||||
* WordUtils.capitalize("i aM.fine", {'.'}) = "I aM.Fine"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to capitalize, may be null
|
||||
* @param delimiters set of characters to determine capitalization, null means
|
||||
* whitespace
|
||||
* @return capitalized String, {@code null} if null String input
|
||||
* @see #uncapitalize(String)
|
||||
* @see #capitalizeFully(String)
|
||||
* @since 2.1
|
||||
*/
|
||||
public static String capitalize(final String str, final char... delimiters) {
|
||||
final int delimLen = delimiters == null ? -1 : delimiters.length;
|
||||
if (StringUtils.isEmpty(str) || delimLen == 0) {
|
||||
return str;
|
||||
}
|
||||
final char[] buffer = str.toCharArray();
|
||||
boolean capitalizeNext = true;
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
final char ch = buffer[i];
|
||||
if (isDelimiter(ch, delimiters)) {
|
||||
capitalizeNext = true;
|
||||
} else if (capitalizeNext) {
|
||||
buffer[i] = Character.toTitleCase(ch);
|
||||
capitalizeNext = false;
|
||||
}
|
||||
}
|
||||
return new String(buffer);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* Converts all the whitespace separated words in a String into capitalized
|
||||
* words, that is each word is made up of a titlecase character and then a
|
||||
* series of lowercase characters.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Whitespace is defined by {@link Character#isWhitespace(char)}. A {@code null}
|
||||
* input String returns {@code null}. Capitalization uses the Unicode title
|
||||
* case, normally equivalent to upper case.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.capitalizeFully(null) = null
|
||||
* WordUtils.capitalizeFully("") = ""
|
||||
* WordUtils.capitalizeFully("i am FINE") = "I Am Fine"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to capitalize, may be null
|
||||
* @return capitalized String, {@code null} if null String input
|
||||
*/
|
||||
public static String capitalizeFully(final String str) {
|
||||
return capitalizeFully(str, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Converts all the delimiter separated words in a String into capitalized
|
||||
* words, that is each word is made up of a titlecase character and then a
|
||||
* series of lowercase characters.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The delimiters represent a set of characters understood to separate words.
|
||||
* The first string character and the first non-delimiter character after a
|
||||
* delimiter will be capitalized.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* A {@code null} input String returns {@code null}. Capitalization uses the
|
||||
* Unicode title case, normally equivalent to upper case.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.capitalizeFully(null, *) = null
|
||||
* WordUtils.capitalizeFully("", *) = ""
|
||||
* WordUtils.capitalizeFully(*, null) = *
|
||||
* WordUtils.capitalizeFully(*, new char[0]) = *
|
||||
* WordUtils.capitalizeFully("i aM.fine", {'.'}) = "I am.Fine"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to capitalize, may be null
|
||||
* @param delimiters set of characters to determine capitalization, null means
|
||||
* whitespace
|
||||
* @return capitalized String, {@code null} if null String input
|
||||
* @since 2.1
|
||||
*/
|
||||
public static String capitalizeFully(String str, final char... delimiters) {
|
||||
final int delimLen = delimiters == null ? -1 : delimiters.length;
|
||||
if (StringUtils.isEmpty(str) || delimLen == 0) {
|
||||
return str;
|
||||
}
|
||||
str = str.toLowerCase();
|
||||
return capitalize(str, delimiters);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* Uncapitalizes all the whitespace separated words in a String. Only the first
|
||||
* character of each word is changed.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Whitespace is defined by {@link Character#isWhitespace(char)}. A {@code null}
|
||||
* input String returns {@code null}.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.uncapitalize(null) = null
|
||||
* WordUtils.uncapitalize("") = ""
|
||||
* WordUtils.uncapitalize("I Am FINE") = "i am fINE"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to uncapitalize, may be null
|
||||
* @return uncapitalized String, {@code null} if null String input
|
||||
* @see #capitalize(String)
|
||||
*/
|
||||
public static String uncapitalize(final String str) {
|
||||
return uncapitalize(str, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Uncapitalizes all the whitespace separated words in a String. Only the first
|
||||
* character of each word is changed.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The delimiters represent a set of characters understood to separate words.
|
||||
* The first string character and the first non-delimiter character after a
|
||||
* delimiter will be uncapitalized.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Whitespace is defined by {@link Character#isWhitespace(char)}. A {@code null}
|
||||
* input String returns {@code null}.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.uncapitalize(null, *) = null
|
||||
* WordUtils.uncapitalize("", *) = ""
|
||||
* WordUtils.uncapitalize(*, null) = *
|
||||
* WordUtils.uncapitalize(*, new char[0]) = *
|
||||
* WordUtils.uncapitalize("I AM.FINE", {'.'}) = "i AM.fINE"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to uncapitalize, may be null
|
||||
* @param delimiters set of characters to determine uncapitalization, null means
|
||||
* whitespace
|
||||
* @return uncapitalized String, {@code null} if null String input
|
||||
* @see #capitalize(String)
|
||||
* @since 2.1
|
||||
*/
|
||||
public static String uncapitalize(final String str, final char... delimiters) {
|
||||
final int delimLen = delimiters == null ? -1 : delimiters.length;
|
||||
if (StringUtils.isEmpty(str) || delimLen == 0) {
|
||||
return str;
|
||||
}
|
||||
final char[] buffer = str.toCharArray();
|
||||
boolean uncapitalizeNext = true;
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
final char ch = buffer[i];
|
||||
if (isDelimiter(ch, delimiters)) {
|
||||
uncapitalizeNext = true;
|
||||
} else if (uncapitalizeNext) {
|
||||
buffer[i] = Character.toLowerCase(ch);
|
||||
uncapitalizeNext = false;
|
||||
}
|
||||
}
|
||||
return new String(buffer);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* Swaps the case of a String using a word based algorithm.
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>Upper case character converts to Lower case</li>
|
||||
* <li>Title case character converts to Lower case</li>
|
||||
* <li>Lower case character after Whitespace or at start converts to Title
|
||||
* case</li>
|
||||
* <li>Other Lower case character converts to Upper case</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Whitespace is defined by {@link Character#isWhitespace(char)}. A {@code null}
|
||||
* input String returns {@code null}.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtils.swapCase(null) = null
|
||||
* StringUtils.swapCase("") = ""
|
||||
* StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to swap case, may be null
|
||||
* @return the changed String, {@code null} if null String input
|
||||
*/
|
||||
public static String swapCase(final String str) {
|
||||
if (StringUtils.isEmpty(str)) {
|
||||
return str;
|
||||
}
|
||||
final char[] buffer = str.toCharArray();
|
||||
|
||||
boolean whitespace = true;
|
||||
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
final char ch = buffer[i];
|
||||
if (Character.isUpperCase(ch) || Character.isTitleCase(ch)) {
|
||||
buffer[i] = Character.toLowerCase(ch);
|
||||
whitespace = false;
|
||||
} else if (Character.isLowerCase(ch)) {
|
||||
if (whitespace) {
|
||||
buffer[i] = Character.toTitleCase(ch);
|
||||
whitespace = false;
|
||||
} else {
|
||||
buffer[i] = Character.toUpperCase(ch);
|
||||
}
|
||||
} else {
|
||||
whitespace = Character.isWhitespace(ch);
|
||||
}
|
||||
}
|
||||
return new String(buffer);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* Extracts the initial characters from each word in the String.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* All first characters after whitespace are returned as a new string. Their
|
||||
* case is not changed.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Whitespace is defined by {@link Character#isWhitespace(char)}. A {@code null}
|
||||
* input String returns {@code null}.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.initials(null) = null
|
||||
* WordUtils.initials("") = ""
|
||||
* WordUtils.initials("Ben John Lee") = "BJL"
|
||||
* WordUtils.initials("Ben J.Lee") = "BJ"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to get initials from, may be null
|
||||
* @return String of initial letters, {@code null} if null String input
|
||||
* @see #initials(String,char[])
|
||||
* @since 2.2
|
||||
*/
|
||||
public static String initials(final String str) {
|
||||
return initials(str, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Extracts the initial characters from each word in the String.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* All first characters after the defined delimiters are returned as a new
|
||||
* string. Their case is not changed.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If the delimiters array is null, then Whitespace is used. Whitespace is
|
||||
* defined by {@link Character#isWhitespace(char)}. A {@code null} input String
|
||||
* returns {@code null}. An empty delimiter array returns an empty String.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.initials(null, *) = null
|
||||
* WordUtils.initials("", *) = ""
|
||||
* WordUtils.initials("Ben John Lee", null) = "BJL"
|
||||
* WordUtils.initials("Ben J.Lee", null) = "BJ"
|
||||
* WordUtils.initials("Ben J.Lee", [' ','.']) = "BJL"
|
||||
* WordUtils.initials(*, new char[0]) = ""
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to get initials from, may be null
|
||||
* @param delimiters set of characters to determine words, null means whitespace
|
||||
* @return String of initial characters, {@code null} if null String input
|
||||
* @see #initials(String)
|
||||
* @since 2.2
|
||||
*/
|
||||
public static String initials(final String str, final char... delimiters) {
|
||||
if (StringUtils.isEmpty(str)) {
|
||||
return str;
|
||||
}
|
||||
if (delimiters != null && delimiters.length == 0) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
final int strLen = str.length();
|
||||
final char[] buf = new char[strLen / 2 + 1];
|
||||
int count = 0;
|
||||
boolean lastWasGap = true;
|
||||
for (int i = 0; i < strLen; i++) {
|
||||
final char ch = str.charAt(i);
|
||||
|
||||
if (isDelimiter(ch, delimiters)) {
|
||||
lastWasGap = true;
|
||||
} else if (lastWasGap) {
|
||||
buf[count++] = ch;
|
||||
lastWasGap = false;
|
||||
} else {
|
||||
continue; // ignore ch
|
||||
}
|
||||
}
|
||||
return new String(buf, 0, count);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* Checks if the String contains all words in the given array.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* A {@code null} String will return {@code false}. A {@code null}, zero length
|
||||
* search array or if one element of array is null will return {@code false}.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* WordUtils.containsAllWords(null, *) = false
|
||||
* WordUtils.containsAllWords("", *) = false
|
||||
* WordUtils.containsAllWords(*, null) = false
|
||||
* WordUtils.containsAllWords(*, []) = false
|
||||
* WordUtils.containsAllWords("abcd", "ab", "cd") = false
|
||||
* WordUtils.containsAllWords("abc def", "def", "abc") = true
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @param word The CharSequence to check, may be null
|
||||
* @param words The array of String words to search for, may be null
|
||||
* @return {@code true} if all search words are found, {@code false} otherwise
|
||||
* @since 3.5
|
||||
*/
|
||||
public static boolean containsAllWords(final CharSequence word, final CharSequence... words) {
|
||||
if (StringUtils.isEmpty(word) || words.length == 0) {
|
||||
return false;
|
||||
}
|
||||
for (final CharSequence w : words) {
|
||||
if (StringUtils.isBlank(w)) {
|
||||
return false;
|
||||
}
|
||||
final Pattern p = Pattern.compile(".*\\b" + w + "\\b.*");
|
||||
if (!p.matcher(word).matches()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Is the character a delimiter.
|
||||
*
|
||||
* @param ch the character to check
|
||||
* @param delimiters the delimiters
|
||||
* @return true if it is a delimiter
|
||||
*/
|
||||
private static boolean isDelimiter(final char ch, final char[] delimiters) {
|
||||
if (delimiters == null) {
|
||||
return Character.isWhitespace(ch);
|
||||
}
|
||||
for (final char delimiter : delimiters) {
|
||||
if (ch == delimiter) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* <p>
|
||||
* Provides classes for handling and manipulating text, partly as an extension
|
||||
* to {@link java.text}. The classes in this package are, for the most part,
|
||||
* intended to be instantiated (i.e. they are not utility classes with lots of
|
||||
* static methods).
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Amongst other classes, the text package provides a replacement for
|
||||
* {@link java.lang.StringBuffer} named
|
||||
* {@link org.apache.commons.lang3.text.StrBuilder}, a class for substituting
|
||||
* variables within a String named
|
||||
* {@link org.apache.commons.lang3.text.StrSubstitutor} and a replacement for
|
||||
* {@link java.util.StringTokenizer} named
|
||||
* {@link org.apache.commons.lang3.text.StrTokenizer}. While somewhat ungainly,
|
||||
* the {@code Str} prefix has been used to ensure we don't clash with any
|
||||
* current or future standard Java classes.
|
||||
* </p>
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
package org.apache.commons.lang3.text;
|
Reference in New Issue
Block a user