org.gatein.common.text.TextTools Maven / Gradle / Ivy
The newest version!
/*
* JBoss, a division of Red Hat
* Copyright 2010, Red Hat Middleware, LLC, and individual
* contributors as indicated by the @authors tag. See the
* copyright.txt in the distribution for a full listing of
* individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.gatein.common.text;
import org.gatein.common.util.ParameterValidation;
/**
* @author Julien Viet
* @version $Revision: 1.1 $
*/
public class TextTools
{
/**
* Returns true if the char c is alpha numeric i.e it belongs to one of the following ranges [0,9], [A,Z] or [a,z]
*
* @param c the char to test
* @return true if c is alpha numeric
*/
public static boolean isAlphaNumeric(char c)
{
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}
/**
* Returns the hexadecimal value of the provided numeric value.
*
* @param z the numeric value to convert
* @return the hexadecimal char
* @throws IllegalArgumentException if the value is not between 0 and 15
*/
public static char toHex(int z) throws IllegalArgumentException
{
if (z >= 0 && z < 10)
{
return (char)('0' + z);
}
else if (z >= 10 && z < 16)
{
return (char)('A' - 10 + z);
}
else
{
throw new IllegalArgumentException("Wrong character");
}
}
/**
* Replace occurence in a string.
*
* @param string the source string
* @param pattern the replaced pattern
* @param replacement the replacement text
* @return the new string
*/
public static String replace(String string, String pattern, String replacement)
{
StringBuffer buffer = new StringBuffer(string.length());
int previous = 0;
int current = string.indexOf(pattern);
while (current != -1)
{
buffer.append(string.substring(previous, current));
buffer.append(replacement);
previous = current + pattern.length();
current = string.indexOf(pattern, previous);
}
buffer.append(string.substring(previous));
return buffer.toString();
}
/**
* Same as replaceBoundedString(initial, prefix, suffix, replacement, true, false).
*
* @param initial
* @param prefix
* @param suffix
* @param replacement
* @return
*/
public static String replaceAllInstancesOfBoundedString(String initial, String prefix, String suffix, String replacement)
{
return replaceBoundedString(initial, prefix, suffix, replacement, true, false, false);
}
public static String replaceAllInstancesOfBoundedString(String initial, String prefix, String suffix, StringReplacementGenerator generator)
{
return replaceBoundedString(initial, prefix, suffix, generator, true, false, false);
}
public static String replaceBoundedString(String initial, String prefix, String suffix, String replacement,
boolean replaceIfBoundedStringEmpty, boolean keepBoundaries)
{
ParameterValidation.throwIllegalArgExceptionIfNull(replacement, "replacement");
return replaceBoundedString(initial, prefix, suffix, new ConstantStringReplacementGenerator(replacement),
replaceIfBoundedStringEmpty, keepBoundaries, false);
}
public static String replaceBoundedString(String initial, String prefix, String suffix, String replacement,
boolean replaceIfBoundedStringEmpty, boolean keepBoundaries, boolean suffixIsOptional)
{
ParameterValidation.throwIllegalArgExceptionIfNull(replacement, "replacement");
return replaceBoundedString(initial, prefix, suffix, new ConstantStringReplacementGenerator(replacement),
replaceIfBoundedStringEmpty, keepBoundaries, suffixIsOptional);
}
public static String replaceBoundedString(String initial, String prefix, String suffix, StringReplacementGenerator generator,
boolean replaceIfBoundedStringEmpty, boolean keepBoundaries)
{
return replaceBoundedString(initial, prefix, suffix, generator, replaceIfBoundedStringEmpty, keepBoundaries, false);
}
/**
* Replace instances of Strings delimited by the given prefix and suffix (hence, bounded) by a replacement String
* computed by the specified StringReplacementGenerator based on the current bounded String match. It is possible to
* specify whether the substitution will happen only if the delimited String is non-empty by setting
* replaceIfBoundedStringEmpty
to false
. It is also possible to keep the boundaries (prefix
* and suffix) after the substitution by setting keepBoundaries
to true
.
Note that it
* is possible to specify that the suffix is optional, will be passed as a match on to the specified
* StringReplacementGenerator and be replaced.
See org.gatein.common.StringTestCase.testReplaceBoundedString()
* for usage details.
*
* @param initial the String in which we want to replace bounded Strings
* @param prefix the prefix used identify the beginning of the String targeted for replacement
* @param suffix the suffix used to identify the end of the String targeted for replacement
* @param generator the StringReplacementGeneraot generating replacements based on the current
* bounded String match
* @param replaceIfBoundedStringEmpty true
to allow replacement of empty Strings (in essence, insertion
* of the replacement String between the prefix and suffix)
* @param keepBoundaries true
to keep the prefix and suffix markers in the resulting
* String
* @param suffixIsOptional whether or not the suffix is optional
* @return a String where the Strings marked by prefix and suffix have been replaced by replacement
*/
public static String replaceBoundedString(final String initial, final String prefix, final String suffix, final StringReplacementGenerator generator,
final boolean replaceIfBoundedStringEmpty, final boolean keepBoundaries, final boolean suffixIsOptional)
{
if (ParameterValidation.isNullOrEmpty(initial))
{
return initial;
}
ParameterValidation.throwIllegalArgExceptionIfNull(generator, "StringReplacementGenerator");
ParameterValidation.throwIllegalArgExceptionIfNullOrEmpty(prefix, "prefix", "TextTools.replaceBoundedString");
StringBuilder tmp = new StringBuilder(initial);
int prefixIndex = tmp.indexOf(prefix);
final int prefixLength = prefix.length();
boolean suffixAbsent = suffix == null;
int suffixLength = suffixAbsent ? 0 : suffix.length();
// nothing to do if didn't ask for an optional suffix and we have one and it's not present in our string
if (!suffixIsOptional && suffix != null && tmp.indexOf(suffix) == -1)
{
return initial;
}
// loop as long as we can find an instance of prefix in the String
while (prefixIndex != -1)
{
int suffixIndex;
if (suffixAbsent)
{
String match = tmp.substring(prefixIndex + prefixLength);
// replace prefix with replacement
if (keepBoundaries)
{
// just insert replacement for prefix
tmp.insert(prefixIndex + prefixLength, generator.getReplacementFor(match, prefix, suffix, true));
}
else
{
// delete prefix then insert remplacement instead
tmp.delete(prefixIndex, prefixIndex + prefixLength);
tmp.insert(prefixIndex, generator.getReplacementFor(match, prefix, suffix, true));
}
// new lookup starting position
prefixIndex = tmp.indexOf(prefix, prefixIndex + prefixLength);
}
else
{
// look for suffix
suffixIndex = tmp.indexOf(suffix, prefixIndex);
if (suffixIndex == -1)
{
// we haven't found suffix in the rest of the String so don't look for it again
suffixAbsent = true;
continue;
}
else
{
if (suffixIsOptional)
{
// if suffix is optional, look for potential next prefix instance that we'd need to replace
int nextPrefixIndex = tmp.indexOf(prefix, prefixIndex + prefixLength);
// check that we're not matching the suffix, which can happen if they are close one to another as is the case with WSRP
if (nextPrefixIndex >= suffixIndex && nextPrefixIndex <= (suffixIndex + suffixLength))
{
// if that's the case, look for the next one instead
nextPrefixIndex = tmp.indexOf(prefix, suffixIndex + suffixLength);
}
if (nextPrefixIndex != -1 && nextPrefixIndex <= suffixIndex)
{
// we've found an in-between prefix, use it as the suffix for the current match
// delete prefix then insert remplacement instead
String match = tmp.substring(prefixIndex + prefixLength, nextPrefixIndex);
tmp.delete(prefixIndex, prefixIndex + prefixLength);
String replacement = generator.getReplacementFor(match, prefix, suffix, true);
tmp.insert(prefixIndex, replacement);
prefixIndex = nextPrefixIndex - prefixLength + replacement.length();
continue;
}
}
// we don't care about empty bounded strings or prefix and suffix don't delimit an empty String => replace!
if (replaceIfBoundedStringEmpty || suffixIndex != prefixIndex + prefixLength)
{
String match = tmp.substring(prefixIndex + prefixLength, suffixIndex);
String replacement = generator.getReplacementFor(match, prefix, suffix, false);
int changeInLength = replacement.length() - match.length();
// compute the next lookup index from which we will look for the next prefix
int nextLookupIndex = prefixIndex + changeInLength;
if (keepBoundaries)
{
if (!suffixAbsent)
{
// delete only match
tmp.delete(prefixIndex + prefixLength, suffixIndex);
}
else
{
// delete nothing
}
tmp.insert(prefixIndex + prefixLength, replacement);
nextLookupIndex += prefixLength + suffixLength;
}
else
{
if (!suffixAbsent)
{
// if we have a suffix, delete everything between start of prefix and end of suffix
tmp.delete(prefixIndex, suffixIndex + suffixLength);
}
else
{
// only delete prefix
tmp.delete(prefixIndex, prefixIndex + prefixLength);
}
tmp.insert(prefixIndex, replacement);
}
prefixIndex = nextLookupIndex;
}
}
prefixIndex = tmp.indexOf(prefix, prefixIndex + 1); // +1 to avoid infinite loop on border cases
}
}
return tmp.toString();
}
public static interface StringReplacementGenerator
{
String getReplacementFor(String match, String prefix, String suffix, boolean matchedPrefixOnly);
}
public static class ConstantStringReplacementGenerator implements StringReplacementGenerator
{
private String replacement;
public ConstantStringReplacementGenerator(String replacement)
{
this.replacement = replacement;
}
public String getReplacementFor(String match, String prefix, String suffix, boolean matchedPrefixOnly)
{
return replacement;
}
}
}