Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 44 additions & 26 deletions CodenameOne/src/com/codename1/util/regex/RECompiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,43 @@ int escape() throws RESyntaxException {
}
}

private int parsePosixCharacterClass(boolean nestedPosixClass) throws RESyntaxException {
// Skip colon
idx++;

// POSIX character classes are denoted with lowercase ASCII strings
int idxStart = idx;
while (idx < len && pattern.charAt(idx) >= 'a' && pattern.charAt(idx) <= 'z') {
idx++;
}

// Should be a ":]" to terminate the POSIX character class
if ((idx + 1) < len && pattern.charAt(idx) == ':' && pattern.charAt(idx + 1) == ']') {
// Get character class
String charClass = pattern.substring(idxStart, idx);

// Select the POSIX class id
Character i = (Character) hashPOSIX.get(charClass);
if (i != null) {
// Move past colon and right bracket
idx += 2;

// Nested POSIX class "[[:class:]]" consumes one more right bracket.
if (nestedPosixClass) {
if (idx >= len || pattern.charAt(idx) != ']') {
syntaxError("Invalid POSIX character class syntax");
}
idx++;
}

return node(RE.OP_POSIXCLASS, i.charValue());
}
syntaxError("Invalid POSIX character class '" + charClass + "'");
}
syntaxError("Invalid POSIX character class syntax");
return -1;
}

/// Compile a character class
///
/// #### Returns
Expand All @@ -447,34 +484,15 @@ int characterClass() throws RESyntaxException {
syntaxError("Empty or unterminated class");
}

// Check for POSIX character class
// Check for POSIX character class in the "[:class:]" form.
if (idx < len && pattern.charAt(idx) == ':') {
// Skip colon
idx++;

// POSIX character classes are denoted with lowercase ASCII strings
int idxStart = idx;
while (idx < len && pattern.charAt(idx) >= 'a' && pattern.charAt(idx) <= 'z') {
idx++;
}

// Should be a ":]" to terminate the POSIX character class
if ((idx + 1) < len && pattern.charAt(idx) == ':' && pattern.charAt(idx + 1) == ']') {
// Get character class
String charClass = pattern.substring(idxStart, idx);

// Select the POSIX class id
Character i = (Character) hashPOSIX.get(charClass);
if (i != null) {
// Move past colon and right bracket
idx += 2;
return parsePosixCharacterClass(false);
}

// Return new POSIX character class node
return node(RE.OP_POSIXCLASS, i.charValue());
}
syntaxError("Invalid POSIX character class '" + charClass + "'");
}
syntaxError("Invalid POSIX character class syntax");
// Check for POSIX character class in the "[[:class:]]" form.
if ((idx + 1) < len && pattern.charAt(idx) == '[' && pattern.charAt(idx + 1) == ':') {
idx++;
return parsePosixCharacterClass(true);
}

// Try to build a class. Create OP_ANYOF node
Expand Down
21 changes: 21 additions & 0 deletions Ports/CLDC11/src/java/lang/Character.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,27 @@ public int hashCode(){
return 0; //TODO codavaj!!
}

/**
* Determines if the specified character is alphabetic.
*/
public static boolean isAlpha(char ch){
return isLowerCase(ch) || isUpperCase(ch);
}

/**
* Determines if the specified character is numeric.
*/
public static boolean isNumeric(char ch){
return isDigit(ch);
}

/**
* Determines if the specified character is alphabetic or numeric.
*/
public static boolean isAlphaNumeric(char ch){
return isAlpha(ch) || isNumeric(ch);
}

/**
* Determines if the specified character is a digit.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,42 @@ void testSubstitutionWithBackReferences() throws Exception {
String[] split = expression.split(input);
assertArrayEquals(new String[]{"", " and "}, split);
}

@FormTest
void testNestedPosixAlphaCharacterClassSupport() throws Exception {
RE expression = new RE("^list [[:alpha:]]*$");

assertTrue(expression.match("list abcXYZ"));
assertTrue(expression.match("list "));
assertFalse(expression.match("list 123"));
assertFalse(expression.match("listing abc"));
}

@FormTest
void testLegacyPosixAlphaCharacterClassSupport() throws Exception {
RE expression = new RE("^list [:alpha:]*$");

assertTrue(expression.match("list alpha"));
assertFalse(expression.match("list alpha1"));
}

@FormTest
void testPosixClassesAndEscapes() throws Exception {
RE alnum = new RE("^[[:alnum:]]+$");
assertTrue(alnum.match("abc123"));
assertFalse(alnum.match("abc-123"));

RE digit = new RE("^[[:digit:]]+$");
assertTrue(digit.match("007"));
assertFalse(digit.match("7a"));

RE xdigit = new RE("^[[:xdigit:]]+$");
assertTrue(xdigit.match("a0B9F"));
assertFalse(xdigit.match("g0"));

RE wordThenDigits = new RE("^\\w+\\s+\\d+$");
assertTrue(wordThenDigits.match("item\t42"));
assertFalse(wordThenDigits.match("item-42"));
}

}
24 changes: 24 additions & 0 deletions vm/JavaAPI/src/java/lang/Character.java
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,30 @@ public int hashCode(){
return value;
}

public static boolean isAlpha(char ch) {
return isLetter(ch);
}

public static boolean isAlpha(int codePoint) {
return isLetter(codePoint);
}

public static boolean isNumeric(char ch) {
return isDigit(ch);
}

public static boolean isNumeric(int codePoint) {
return isDigit(codePoint);
}

public static boolean isAlphaNumeric(char ch) {
return isLetterOrDigit(ch);
}

public static boolean isAlphaNumeric(int codePoint) {
return isLetterOrDigit(codePoint);
}

public static boolean isLetterOrDigit(char ch) {
return isLetterOrDigit((int) ch);
}
Expand Down
Loading