/*
* This file is part of WebLookAndFeel library.
*
* WebLookAndFeel library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* WebLookAndFeel library 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with WebLookAndFeel library. If not, see .
*/
package com.alee.utils;
import com.alee.utils.text.SimpleTextProvider;
import com.alee.utils.text.TextProvider;
import java.awt.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;
/**
* This class provides a set of utilities to work with various text usage cases.
*
* @author Mikle Garin
*/
public final class TextUtils
{
/**
* Separators used to determine words in text.
*/
private static final List textSeparators =
Arrays.asList ( " ", ".", ",", ":", ";", "/", "\\", "\n", "\t", "|", "{", "}", "[", "]", "(", ")", "<", ">", "-", "+", "\"",
"'", "*", "%", "$", "#", "@", "!", "~", "^", "&", "?" );
/**
* Text provider for any type of objects.
*/
private static final SimpleTextProvider simpleTextProvider = new SimpleTextProvider ();
/**
* Default ID part length.
*/
private static final int idPartLength = 5;
/**
* Default ID prefix.
*/
private static final String defaultIdPrefix = "WebLaF";
/**
* Default ID suffix.
*/
private static final String defaultIdSuffix = "ID";
/**
* Returns first number found in text.
*
* @param text text to search through
* @return first found number
*/
public static Integer findFirstNumber ( final String text )
{
final StringBuilder sb = new StringBuilder ( "" );
for ( int j = 0; j < text.length (); j++ )
{
final char ch = text.charAt ( j );
if ( Character.isDigit ( ch ) )
{
sb.append ( ch );
}
else if ( sb.length () > 0 )
{
break;
}
}
return Integer.parseInt ( sb.toString () );
}
/**
* Returns a word from text at the specified location.
*
* @param text text to retrieve the word from
* @param location word location
* @return word
*/
public static String getWord ( final String text, final int location )
{
int wordStart = location;
int wordEnd = location;
// At the word start
while ( wordEnd < text.length () - 1 && !textSeparators.contains ( text.substring ( wordEnd, wordEnd + 1 ) ) )
{
wordEnd++;
}
// At the word end
while ( wordStart > 0 && !textSeparators.contains ( text.substring ( wordStart - 1, wordStart ) ) )
{
wordStart--;
}
return wordStart == wordEnd ? null : text.substring ( wordStart, wordEnd );
}
/**
* Returns a word start index at the specified location.
*
* @param text text to retrieve the word start index from
* @param location word location
* @return word start index
*/
public static int getWordStart ( final String text, final int location )
{
int wordStart = location;
while ( wordStart > 0 && !textSeparators.contains ( text.substring ( wordStart - 1, wordStart ) ) )
{
wordStart--;
}
return wordStart;
}
/**
* Returns a word end index at the specified location.
*
* @param text text to retrieve the word end index from
* @param location word location
* @return word end index
*/
public static int getWordEnd ( final String text, final int location )
{
int wordEnd = location;
while ( wordEnd < text.length () - 1 && !textSeparators.contains ( text.substring ( wordEnd, wordEnd + 1 ) ) )
{
wordEnd++;
}
return wordEnd;
}
/**
* Returns text with first lines removed.
*
* @param text text to crop
* @param count lines count to crop
* @return cropped text
*/
public static String removeFirstLines ( final String text, final int count )
{
int found = 0;
int index = 0;
while ( found < count )
{
index = text.indexOf ( "\n", index );
if ( index != -1 )
{
index += 1;
found++;
}
else
{
return "";
}
}
return text.substring ( index );
}
/**
* Returns a list of text parts splitted using specified separator.
*
* @param text text to split
* @param separator text parts separator
* @return list of splitted parts
*/
public static List split ( final String text, final String separator )
{
return Arrays.asList ( text.split ( separator ) );
}
/**
* Returns point extracted from text.
*
* @param text text to extract point from
* @return extracted point
*/
public static Point parsePoint ( final String text )
{
return parsePoint ( text, "," );
}
/**
* Returns point extracted from text.
*
* @param text text to extract point from
* @param separator point values separator
* @return extracted point
*/
public static Point parsePoint ( final String text, final String separator )
{
final String[] parts = text.split ( separator );
return parts.length == 2 ? new Point ( Integer.parseInt ( parts[ 0 ].trim () ), Integer.parseInt ( parts[ 1 ].trim () ) ) : null;
}
/**
* Returns text with all control symbols removed.
* This method works faster than simple replaceAll("\\p{Cntrl}", "").
*
* @param text text to modify
* @return text without conytol symbols
*/
public static String removeControlSymbols ( final String text )
{
final int length = text.length ();
final char[] oldChars = new char[ length ];
text.getChars ( 0, length, oldChars, 0 );
int newLen = 0;
for ( int j = 0; j < length; j++ )
{
final char ch = oldChars[ j ];
if ( ch >= ' ' )
{
oldChars[ newLen ] = ch;
newLen++;
}
}
return text;
}
/**
* Returns shortened text.
*
* @param text text to shorten
* @param maxLength maximum shortened text lenght
* @param addDots add dots at the end of the text when shortened
* @return shortened text
*/
public static String shortenText ( final String text, final int maxLength, final boolean addDots )
{
return text.length () <= maxLength ? text :
text.substring ( 0, maxLength > 3 && addDots ? maxLength - 3 : maxLength ) + ( addDots ? "..." : "" );
}
/**
* Returns shortened text.
*
* @param text text to shorten
* @param maxLength maximum shortened text lenght
* @param addDots add dots at the end of the text when shortened
* @return shortened text
*/
public static String shortenTextEnd ( final String text, final int maxLength, final boolean addDots )
{
return text.length () <= maxLength ? text :
( addDots ? "..." : "" ) + text.substring ( text.length () - ( maxLength > 3 && addDots ? maxLength - 3 : maxLength ) );
}
/**
* Returns a list of text parts splitted using specified separator.
*
* @param string text to split
* @param separator text parts separator
* @return list of splitted parts
*/
public static List stringToList ( final String string, final String separator )
{
final List strings = new ArrayList ();
if ( string != null )
{
final StringTokenizer tokenizer = new StringTokenizer ( string, separator, false );
while ( tokenizer.hasMoreTokens () )
{
strings.add ( tokenizer.nextToken ().trim () );
}
}
return strings;
}
/**
* Returns a list of integer parts splitted using specified separator.
*
* @param string text to split
* @param separator text parts separator
* @return list of splitted parts
*/
public static List stringToIntList ( final String string, final String separator )
{
final List stringList = stringToList ( string, separator );
if ( stringList != null )
{
final List intList = new ArrayList ( stringList.size () );
for ( final String s : stringList )
{
intList.add ( Integer.parseInt ( s ) );
}
return intList;
}
else
{
return null;
}
}
/**
* Returns single text combined using list of strings and specified separator.
*
* @param list list to combine into single text
* @param separator text parts separator
* @return single text
*/
public static String listToString ( final List list, final String separator )
{
return listToString ( list, separator, simpleTextProvider );
}
/**
* Returns single text combined using list of strings and specified separator.
*
* @param list list to combine into single text
* @param separator text parts separator
* @param textProvider text provider
* @return single text
*/
public static String listToString ( final List list, final String separator, final TextProvider textProvider )
{
if ( list != null && list.size () > 0 )
{
final StringBuilder stringBuilder = new StringBuilder ();
final int end = list.size () - 1;
for ( int i = 0; i <= end; i++ )
{
stringBuilder.append ( textProvider.provide ( list.get ( i ) ) );
stringBuilder.append ( i != end ? separator : "" );
}
return stringBuilder.toString ();
}
else
{
return null;
}
}
/**
* Converts list of enumeration constants into string with list of enumeration constants and returns it.
*
* @param enumList enumeration constants list
* @param enumeration type
* @return string with list of enumeration constants
*/
public static > String enumListToString ( final List enumList )
{
if ( enumList != null && enumList.size () > 0 )
{
final int end = enumList.size () - 1;
final StringBuilder stringBuilder = new StringBuilder ();
for ( int i = 0; i <= end; i++ )
{
stringBuilder.append ( enumList.get ( i ) );
stringBuilder.append ( i != end ? "," : "" );
}
return stringBuilder.toString ();
}
else
{
return null;
}
}
/**
* Converts string with list of enumeration constants into real list of enumeration constants and returns it.
*
* @param enumString enumeration constants string list
* @param enumClass enumeration class
* @param enumeration type
* @return list of enumeration constants
*/
public static > List enumStringToList ( final String enumString, final Class enumClass )
{
final List enumerations;
if ( enumString != null )
{
final StringTokenizer tokenizer = new StringTokenizer ( enumString, ",", false );
enumerations = new ArrayList ();
while ( tokenizer.hasMoreTokens () )
{
enumerations.add ( Enum.valueOf ( enumClass, tokenizer.nextToken ().trim () ) );
}
}
else
{
enumerations = new ArrayList ( 0 );
}
return enumerations;
}
/**
* Creates new string filled with specified amount of same characters.
*
* @param character character to fill string with
* @param length string length
* @return new string filled with specified amount of same characters
*/
public static String createString ( final String character, int length )
{
final StringBuilder sb = new StringBuilder ( length );
while ( length-- > 0 )
{
sb.append ( character );
}
return sb.toString ();
}
/**
* Returns random ID with default prefix and suffix.
*
* @return ID
*/
public static String generateId ()
{
return generateId ( null, null );
}
/**
* Returns random ID with specified prefix and default suffix.
*
* @param prefix id prefix
* @return ID
*/
public static String generateId ( final String prefix )
{
return generateId ( prefix, null );
}
/**
* Returns random ID with specified prefix and suffix.
*
* @param prefix id prefix
* @param suffix id suffix
* @return ID
*/
public static String generateId ( final String prefix, final String suffix )
{
return ( prefix == null ? defaultIdPrefix : prefix ) + "-" + generateId ( idPartLength ) + "-" + generateId ( idPartLength ) + "-" +
generateId ( idPartLength ) + "-" + generateId ( idPartLength ) + "-" + ( suffix == null ? defaultIdSuffix : suffix );
}
/**
* Returns randomly generated ID part with specified length.
*
* @param length part length in symbols
* @return ID part
*/
private static String generateId ( final int length )
{
final StringBuilder stringBuilder = new StringBuilder ( length );
for ( int i = 0; i < length; i++ )
{
char next = 0;
int range = 10;
switch ( MathUtils.random ( 3 ) )
{
case 0:
{
next = '0';
range = 10;
break;
}
case 1:
{
next = 'a';
range = 26;
break;
}
case 2:
{
next = 'A';
range = 26;
break;
}
}
stringBuilder.append ( ( char ) ( ( MathUtils.random ( range ) ) + next ) );
}
return stringBuilder.toString ();
}
}