Before the introduction of the printf(..) and format(..) methods in Java 1.5 padding strings was a little more
involved. The following method allows a string to be aligned within a column by padding the string with
the given character (most probably ' ').
For those of you who can't get to grips with format strings this method provides a simple means
of aligning text for output in tabular format.
/**
* Pad a string to the given size and alignment requirements. If the
* string is greater than the max width it is returned unmodified.
*
* If the alignment is LEFT all padding is added after the text, if the alignment
* is RIGHT all padding is added before the text and if the alignment is CENTER
* the padding is split equally before and after the text. If the padding
* cannot be split equally the extra padding is added after the text.
*
*@param text - the string to pad
*@param width - the width to pad it to
*@param align - the alignment, one of the swing constants
* SwingConstants.LEFT, SwingConstants.RIGHT or SwingConstants.CENTER
*@param padChar - the char to use for padding
*@return String - the padded string
*/
public static String padString(String text, int width, int align, char padChar)
{
if ( text == null || text.length() >= width )
return text;
StringBuilder sb = new StringBuilder();
int spaces = width - text.length();
if ( align == SwingConstants.RIGHT ||
align == SwingConstants.TRAILING )
{
for ( int i = 0; i < spaces; ++i )
sb.append(padChar);
sb.append(text);
}
else if ( align == SwingConstants.LEFT ||
align == SwingConstants.LEADING )
{
sb.append(text);
for ( int i = 0; i < spaces; ++i )
sb.append(padChar);
}
else if ( align == SwingConstants.CENTER )
{
int pre = spaces / 2;
int post = spaces - pre;
for ( int i = 0; i < pre; ++i )
sb.append(padChar);
sb.append(text);
for ( int i = 0; i < post; ++i )
sb.append(padChar);
}
return sb.toString();
}
Ever had some text where the capitalisation is not what you want, or user input that
needs correcting before output then these methods could just help you.
Sentence Capitalisation
Convert text to sentence capitalisation ie all lower case except for the first letter
of the sentence. This method also handles the special case of English text which requires
that the word 'I' is always capitalised, it does not handle proper nouns etc.
/**
* Set the capitalisation of the text on a sentence basis.
* All text to set to lower case and then the first letter of each sentence
* is set to upper case.
* A sentence is a group of characters following a '.' character.
* This implementation handles the English special case of 'I' which is
* always capitalised when used as a word in a sentence.
*
*@param text - the text to capitalise
*@return String - the captialised text
*/
public String toSentenceCapitalisation(String text)
{
char[] c = text.toLowerCase().toCharArray();
// the first char must be upper case
boolean caps = true;
// find any new sentences
for ( int i = 0; i < c.length; ++i )
{
if ( c[i] == '.' )
caps = true;
else if ( caps && Character.isLetter(c[i]) )
{
c[i] = Character.toUpperCase(c[i]);
caps = false;
}
else if ( caps && !Character.isWhitespace(c[i]) )
caps = false;
}
text = new String(c);
// if english set word 'i' to 'I'
if ( Locale.getDefault().getLanguage().equals("en") )
{
StringBuilder sb = new StringBuilder();
BreakIterator boundary = BreakIterator.getWordInstance();
boundary.setText(text);
int start = boundary.first();
int end = 0;
while ( (end = boundary.next()) != BreakIterator.DONE )
{
String word = text.substring(start, end);
start = end;
if ( word.equals("i") )
word = "I";
sb.append(word);
}
text = sb.toString();
}
return text;
}
Word Capitalisation
Convert text to word capitalisation ie every word is has an upper case first letter
and the rest of the word is lower case.
/**
* Set the capitalisation of the text on a word basis.
* All text to set to lower case and then the first letter of each word is
* set to upper case.
* A word is a group of characters following a whitespace character.
*
*@param text - the text to capitalise
*@param locale - the locale
*@return String - the captialised text
*/
public String toWordCapitalisation(String text, Locale locale)
{
StringBuilder sb = new StringBuilder();
BreakIterator boundary = BreakIterator.getWordInstance(locale);
boundary.setText(text);
int start = boundary.first();
int end = 0;
while ( (end = boundary.next()) != BreakIterator.DONE )
{
char[] c = text.substring(start, end).toLowerCase().toCharArray();
start = end;
// if the first char is a letter
if ( Character.isLetter(c[0]) )
c[0] = Character.toUpperCase(c[0]);
sb.append(c);
}
return sb.toString();
}
Making a copy of a file sounds easy but handling all the exceptions and ensuring the file
streams are always closed makes a simple task very complicated.
Here's a method that creates the destination files directory structure if it doesn't already exist and
then copies the source file to the destination file. This method handles binary and text files.
/**
* Copy a file.
*
*@param source - the file to be copied
*@param dest - the destination file
*/
public void copyFile(File source, File dest) throws FileNotFoundException, IOException
{
if ( source == null || dest == null )
throw new NullPointerException("The source and/or destination files can not be null");
// if there's no source
if ( !source.exists() )
{
throw new FileNotFoundException("The source file "+source+" does not exist");
}
// if the destination file has a parent directory but it doesn't exist yet then create it
File dir = dest.getParentFile();
if ( dir != null && !dir.exists() )
{
boolean ok = dir.mkdirs();
if ( !ok )
{
throw new IOException("Make dirs for '"+dir+"' failed");
}
}
BufferedInputStream bfis;
BufferedOutputStream bfos;
// open input and output streams
bfis = new BufferedInputStream(new FileInputStream(source), BUFSIZE);
try {
bfos = new BufferedOutputStream(new FileOutputStream(dest), BUFSIZE);
}
catch(IOException e)
{
// if there is no output stream close the input stream and exit
bfis.close();
throw e;
}
// copy the file
try {
byte[] b = new byte[BUFSIZE];
int nb;
do
{
nb = bfis.read(b, 0, b.length);
if ( nb > 0 )
bfos.write(b, 0, nb);
}
while ( nb != -1 );
bfos.flush();
}
finally
{
// close the file streams
try {
bfis.close();
}
finally
{
bfos.close();
}
}
}
If you have a string with a combination and text and numbers with clearly defined boundaries
(for example: "Number of Parts = 230") then
you can easily tokenise the string using the java.util.scanner class. But if there are no obvious boundaries
such as component part numbers which are often a combination of letters and numbers
(for example: "AN3498-A") it is harder to tokenise the text.
This class provides a solution, handling embedded integer and optionally floating point numbers
in locale specific formats.
/**
* Copyright (c) 2004, 2010 Keang Ltd
*
* The AlphaNumericTokeniser class 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.
*
* The AlphaNumericTokeniser class 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 the AlphaNumericTokeniser class. If not, see www.gnu.org/licenses.
*/
package uk.co.keang.utilities;
import java.text.DecimalFormatSymbols;
import java.util.Iterator;
import java.util.Locale;
import java.util.NoSuchElementException;
/**
* A tokeniser class that breaks a string into alpha and numeric parts in a
* locale dependent way.
*
* The numeric parts are converted into either int or double types
* wrapped in their corresponding object type.
* The alpha parts are returned as Strings.
*
* Example:
*
* AlphaNumericTokeniser ant = new AlphaNumericTokeniser(null);
*
* ant.setText("Mixed 123 alph 0.122 chars");
*
* while ( ant.hasNext() )
* logger.info("Found '"+ant.next()+"'");
*
*
*
* The tokeniser can be configured to adjust the way it handles numeric values.
*
*
*@author Keang Ltd
*@version 1.0, 22/06/2004
*/
public class AlphaNumericTokeniser implements Iterator
When sorting lists of text, such as file names, into alphbetical order problems can
arise if the text includes numbers. For example if you have a series of files numbered from
myFile1.txt to myFile17.txt then myFile2.txt to myFile9.txt would appear after myFile17.txt
when, from a numerical point of view, they should be after myFile1.txt and before myFile10.txt.
This class provides a solution utilising the Alpha-Numeric Tokeniser class to
handle embedded integer and optionally floating point numbers
in locale specific formats.
Sorting of lists etc is achieved by creating an instance of this comparator and passing it to
any sorting method that accepts a comparator for example java.util.Collections.sort(..)
or for classes which maintain order of their elements, for example java.util.TreeMap,
by passing it as a parameter to the class constructor.
/**
* Copyright (c) 2006, 2010 Keang Ltd
*
* The AlphaNumericComparator class 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.
*
* The AlphaNumericComparator class 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 the AlphaNumericComparator class. If not, see www.gnu.org/licenses.
*/
package uk.co.keang.utilities;
import java.util.Comparator;
import java.util.Locale;
/**
* A comparator class for comparing strings with a mix of
* alpha and numeric parts. The strings are split into there alpha and numeric
* parts which are then compared part by part. In this way numeric parts are
* handled as complete numbers giving proper ordering.
*
*@author Keang Ltd
*@version 1.0, 28/06/2006
*/
public class AlphaNumericComparator implements Comparator
{
private AlphaNumericTokeniser tok1;
private AlphaNumericTokeniser tok2;
/**
* Create a Comparator for this locale that does not allow negative number, floating point
* numbers or numeric separators.
*
*/
public AlphaNumericComparator()
{
this(null, false, false, false, false);
}
/**
* Create a Comparator
*
* @param locale the locale to use for define numeric symbols such as the decimal point etc,
* or null for the default locale
* @param minusEnabled true to allow negative numbers
* @param floatsEnabled true to allow floating point numbers
* @param floatsNoLeadingDigitEnabled true to allow floating point numbers without leading digits
* @param separatorsEnabled true to allow numeric separators (ie in UK ',' is a thousands separator)
*/
public AlphaNumericComparator(Locale locale, boolean minusEnabled, boolean floatsEnabled,
boolean floatsNoLeadingDigitEnabled, boolean separatorsEnabled)
{
tok1 = new AlphaNumericTokeniser(null, locale, minusEnabled, floatsEnabled, floatsNoLeadingDigitEnabled, separatorsEnabled);
tok2 = new AlphaNumericTokeniser(null, locale, minusEnabled, floatsEnabled, floatsNoLeadingDigitEnabled, separatorsEnabled);
}
/**
* Compares its two arguments for order. Returns a negative integer, zero, or a
* positive integer as the first argument is less than, equal to, or greater
* than the second.
*
* The ordering by type is Integer, Double and then String.
* The ordering within each type is: Numeric types are in numerical order, String types
* are in alphabetical order.
*
*@param s1 - the first object to be compared.
*@param s2 - the second object to be compared.
*@return a negative integer, zero, or a positive integer as the first argument
* is less than, equal to, or greater than the second.
*@exception ClassCastException - if the arguments' types prevent them from
* being compared by this Comparator.
*/
public int compare(String s1, String s2)
{
// do a simple check for equality first
if ( s1.equals(s2) )
return 0;
tok1.setText(s1);
tok2.setText(s2);
while ( tok1.hasNext() )
{
// if the second string doesn't have as many parts: o1 > o2
if ( !tok2.hasNext() )
return 1;
Object obj1 = tok1.next();
Object obj2 = tok2.next();
if ( obj1 instanceof String )
{
if ( obj2 instanceof String )
{
// they're both strings so compare them
int result = ((String)obj1).compareTo((String)obj2);
if ( result != 0 )
return result;
}
else
{
// o1 has a string part here and o2 doesn't: o1 > 02
return 1;
}
}
else if ( obj1 instanceof Integer )
{
if ( obj2 instanceof Integer )
{
// they're both ints so compare them
int i1 = ((Integer)obj1).intValue();
int i2 = ((Integer)obj2).intValue();
int result = i1 - i2;
if ( result < 0 )
return -1;
else if ( result > 0 )
return 1;
}
else
{
// o1 has an integer part here and o2 doesn't: o1 < 02
return -1;
}
}
else if ( obj1 instanceof Double )
{
if ( obj2 instanceof Double )
{
// they're both ints so compare them
double i1 = ((Double)obj1).doubleValue();
double i2 = ((Double)obj2).doubleValue();
double result = i1 - i2;
if ( result < 0 )
return -1;
else if ( result > 0 )
return 1;
}
else if ( obj2 instanceof Integer )
{
// o1 has a double part here and o2 has an integer: o1 > 02
return 1;
}
else
{
// o1 has a double part here and o2 has a string: o1 < 02
return -1;
}
}
else
{
throw new ClassCastException("Can't compare "+obj1+" to "+obj2);
}
}
if ( tok2.hasNext() )
return -1;
return 0;
}
}