How do I breaks a text or sentence into words?

At first it might look simple. We can just split the text using the String.split(), the word is splitted using space. But what if a word ends with questions marks (?) or exclamation marks (!) instead? There might be some other rules that we also need to care.

Using the java.text.BreakIterator makes it much simpler. The class’s getWordInstance() factory method creates a BreakIterator instance for words break. Instantiating a BreakIterator and passing a locale information makes the iterator to breaks the text or sentence according the rule of the locale. This is really helpful when we are working with a complex language such as Japanese or Chinese.

Let us see an example of using the BreakIterator below.

package org.kodejava.example.text;

import java.text.BreakIterator;
import java.util.Locale;

public class BreakIteratorExample {
    public static void main(String[] args) {
        String data = "The quick brown fox jumps over the lazy dog.";
        String search = "dog";

        //
        // Gets an instance of BreakIterator for word break for the
        // given locale. We can instantiate a BreakIterator without
        // specifying the locale. The locale is important when we
        // are working with languages like Japanese or Chinese where
        // the breaks standard may be different compared to English.
        //
        BreakIterator bi = BreakIterator.getWordInstance(Locale.US);

        //
        // Set the text string to be scanned.
        //
        bi.setText(data);

        //
        // Iterates the boundary / breaks
        //
        System.out.println("Iterates each word: ");
        int count = 0;
        int lastIndex = bi.first();
        while (lastIndex != BreakIterator.DONE) {
            int firstIndex = lastIndex;
            lastIndex = bi.next();

            if (lastIndex != BreakIterator.DONE
                    && Character.isLetterOrDigit(
                    data.charAt(firstIndex))) {
                String word = data.substring(firstIndex, lastIndex);
                System.out.println("'" + word + "' found at (" +
                        firstIndex + ", " + lastIndex + ")");

                //
                // Counts how many times the word dog occurs.
                //
                if (word.equalsIgnoreCase(search)) {
                    count++;
                }
            }
        }

        System.out.println("");
        System.out.println("Number of word '" + search +
                "' found = " + count);
    }
}

Here are the program output:

Iterates each word: 
'The' found at (0, 3)
'quick' found at (4, 9)
'brown' found at (10, 15)
'fox' found at (16, 19)
'jumps' found at (20, 25)
'over' found at (26, 30)
'the' found at (31, 34)
'lazy' found at (35, 39)
'dog' found at (40, 43)

Number of word 'dog' found = 1

How do I sort strings data using CollationKey class?

When the strings must be compared multiple times, for example when sorting a list of strings. It’s more efficient to use CollationKey class. Using CollationKey to compare strings is generally faster than using Collator.compare().

You can not create CollationKey directly. Rather, generate them by calling Collator.getCollationKey() method. You can only compare CollationKey generated from the same Collator object.

package org.kodejava.example.text;

import java.text.CollationKey;
import java.text.Collator;
import java.util.Arrays;
import java.util.Collections;

public class CollationKeyExample {
    public static void main(String[] args) {
        String[] countries = {
                "German",
                "United Kingdom",
                "United States",
                "French",
                "Japan",
                "Myanmar",
                "India"
        };

        System.out.println("original:");
        System.out.println(Arrays.toString(countries));

        //
        // Gets Collator object of default locale
        //
        Collator collator = Collator.getInstance();

        //
        // Creates and initializes CollationKey array
        //
        CollationKey[] keys = new CollationKey[countries.length];

        for (int i = 0; i < countries.length; i++) {
            //
            // Generate CollationKey by calling
            // Collator.getCollationKey() method then assign into
            // keys which is an array of CollationKey.
            //
            // The CollationKey for the given String based on the 
            // Collator's collation rules.
            //
            keys[i] = collator.getCollationKey(countries[i]);
        }

        //
        // Sort the keys array
        //
        Collections.sort(Arrays.asList(keys));

        //
        // Print out the sorted array
        //
        System.out.println("sorted result: ");
        StringBuilder sb = new StringBuilder("[");
        for (CollationKey key : keys) {
            sb.append(key.getSourceString()).append(",");
        }
        sb.deleteCharAt(sb.length() - 1).append("]");
        System.out.println(sb.toString());
    }
}

Below is the result of the program:

original:
[German, United Kingdom, United States, French, Japan, Myanmar, India]
sorted result: 
[French,German,India,Japan,Myanmar,United Kingdom,United States]

How do I sort an array of string data using RuleBasedCollator class?

We can use the java.text.Collator class to sort strings in language-specific order. Using the java.text.Collator class makes the string not just sorted by the ASCII code of their characters but it will follow the language natural order of the characters.

If the predefined collation rules do not meet your needs, you can design your own rules and assign them to a RuleBasedCollator object. Customized collation rules are contained in a String object that is passed to the RuleBasedCollator constructor.

package org.kodejava.example.text;

import java.text.Collator;
import java.text.ParseException;
import java.text.RuleBasedCollator;
import java.util.Arrays;
import java.util.Collections;

public class RuleBasedCollatorDemo {
    public static void main(String[] args) {
        String rule1 = ("< a < b < c");
        String rule2 = ("< c < b  < a");
        String rule3 = ("< c < a  < b");

        String words[] = {
                "apple",
                "banana",
                "carrot",
                "apricot",
                "blueberry",
                "cabbage"
        };

        try {
            RuleBasedCollator rb1 = new RuleBasedCollator(rule1);
            RuleBasedCollator rb2 = new RuleBasedCollator(rule2);
            RuleBasedCollator rb3 = new RuleBasedCollator(rule3);

            System.out.println("original: ");
            System.out.println(Arrays.toString(words));

            //
            // Sort based on rule1
            //
            Collections.sort(Arrays.asList(words), rb1);
            System.out.println("nrule: " + rb1.getRules());
            System.out.println(Arrays.toString(words));

            //
            // Sort based on rule2
            //
            Collections.sort(Arrays.asList(words), rb2);
            System.out.println("nrule: " + rb2.getRules());
            System.out.println(Arrays.toString(words));

            //
            // Sort based on rule3
            //
            Collections.sort(Arrays.asList(words), rb3);
            System.out.println("nrule: " + rb3.getRules());
            System.out.println(Arrays.toString(words));
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

Below is the result of sorting strings using a different RuleBasedCollator

original: 
[apple, banana, carrot, apricot, blueberry, cabbage]

rule: < a < b < c
[apple, apricot, banana, blueberry, cabbage, carrot]

rule: < c < b  < a
[cabbage, carrot, banana, blueberry, apple, apricot]

rule: < c < a  < b
[cabbage, carrot, apple, apricot, banana, blueberry]

How do I change the date format symbols for a specified locale?

package org.kodejava.example.text;

import java.text.DateFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class ChangeDateFormatSymbols {
    public static void main(String[] args) {
        Locale id = new Locale("in", "ID");
        String pattern = "EEEE, dd MMM yyyy";
        Date today = new Date();

        //
        // Gets formatted date specify by the given pattern for
        // Indonesian Locale no changes for default date format
        // is applied here.
        //
        SimpleDateFormat sdf = new SimpleDateFormat(pattern, id);
        String before = sdf.format(today);
        System.out.println("Before format change: " + before);

        //
        // Create a DateFormatSymbols object for Indonesian locale.
        //
        DateFormatSymbols dfs = new DateFormatSymbols(id);

        //
        // Gets String array of default format of weekdays.
        //
        String[] days = dfs.getWeekdays();
        String newDays[] = new String[days.length];
        for (int i = 0; i < days.length; i++) {
            //
            // For each day, apply toUpperCase() method to
            // capitalized it.
            //
            newDays[i] = days[i].toUpperCase();
        }

        //
        // Set String array of weekdays.
        //
        dfs.setWeekdays(newDays);

        //
        // Gets String array of default format of short months.
        //
        String[] shortMonths = dfs.getShortMonths();
        String months[] = new String[shortMonths.length];
        for (int j = 0; j < shortMonths.length; j++) {
            //
            // For each short month, apply toUpperCase() method
            // to capitalized it.
            //
            months[j] = shortMonths[j].toUpperCase();
        }

        //
        // Set String array of short months.
        //
        dfs.setShortMonths(months);

        //
        // Create a SimpleDateFormat object by given pattern and 
        // symbol and then format the date object as String.
        //
        sdf = new SimpleDateFormat(pattern, dfs);
        String after = sdf.format(today);
        System.out.println("After change format : " + after);
    }
}

Here are the output of our program:

Before format change: Jumat, 10 Sep 2010
After change format : JUMAT, 10 SEP 2010

How do I get a formatted date for a specific pattern and locale?

If you want to change formatting styles provided by DateFormat, you can uses SimpleDateFormat class. The SimpleDateFormat class is locale-sensitive.

If you instantiate SimpleDateFormat without a Locale parameter, it will format the date and time according to the default Locale. Both the pattern and the Locale determine the format. For the same pattern, SimpleDateFormat may format a date and time differently if the Locale varies.

package org.kodejava.example.text;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class SimpleDateFormatChangeLocalePattern {
    public static void main(String[] args) {
        String pattern = "dd-MMM-yyyy";
        Date today = new Date();

        //
        // Gets a formatted date according to the given pattern.
        // Here only the pattern is passed as argument of the
        // SimpleDateFormat constructor, so it will format the
        // date according to the default Locale.
        //
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        String local = sdf.format(today);
        System.out.println("Date in default locale: " + local);

        Locale[] locales = {
                Locale.CANADA,
                Locale.FRANCE,
                Locale.GERMANY,
                Locale.US,
                Locale.JAPAN
        };

        for (Locale locale : locales) {
            //
            // Format a date according to the given pattern for each
            // locale.
            //
            sdf = new SimpleDateFormat(pattern, locale);
            String after = sdf.format(today);
            System.out.println(locale.getDisplayCountry() + 
                    " | format: " + after);
        }
    }
}

Here are the variety of output produces when formatting a date in the same date pattern but varies in Locale

Date in default locale: 10-Sep-2010
Canada			 | format: 10-Sep-2010
France			 | format: 10-sept.-2010
Germany			 | format: 10-Sep-2010
United States			 | format: 10-Sep-2010
Japan			 | format: 10-9-2010