1. Strings

Introduction

//----------------------------------------------------------------------------------
// character are simple values, and use single quotes are delimiters
char c = '\n';                           // a newline character
//----------------------------------------------------------------------------------
// strings are immutable objects, and use double quotes as delimiters
String s1 = "\n";                    // a string containing only a newline
String s2 = "Jon \"Maddog\" Orwant"; // a string containing double quotes
//----------------------------------------------------------------------------------
// use concatenation for multiline string declation
String s = "This is a multiline string declaration "
         + "using the concatenation operator "
         + "to append separate parts.";
//----------------------------------------------------------------------------------

Accessing Substrings

//----------------------------------------------------------------------------------
// accessing substrings
String s1 = data.substring(start, end);
String s2 = data.substring(start);
            
// String instances are immutable character sequences
// recreating them on the fly is unefficient
String variableString = data;
variableString = variableString.substring(0, start) + newMiddle
    + variableString.substring(start);
variableString = variableString.substring(0, start) + newTail;

// StringBuffer instances are mutable character sequences
// they provides efficient modification methods
StringBuffer variableStringBuffer = new StringBuffer(data);
variableStringBuffer.replace(start, end, newMiddle);
variableStringBuffer.replace(start, variableStringBuffer.length(), newTail);
//----------------------------------------------------------------------------------
// No real pack/unpack equivalent exist in Java. Exemples here use a custom
// implementation to split an original string into chunks of specified length

// get a 5-characters string, skip 3, then grab 2 8-characters strings,
// then the rest
try { 
    String[] a = unpack("A5 x3 A8 A8 A*", data);
} catch (ParseException ex) {}

// split at five characters boundaries
try { 
    String[] fivers = unpack(aggregate("A5 ", data.length() / 5), data);
} catch (ParseException ex) {}

// chop string into unique character strings
try { 
    String[] chars = unpack(aggregate("A1 ", data.length()), data);
} catch (ParseException ex) {}

/**
 * Unpacks a string into a string array following a given format.
 */
String[] unpack(String format, String data) throws ParseException {
    ArrayList result = new ArrayList();
    int formatOffset = 0;
    int dataOffset = 0;
    int minDataOffset = 0;
    int maxDataOffset = data.length();
    
    StringTokenizer tokenizer = new StringTokenizer(format);
    while (tokenizer.hasMoreTokens()) {
        String token = tokenizer.nextToken();
        int tokenLen = token.length();
        
        // count determination
        int count = 0;
        if (tokenLen == 1)
            count = 1;
        else if (token.charAt(1) == '*')
            count = -1;
        else {
            try {
                count = new Integer(token.substring(1)).intValue();
            } catch (NumberFormatException ex) {
                throw new ParseException("Unknown count token", formatOffset);
            }
        }
        
        // action determination
        char action = token.charAt(0);
        switch (action) {
            case 'A':
                if (count == -1) {
                    int start = (dataOffset < maxDataOffset) ?
                        dataOffset : maxDataOffset;
                    result.add(data.substring(start));
                    dataOffset = maxDataOffset;
                } else {
                    int start = (dataOffset < maxDataOffset) ?
                        dataOffset : maxDataOffset;
                    int end = (dataOffset + count < maxDataOffset) ?
                        dataOffset + count : maxDataOffset;
                    result.add(data.substring(start, end));
                    dataOffset += count;
                }
                break;
            case 'x':
                if (count == -1)
                    dataOffset = maxDataOffset;
                else
                    dataOffset += count;
                break;
            case 'X':
                if (count == -1)
                    dataOffset = minDataOffset;
                else
                    dataOffset -= count;
                break;
            default:
                throw new ParseException("Unknown action token", formatOffset);
        }
        formatOffset += tokenLen + 1;
    }
    return (String[]) result.toArray(new String[result.size()]);
}

/**
 * Aggregates repetitly a basic pattern.
 */
String aggregate(String pattern, int count) {
    StringBuffer buffer = new StringBuffer();
    for (int i=0; i < count; i++)
        buffer.append(pattern);
    return buffer.toString();
}
//----------------------------------------------------------------------------------
String data = "This is what you have";
// forward    +012345678901234567890 
// backward    109876543210987654321-

// backward indexing doesn't exist, but can easily be translated into forward
// indexing: forward = data.length() - backward;

String first = data.substring(0, 1);
// "T"
String start = data.substring(5, 7);
// "is"
String rest  = data.substring(13);
// "you have"
String last  = data.substring(data.length() - 1);
// "e"
String end   = data.substring(data.length() - 4);
// "have"
String piece = data.substring(data.length() - 8, data.length() - 5);
// "you"
//----------------------------------------------------------------------------------
String data = "This is what you have";
data = data.substring(0, 5) + "wasn't" + data.substring(7);
// "This wasn't what you have"
data = data.substring(0, data.length() - 12) + "ondrous";
// "This wasn't wondrous"
data = data.substring(1);
// "his wasn't wondrous"
data = data.substring(0, data.length() - 10);
// "his wasn'"
//----------------------------------------------------------------------------------
import org.apache.oro.text.perl.Perl5Util;

Perl5Util util = new Perl5Util();
// you can test substrings with match() method
if (util.match("/pattern/", data.substring(data.length() - 10)))
    System.out.println("Pattern matches in last 10 characters");

// substitute "at" for "is", restricted to first five characters
data = util.substitute("s/is/at/g", data.substring(0, 5)) + data.substring(5);
//----------------------------------------------------------------------------------
// exchange the first and last letters in a string
String data = "make a hat";
data = data.charAt(data.length() -1) + data.substring(1, data.length() - 1)
    + data.charAt(0); // "take a ham"
//----------------------------------------------------------------------------------
// extract column with unpack
String data = "To be or not to be";

// skip 6, grab 6
try {
    String[] a1 = unpack("x6 A6", data);       // {"or not"}
} catch (ParseException ex) {}

// forward 6, grab 2, backward 5, grab 2
try {
    String[] a2 = unpack("x6 A2 X5 A2", data); // {"or", "be"}
} catch (ParseException ex) {}
//----------------------------------------------------------------------------------
/**
 * Creates a format suitable for unpack method.
 */
String cut2fmt(int[] positions) {
    StringBuffer sb = new StringBuffer();
    int end = 1;
    for (int i=0; i < positions.length; i++) {
        sb.append("A");
        sb.append(positions[i] - end);
        sb.append(" ");
        end = positions[i];
    }
    sb.append("A*");
    return sb.toString();
}

String fmt = cut2fmt(new int[] {8, 14, 20, 26, 30}); // "A7 A6 A6 A6 A4 A*"
//----------------------------------------------------------------------------------

Establishing a Default Value

//----------------------------------------------------------------------------------
// truth only concern boolean values

// use b if b is true, else c
boolean  b, c;
// [..]
boolean a = (b || c);              

// set x to y unless x is already true
boolean x, y;
// [..]
x = (x || y);
//----------------------------------------------------------------------------------
// other types must test default value
// only instance variables have default values, depending of their type:
// object -> null
// int -> 0
// char -> ?
// boolean -> ?
// local variables must always be explicitly initialised

// creating a new variable: ternary operator
//use b if b is not null, else c
Object b, c;
// [..]
Object a = (b != null) ? b : c;

// reallocating a variable: direct test
// set x to y unless x is already true
Object x, y;
// [..]
if (x == null)
    x = y;
//----------------------------------------------------------------------------------
// strings are objects, so you must use the ternary operator
String foo = (bar != null) ? bar : "DEFAULT VALUE";
// you may also consider the empty string case
// you must first test for nullity, to prevent a potential NullPointerException
String foo = ((bar != null) && (bar.length != 0)) ? bar : "DEFAULT VALUE";
//----------------------------------------------------------------------------------
int index = 0;
// lazy evaluation prevents various exceptions to occurs
String dir = ((args.length > index) && (args[index] != null)
    && (args[index].length != 0)) ? args[index] : "/tmp";
index++;
//----------------------------------------------------------------------------------
int index = 0;
// lazy evaluation prevents various exceptions to occurs
String dir = ((args.length > index) && (args[index] != null)
    && (args[index].length != 0)) ? args[index++] : "/tmp";
//----------------------------------------------------------------------------------
String dir = ((args.length != 0)) ? args[0] : "/tmp";
//----------------------------------------------------------------------------------
// Collection contains only objects, so values must be wrapped
String key = (shell != null) ? shell : "/bin/sh";
int value = 0;
if (count.containsKey(key))
    value = ((Integer) count.get(key)).intValue();
count.put(key, new Integer(++value));
//----------------------------------------------------------------------------------
// chained conditional allocations can test preceding allocation value

// find the user name on Unix systems
String user;
Properties environment = getEnvironment();
int UID = getUID();
if ((user = environment.getProperty("USER")) == null)
    if ((user = environment.getProperty("LOGNAME")) == null)
        if ((user = getLogin()) == null)
            if ((user = getPWUID(UID)[0]) == null)
                user = "Unknown uid number " + UID;

/**
 * Returns current environment.
 */
Properties getEnvironment() {
    Properties environment = new Properties();
    try {
        Process process = Runtime.getRuntime().exec("env");
        BufferedReader input =
            new BufferedReader(new InputStreamReader(process.getInputStream()));
        String line;
        while ((line = input.readLine()) != null) {
            int limit = line.indexOf('=');
            String key = line.substring(0, limit);
            String value = line.substring(limit + 1);
            environment.setProperty(key, value);
        }
    } catch (IOException ex) {
        System.err.println("Error occured while processing environment");
    }
    return environment;
}

/**
 * Returns current login.
 */
String getLogin() {
    String login = "";
    try {
        Process process = Runtime.getRuntime().exec("cat /etc/utmp");
        BufferedReader input = 
            new BufferedReader(new InputStreamReader(process.getInputStream()));
        login = input.readLine();
    } catch (IOException ex) {
        System.err.println("Error occured while processing login");
    }
    return login;
}

/**
 * Returns current UID.
 */
int getUID() {
    int uid = 0;
    try {
        Process process = Runtime.getRuntime().exec("id -u");
        BufferedReader input =
            new BufferedReader(new InputStreamReader(process.getInputStream()));
        uid = new Integer(input.readLine()).intValue();
    } catch (IOException ex) {
        System.err.println("Error occured while processing login");
    }
    return uid;
}

/**
 * Returns /etc/passwd line relative to given UID.
 */
String[] getPWUID(int uid) {
    ArrayList pwuid = new ArrayList();
    try {
        Process process =
            Runtime.getRuntime().exec("grep ^[^:]*:[^:]*:" + uid + " /etc/passwd");
        BufferedReader input =
            new BufferedReader(new InputStreamReader(process.getInputStream()));
        StringTokenizer tokenizer = new StringTokenizer(input.readLine(), ":");
        while (tokenizer.hasMoreTokens())
            pwuid.add(tokenizer.nextToken());
    } catch (IOException ex) {
        System.err.println("Error occured while processing login");
    }
    return (String[]) pwuid.toArray(new String[pwuid.size()]);
}
//----------------------------------------------------------------------------------
// test for nullity then for emptyness
if ((startingPoint == null) || (startingPoint.length() == 0))
    startingPoint = "Greenwich";
//----------------------------------------------------------------------------------
Object[] a, b, c;

// copy only if empty
// test for nullity then for emptyness
if ((a == null) || (a.length == 0))
    a = b;

// assign b if nonempty, else c
// test for nullity then for emptyness
a = ((b != null) && (b.length != 0)) ? b : c;
//----------------------------------------------------------------------------------

Exchanging Values Without Using Temporary Variables

//----------------------------------------------------------------------------------
// Not possible in Java
//----------------------------------------------------------------------------------

Converting Between ASCII Characters and Values

//----------------------------------------------------------------------------------
// char and int are interchangables, apart precision difference
// char use 16 bits while int use 32, requiring a cast from int to char
int num;
char ch;
num = ch;        // no problem 
ch = (char) num; // needs an explicit cast
//----------------------------------------------------------------------------------
System.out.println("Number " + num + " is character " + (char) num);
// Number 101 is character e
System.out.println("Character " + ch + " is number " + (int) ch);
// Character e is number 101
//----------------------------------------------------------------------------------
char[] ascii = string.toCharArray();
String string = new String(ascii);
//----------------------------------------------------------------------------------
int value      = 'e'; // now 101
char character = 101; // now "e"
//----------------------------------------------------------------------------------
System.out.println("Number " + 101 + " is character " + (char) 101);
//----------------------------------------------------------------------------------
char[] ascii = "sample".toCharArray();
// {115, 97, 109, 112, 108, 101}
String s1 = new String(ascii);
// "sample"
String s2 = new String(new char[] {115, 97, 109, 112, 108, 101});
// "sample"
//----------------------------------------------------------------------------------
String hal = "HAL";
char[] ascii = hal.toCharArray();
for (int i=0; i<ascii.length; i++)
    ascii[i]++;                 // add one to each ASCII value
String ibm = new String(ascii); // IBM
//----------------------------------------------------------------------------------

Processing a String One Character at a Time

//----------------------------------------------------------------------------------
// You can process a string either by character or by string element:
// using character is more efficient, as they are values
// using string allow to use object-based methods, as collections 

// splitting a string into elementary characters
char[] charArray = string.toCharArray();
//----------------------------------------------------------------------------------
int size = string.length();
// processing a string by elementary strings
for (int i=0; i<size; i++) {
    String s = string.substring(i, i + 1);
    // do something with s
}
// processing a string by elementary characters
for (int i=0; i<size; i++) {
    char ch = string.charAt(i);
    // do something with s
}
//----------------------------------------------------------------------------------
// with an array, using chars
String string = "an apple a day";
boolean[] seen = new boolean[256];
Arrays.fill(seen, false);

char[] array = string.toCharArray();
for (int i=0; i<array.length; i++)
    seen[array[i]] = true;

System.out.print("unique chars are: ");
for (int i=0; i<seen.length; i++)
    if (seen[i])
        System.out.print((char) i);
System.out.println(); 

//=> unique chars are:  adelnpy
//----------------------------------------------------------------------------------
// with a loop, using strings
String string = "an apple a day";
TreeSet seen = new TreeSet();

int size = string.length();
for (int i=0; i<size; i++)
    seen.add(string.substring(i, i + 1));

System.out.print("unique chars are: ");
Iterator it = seen.iterator();
while (it.hasNext())
    System.out.print(it.next());
System.out.println();

//=> unique chars are:  adelnpy
//----------------------------------------------------------------------------------
int sum = 0;
char[] chars = string.toCharArray();
for (int i=0; i<chars.length; i++)
    sum += chars[i];
System.out.println("sum is " + sum);

// prints "1248" if string was "an apple a day"
//----------------------------------------------------------------------------------
/*
 * Sum.java
 */
package pleac.ch01.part05;

import java.io.*;
/**
 * Compute 16-bit checksum of input file
 * Usage: java pleac.ch01.part05.Sum <file>
 */
public class Sum {

    public static void main(String args[]) {
        if (args.length < 1) {
            System.err.println("Usage: java pleac.ch01.part05.Sum <file>");
            System.exit(1);
        }
        
        int checksum = 0;
        try {
            Reader input = new FileReader(args[0]);
            int ch;
            while ((ch = input.read()) != -1)
                checksum += ch;
        } catch (IOException ex) {
            System.err.println("Exception occured: " + ex);
        }
        checksum %= (java.lang.Math.pow(2, 16) - 1); 

        System.out.println(checksum);
    }
    
}
//----------------------------------------------------------------------------------
//=> % java Sum /etc/termcap
//=> 53651
//----------------------------------------------------------------------------------
//=> % sum --sysv /etc/termcap
//=> 53651 1373 /etc/termcap
//----------------------------------------------------------------------------------
/*
 * Slowcat.java
 */
package pleac.ch01.part05;

import java.io.*;
/**
 * Emulate a  s l o w line printer
 * Usage: java pleac.ch01.part05.Slowcat <file>
 */
public class Slowcat {

    public static void main(String args[]) {
        if (args.length < 1) {
            System.err.println("Usage: java pleac.ch01.part05.Slowcat <file> [delay]");
            System.exit(1);
        }
        long delay = ((args.length > 1) && (args[1] != null)) ?
            1000 * new Long(args[1]).longValue() : 1000;
        
        try {
            Reader input = new FileReader(args[0]);
            int ch;
            while ((ch = input.read()) != -1) {
                System.out.print((char) ch);
                try {
                Thread.sleep(delay);
                } catch (InterruptedException ex) {}
            }
        } catch (IOException ex) {
            System.err.println("Exception occured: " + ex);
        }
    }
    
}
//----------------------------------------------------------------------------------

Reversing a String by Word or Character

//----------------------------------------------------------------------------------
String reverseCharacters(String string) {
    int length = string.length();
    char[] chars = string.toCharArray();
    char[] revChars = new char[length];
    for (int i=0; i < length; i++)
        revChars[i] = chars[length - i];
    return new String(revChars);
}
//----------------------------------------------------------------------------------
String reverseWords(String string) {
    StringTokenizer tokenizer = new StringTokenizer(string, " ");
    StringBuffer buffer = new StringBuffer();
    while (tokenizer.hasMoreTokens())
        buffer.insert(0, tokenizer.nextToken() + " ");
    return buffer.toString();
}
//----------------------------------------------------------------------------------
String string = 'Yoda said, "can you see this?"';
System.out.println(reverseWords(string));

this?" see you "can said, Yoda
//----------------------------------------------------------------------------------
// normalize whitespace
StringTokenizer tokenizer = new StringTokenizer(string, " ");
StringBuffer buffer = new StringBuffer();
while (tokenizer.hasMoreTokens())
    buffer.insert(0, tokenizer.nextToken() + " ");
//----------------------------------------------------------------------------------
// preserve whitespace
StringTokenizer tokenizer = new StringTokenizer(string, " ", true);
StringBuffer buffer = new StringBuffer();
while (tokenizer.hasMoreTokens())
    buffer.insert(0, tokenizer.nextToken());
//----------------------------------------------------------------------------------
String word = "reviver";
boolean isPalindrome = word.equals(reverseCharacters(word));
//----------------------------------------------------------------------------------
String file = "/usr/share/dict/words";
int length = 5;
try {
    BufferedReader input = new BufferedReader(new FileReader(file));
    String word;
    while ((word = input.readLine()) != null)
        if ((word.length() > length) && (word.equals(reverseCharacters(word))))
            System.out.println(word);
} catch (IOException ex) {
    System.err.println("Exception occured: " + ex);
}
//=> redder
//=> reviver
//=> rotator

Expanding and Compressing Tabs

//----------------------------------------------------------------------------------
String expand(String string, int tabStop) {
    int index = string.indexOf('\t');
    if (index == -1)
        return string;
    else {
        StringBuffer buffer = new StringBuffer(string);
        int count = tabStop - index % tabStop;
        buffer.deleteCharAt(index);
        for (int i=0; i<count; i++)
            buffer.insert(index, " ");
        return expand(buffer.toString(), tabStop);      
    }
}

String unexpand(String string, int tabStop) {
    StringBuffer buffer = new StringBuffer(string);
    int index = 0;
    while (index + tabStop < buffer.length()) {
        // cut original string in tabstop-length pieces
        String piece = buffer.substring(index, index + tabStop);
        // count trailing whitespace characters
        int count = 0;
        while ((count < tabStop)
            && (Character.isWhitespace(piece.charAt(tabStop - (count + 1)))))
            count++;
        // replace in original string if any whitespace was found
        if (count > 0) {
            piece = piece.substring(0, tabStop - count) + '\t';
            buffer.replace(index, index + tabStop, piece);
            index = index + tabStop - (count - 1);
        } else 
            index = index + tabStop;
    }
    return buffer.toString();
}
//----------------------------------------------------------------------------------
BufferedReader input;
String line;
// [..]
while ((line = input.readLine()) != null)
    System.out.println(expand(line), 4);
//----------------------------------------------------------------------------------
BufferedReader input;
String line;
// [..]
while ((line = input.readLine()) != null)
    System.out.println(unexpand(line), 8);
//----------------------------------------------------------------------------------

Expanding Variables in User Input

//----------------------------------------------------------------------------------
// No interpolation in Java
//----------------------------------------------------------------------------------

Controlling Case

//----------------------------------------------------------------------------------
String big = little.toUpperCase(); // "bo peep" -> "BO PEEP"
String little = big.toLowerCase(); // "JOHN"    -> "john"
//----------------------------------------------------------------------------------
String big = little.substring(0, 1).toUpperCase() + little.substring(1);
// "bo"      -> "Bo"
String little = big.substring(0, 1).toLowerCase() + big.substring(1);
// "BoPeep" -> "boPeep"
//----------------------------------------------------------------------------------
String beast   = "dromedary";
// capitalize various parts of beast
String capit1   = beast.substring(0, 1).toUpperCase()
    + beast.substring(1).toLowerCase();
// Dromedary
String capit2   = Character.toUpperCase(beast.charAt(0))
    + beast.substring(1).toLowerCase();
// Dromedary
String capall   = beast.toUpperCase();
// DROMEDARY
String caprest1 = beast.substring(0, 1).toLowerCase()
    + beast.substring(1).toUpperCase();
// dROMEDARY
String caprest2 = Character.toLowerCase(beast.charAt(0))
    + beast.substring(1).toUpperCase();
// dROMEDARY
//----------------------------------------------------------------------------------
// capitalize each word's first character, downcase the rest
String text = "thIS is a loNG liNE";
StringTokenizer tokenizer = new StringTokenizer(text);
while (tokenizer.hasMoreTokens()) {
    String word = tokenizer.nextToken();
    System.out.print(word.substring(0, 1).toUpperCase() 
                   + word.substring(1).toLowerCase()
                   + " ");
    }
//=> This Is A Long Line
//----------------------------------------------------------------------------------
String a, b;
if (a.equalsIgnoreCase(b))
    System.out.println("a and b are the same");
//----------------------------------------------------------------------------------
private Random rand;
char randomCase(char ch) {
    return (rand.nextInt(100) < 20) ? Character.toLowerCase(ch): ch;
}
//----------------------------------------------------------------------------------

Interpolating Functions and Expressions Within Strings

//----------------------------------------------------------------------------------
// No interpolation in Java
//----------------------------------------------------------------------------------

Indenting Here Documents

//----------------------------------------------------------------------------------
// No here-document in Java
//----------------------------------------------------------------------------------

Reformatting Paragraphs

//----------------------------------------------------------------------------------
import java.text.BreakIterator();
BreakIterator boundary = BreakIterator.getLineInstance();
//----------------------------------------------------------------------------------
/**
 * WrapDemo.java
 */
package pleac.ch01.part12;

import java.text.BreakIterator;
/**
 * Show how BreakIterator works
 */
public class WrapDemo {

    private static BreakIterator iterator = BreakIterator.getLineInstance();

    public static void main(String[] args) {
        String input = "Folding and splicing is the work of an editor,"
                 + " not a mere collection of silicon"
                 + " and"
                 + " mobile electrons!";
        int column = 20;
        String leadTab = "    ";
        String nextTab = "  ";

        System.out.println("01234567890123456789");
        input = wrapLine(leadTab + input, column);
        while (input != null)
            input = wrapLine(nextTab + input, column);
    }

    private static String wrapLine(String line, int width) {
        iterator.setText(line);
        int end = iterator.first();
        while ((end != BreakIterator.DONE) && (end <= width))
            end = iterator.next();
        if (end == BreakIterator.DONE) {
            System.out.println(line);
            return null;
        } else {
            end = iterator.previous();
            System.out.println(line.substring(0, end));
            return line.substring(end);
        }
    }

}
//----------------------------------------------------------------------------------

Escaping Characters

//----------------------------------------------------------------------------------
Perl5Util util = new Perl5Util();
// backslash
var = util.substitute("s/([CHARLIST])/\\\\$1/g", var);

// double
var = util.substitute("s/([CHARLIST])/$1$1/g", var);
//----------------------------------------------------------------------------------
string = util.substitute("s/%/%%/g", string);
//----------------------------------------------------------------------------------
string = "Mom said, \"Don't do that.\"";
string = util.substitute("s/(['\"])/\\\\$1/g", string);
//----------------------------------------------------------------------------------
string = util.substitute("s/([^A-Z])/\\\\$1/g", string);
//----------------------------------------------------------------------------------

Trimming Blanks from the Ends of a String

//----------------------------------------------------------------------------------
string = string.trim();
//----------------------------------------------------------------------------------
// print what's typed, but surrounded by >< symbols
try {
    BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
    String line;
    while((line = input.readLine()) != null) {
        line = line.trim();
        System.out.println(">" + line + "<");
    }
} catch (IOException ex) {
    System.err.println("Exception occured: " + ex);
}
//----------------------------------------------------------------------------------

Parsing Comma-Separated Data

//----------------------------------------------------------------------------------
static final String PATTERN =
    "m/\"([^\\\"\\\\]*(?:\\\\.[^\\\"\\\\]*)*)\",? | ([^,]+),? | ,/x";
Perl5Util util = new Perl5Util();

Iterator parseCSV(String text) {
    ArrayList list = new ArrayList();
    while (util.match(PATTERN, text)) {
        // find which group matched
        if (util.group(1) != null)
            list.add(util.group(1));
        else if (util.group(2) != null)
            list.add(util.group(2));
        else
            list.add(null);
        // loop on post-match string
        text = util.postMatch();
       };
       return list.iterator();
}  
//----------------------------------------------------------------------------------
String line = 
    "XYZZY,\"\",\"O'Reilly, Inc\",\"Wall, Larry\",\"a \\\"glug\\\" bit,\",5,\"Error, Core Dumped\"";
Iterator it = parseCSV(line);
while (it.hasNext())
    System.out.println(count++ + " : " + it.next());

//=> 0 : XYZZY
//=> 1 :
//=> 2 : O'Reilly, Inc
//=> 3 : Wall, Larry
//=> 4 : a \"glug\" bit,
//=> 5 : 5
//=> 6 : Error, Core Dumped
//----------------------------------------------------------------------------------

Soundex Matching

//----------------------------------------------------------------------------------
// Sorry, no java soundex implementation found 
//----------------------------------------------------------------------------------

Program: fixstyle

//----------------------------------------------------------------------------------
/*
 * FixStyle.java
 */
package pleac.ch01.part17;

import java.io.*;
import java.util.*;
/**
 * Switch first set of strings from to second set according to STYLE_FILE
 * Usage: see derived classes
 */
public abstract class FixStyle {

    private static final String STYLE_FILE = "pleac/ch01/part17/style";
    private static final String BACKUP_SUFFIX = ".orig";
    private static final String VERBOSE_FLAG = "-v";

    Properties changes;

    FixStyle() {
        changes = new Properties();
        try {
            InputStream input =
                getClass().getClassLoader().getResourceAsStream(STYLE_FILE);
            changes.load(input);
        } catch (IOException ex) {
            System.err.println("Style loading failed: " + ex);
        }
    }

    void fix(String[] args) {
        if (args.length < 1) {
            System.out.println("usage: java " + getClass().getName()
                + " <file> [-v]");
            System.exit(1);
        }
        String file = args[0];
        boolean verbose = ((args.length > 1) && (args[1] != null)
            && (args[1].equals(VERBOSE_FLAG))) ? true: false;
        fixFile(file, verbose);
    }

    void fixFile(String file, boolean verbose) {
         try {
            BufferedReader input = new BufferedReader(new FileReader(file));
            BufferedWriter output =
                new BufferedWriter(new FileWriter(file + BACKUP_SUFFIX));
            String line;
            int count = 0;
            while ((line = input.readLine()) != null) {
                output.write(fixLine(line, ++count, verbose));
                output.newLine();
            }
            output.close();
        } catch (IOException ex) {
             System.err.println("Exception occured: " + ex);
        }
    }

    abstract String fixLine(String line, int count, boolean verbose);

}

/*
 * FixStyle1.java
 */
package pleac.ch01.part17;

import java.util.*;
import org.apache.oro.text.perl.Perl5Util;
/**
 * Fix style using substitutions
 * Usage: java pleac.ch01.part17.FixStyle1 <file> [-v]
 */
public class FixStyle1 extends FixStyle {

    private static Perl5Util util;

    FixStyle1() {
        util = new Perl5Util();
    }

    String fixLine(String line, int count, boolean verbose) {
        Enumeration enum = changes.propertyNames();
        while (enum.hasMoreElements()) {
            String oldWord = (String) enum.nextElement();
            if (util.match("/" + oldWord + "/", line)) {
                String newWord = changes.getProperty(oldWord);
                if (verbose)
                    System.out.println("substituting " + newWord + " to "
                        + oldWord + " in line " + count);
                line = util.substitute("s/" + oldWord + "/" + newWord + "/g", line);
            }
        }
        return line;
    }

    public static void main(String[] args) {
        FixStyle fixer = new FixStyle1();
        fixer.fix(args);
    }

}

/*
 * FixStyle2.java
 */
package pleac.ch01.part17;

import java.util.*;
import java.text.BreakIterator;
/**
 * Fix style using a break iterator
 * Usage: java pleac.ch01.part17.FixStyle2 <file> [-v]
 */  
public class FixStyle2 extends FixStyle {

    private BreakIterator iterator;

    FixStyle2() {
        iterator = BreakIterator.getWordInstance();
    }

    String fixLine(String line, int count, boolean verbose) {
        // use a mutable string buffer to performs string modifications
        StringBuffer buffer = new StringBuffer(line);
        // use a break iterator to performs initial string analysis
        iterator.setText(line);
        // and keep track of offset between them
        int offset = 0;

        int start = iterator.first();
        int end = iterator.first();
        while ((end = iterator.next()) != BreakIterator.DONE) {
            String oldWord = line.substring(start, end);
            if (changes.containsKey(oldWord)) {
                String newWord = changes.getProperty(oldWord);
                if (verbose)
                    System.out.println("substituting " + newWord + " to "
                        + oldWord + " in line " + count);
                buffer.replace(start + offset, end + offset, newWord);
                offset += newWord.length() - oldWord.length();
            }
            start = end;
        }
        return buffer.toString();
    }

    public static void main(String[] args) {
        FixStyle fixer = new FixStyle2();
        fixer.fix(args);
    }

}
//----------------------------------------------------------------------------------

Program: psgrep

//----------------------------------------------------------------------------------
// To do...
// @@INCOMPLETE@@
// @@INCOMPLETE@@
//----------------------------------------------------------------------------------