Pages

Thursday, June 4, 2009

Java Unicode Regex

Working on an internationalized application has it's challenges. As we accept data from each country we need to validate the inputs. Regex is a great tool for this and Java's ability to do unicode regex is excellent.

Here are some details. Java takes the POSIX concept from Perl and groups unicode characters together based on purpose. Here are some of the base groups.

Numbers
\\p{N}
Alpha characters (all languages)
\\p{L}
Symbol characters (all languages)
\\p{S}
Punctuation characters (all languages)
\\p{P}
Spacing characters (all languages)
\\p{Z}
Mark characters (all languages)
\\p{M}

You can also use the '\\P' to xor the condition. So \\P{N} means not numbers.

These groups also have sub groups, for example \\p{Lu} would represent Uppercase letters. Lowercase would be \\p{Ll}

Java also has some flags that control the evaluation of the regex. I use the following flags when I create my pattern.
Pattern.CANON_EQ          This allows the regex to accept a suitable substitute char, for example a for à.
Pattern.CASE_INSENSITIVE  This allows the regex to ignore case
Pattern.UNICODE_CASE      This allows the regex to ignore unicode case.

Below is a code snippet showing how to use these for AlphaNumeric, Numeric and Alpha.
/**
* A regex for valid UTF-8 characters.
*
* Numbers  and notNumbers
*    \\p{N}           \\P{N}
* Alpha characters (all languages)
*    \\p{A}
* Symbol characters (all languages)
*    \\p{S}
* Punctuation characters (all languages)
*    \\p{P}
* Spacing characters (all languages)
*    \\p{Z}
* Mark characters (all languages)
*    \\p{M}
*/
private static final String ALPHANUMERIC_CHARS = "[\\p{N}\\p{P}\\p{Z}\\p{L}\\p{M}*]+";
private static final String NUMERIC_CHARS = "[\\p{N}*]+";
private static final String ALPHA_CHARS = "^[\\p{L}*]+";

/**
* Tests for alphanumeric characters in the string.  This also allows comma, period, space, dash and ampersand.
* @param testString
* @return
*/
private Boolean isAlphaNumeric(String testString) {       
Pattern p = Pattern.compile(ALPHANUMERIC_CHARS, Pattern.CANON_EQ |
Pattern.CASE_INSENSITIVE |
Pattern.UNICODE_CASE);
Matcher m = p.matcher(testString);
return m.matches();
}

/**
* Tests to make sure only alpha characters are in the string.
* @param testString
* @return
*/
private Boolean isAlpha(String testString) {
Pattern p = Pattern.compile(ALPHA_CHARS, Pattern.CANON_EQ |
Pattern.CASE_INSENSITIVE |
Pattern.UNICODE_CASE);
Matcher m = p.matcher(testString);
return m.matches();           
}

Note: With in the code the regex is java escaped. If you are testing this in a regex tester the regex would look like this:
[\p{N}\p{P}\p{Z}\p{L}\p{M}*]+

Excellent resources on this are here http://icu-project.org/docs/papers/iuc26_regexp.pdf
and here http://www.regular-expressions.info/unicode.html

No comments:

Post a Comment