Emax Emax - 13 days ago 5
Java Question

Java, string matching for validating permissions

Hi i'm working on an algorithm for validating permissions,
a permission is defined by a succession of token concatenated by a period,
for example:

this.is.a.permission
a.b.c.d
another.permission


permission can also contains special tokens listed below:




Asterisk:

magicFunction("this.is.a.permission", "this.is.*") // <-- return true
magicFunction("this.is.a.permission", "*") // <-- return true
magicFunction("this.is.a.permission", "random.*") // <-- return false



The asterisk validate only his token and all the next


Question Mark:

magicFunction("this.is.a.permission", "this.is.?.permission") // <-- return true
magicFunction("this.is.a.permission", "?.is.a.permission") // <-- return true
magicFunction("this.is.a.permission", "this.?.wrong") // <-- return false



The question mark validate only his token


Inclusive List:

magicFunction("this.is.a.permission", "this.is.[a,permission,c].permission") // <-- return true
magicFunction("this.is.a.permission", "[this].is.a.[a,permission,c]") // <-- return true
magicFunction("this.is.a.permission", "this.[is,c,d].wrong") // <-- return false



The inclusive list validate token only if it's contained in itself, defined by [argument,argument1,argument2,...]


Exclusive List:

magicFunction("this.is.a.permission", "this.is.<b,c,d>.permission") // <-- return true
magicFunction("this.is.a.permission", "<everything>.is.a.<invalid>") // <-- return true
magicFunction("this.is.a.permission", "this.is.a.<permission,wrong>") // <-- return false



The exclusive list validate token only if it's not contained in itself, defined by <argument,argument1,argument2,...>





Here is a test case:

public class PermissionTest {

public static void main(String[] args) {

System.out.println(rightPad("PERMISSION", 35) + rightPad("PERMISSION EXPRESSION", 35) + "RESULT");

// ALL TRUE
assert magicFunction( "A.B.C", "A.B.C.D");
assert magicFunction( "A.B.C.D", "A.B.C.D");
assert magicFunction( "A.B.C.D", "A.B.*");
assert magicFunction( "A.B.C.D", "A.B.?.D");
assert magicFunction( "A.B.C.D", "A.B.C.[D,E,F]");
assert magicFunction( "A.B.C.E", "A.B.C.[D,E,F]");
assert magicFunction( "A.B.C.F", "A.<A,C>.C.[D,E,F]");
assert magicFunction( "A.B.C.D", "A.B.C.<A,B,C>");
assert magicFunction( "A.B.C.E", "A.B.C.<A,B,C>");
assert magicFunction( "A.B.C.F", "A.[B].C.<A,B,C>");

System.out.println();

// ALL FALSE
assert !magicFunction( "A.B.C", "A.B");
assert !magicFunction( "A.B.C.D", "A.B.?.E");
assert !magicFunction( "A.B.C.D", "A.D.*");
assert !magicFunction( "A.B.C.D", "A.B.?");
assert !magicFunction( "A.B.C.Q", "A.?.C.[D,E,F]");
assert !magicFunction( "A.B.C.W", "A.?.C.[D,E,F]");
assert !magicFunction( "A.B.C.E", "A.<B,D,E>.?.[D,E,F]");
assert !magicFunction( "A.B.C.A", "A.B.C.<A,B,C>");
assert !magicFunction( "A.B.C.B", "A.B.C.<A,B,C>");
assert !magicFunction( "A.B.C.C", "A.[D].C.<A,B,C>");
}

public static boolean magicFunction(String permission, String permissionExpression) {
boolean value = magicFunctionImplementation(permission, permissionExpression);
System.out.println(
rightPad(permissionExpression, 35) +
rightPad(permission, 35) +
value
);
return value;
}

/**
* The function implementation
*
* IMPLEMENT YOUR FUNCTION HERE
*/
public static boolean magicFunctionImplementation(String permission, String permisionExpression) {
return false;
}

/**
* For formatting purpose
*/
public static String rightPad(String pad, int size) {
String paddedString = pad;
for (int i = pad.length(); i < size; i++) {
paddedString += " ";
}
return paddedString;
}
}


Here is my final question is possible to write this function with a regular expression? if isn't possible there is a more elegant way to write this function?

Answer

I suggest using

public static boolean magicFunctionImplementation(String permission, String permissionExpression) {
    boolean res = false;
    String rx = permissionExpression.replace(".", "\\.") // escape the dot in regex
            .replace("*", ".*") // prep the * token to match any 0+ chars
            .replace("?", ".")  // . will match any 1 char
            .replaceAll("\\[([^\\]\\[]*)]", "($1)") // [a,b] => (a|b) = match a or b
            .replaceAll("<([^<>]+)>", "(?:(?!$1)[^.])*") // <a,b> => (?:(?!a|b).)* = match text that is not a starting point of a or b
            .replace(",", "|"); // replace all commas with alternation symbol (for the above 2 patterns)
    if (permissionExpression.contains(permission)) { // if permissionExpr contains permission, it is TRUE
        res = true;
    } else {
        res = permission.matches(rx); // Check if the entire permission matches the regex
    }
    return res;
}

See the Java demo

Comments