Author: julien_viet
Date: 2010-11-26 15:50:07 -0500 (Fri, 26 Nov 2010)
New Revision: 5302
Added:
portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/regexp/SubCharSequence.java
portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/regexp/TestSubCharSequence.java
Modified:
portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/regexp/Quantifier.java
portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/regexp/RegExpParser.java
portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/regexp/TestParser.java
Log:
- implement fully quantifier
- implement reluctant and possessive quantifier
- implement grouping
Modified:
portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/regexp/Quantifier.java
===================================================================
---
portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/regexp/Quantifier.java 2010-11-26
19:21:57 UTC (rev 5301)
+++
portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/regexp/Quantifier.java 2010-11-26
20:50:07 UTC (rev 5302)
@@ -23,41 +23,113 @@
* @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a>
* @version $Revision$
*/
-public abstract class Quantifier
+public class Quantifier
{
- private Quantifier()
+ public enum Mode
{
- }
- /** . */
- public static final Quantifier STAR = new Quantifier()
- {
- @Override
- public String toString()
+ GREEDY(""), RELUCTANT("?"), POSSESSIVE("+");
+
+ /** . */
+ private final String value;
+
+ Mode(String value)
{
- return "*";
+ this.value = value;
}
- };
+ }
/** . */
- public static final Quantifier PLUS = new Quantifier()
+ private final Mode mode;
+
+ /** . */
+ private final int min;
+
+ /** . */
+ private final Integer max;
+
+ protected Quantifier(Mode mode, int min, Integer max)
{
- @Override
- public String toString()
+ this.mode = mode;
+ this.min = min;
+ this.max = max;
+ }
+
+ public static Quantifier onceOrNotAtAll(Mode mode)
+ {
+ return new Quantifier(mode, 0, 1);
+ }
+
+ public static Quantifier zeroOrMore(Mode mode)
+ {
+ return new Quantifier(mode, 0, null);
+ }
+
+ public static Quantifier oneOrMore(Mode mode)
+ {
+ return new Quantifier(mode, 1, null);
+ }
+
+ public static Quantifier exactly(Mode mode, int value)
+ {
+ return new Quantifier(mode, value, value);
+ }
+
+ public static Quantifier atLeast(Mode mode, int value)
+ {
+ return new Quantifier(mode, value, null);
+ }
+
+ public static Quantifier between(Mode mode, int min, int max)
+ {
+ return new Quantifier(mode, min, max);
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (o == this)
{
- return "+";
+ return true;
}
- };
+ else if (o instanceof Quantifier)
+ {
+ Quantifier that = (Quantifier)o;
+ return mode == that.mode && min == that.min && (max == null ?
that.max == null : max.equals(that.max));
+ }
+ return false;
+ }
- /** . */
- public static final Quantifier QUESTION_MARK = new Quantifier()
+ @Override
+ public String toString()
{
- @Override
- public String toString()
+ if (min == 0)
{
- return "?";
+ if (max == null)
+ {
+ return "*" + mode.value;
+ }
+ else if (max == 1)
+ {
+ return "?" + mode.value;
+ }
}
- };
-
+ else if (min == 1 && max == null)
+ {
+ return "+" + mode.value;
+ }
+ if (max == null)
+ {
+ return "{" + min + ",}" + mode.value;
+ }
+ else if (min == max)
+ {
+ return "{" + min + "}" + mode.value;
+ }
+ else
+ {
+ return "{" + min + "," + max + "}" + mode.value;
+ }
+ }
}
Modified:
portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/regexp/RegExpParser.java
===================================================================
---
portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/regexp/RegExpParser.java 2010-11-26
19:21:57 UTC (rev 5301)
+++
portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/regexp/RegExpParser.java 2010-11-26
20:50:07 UTC (rev 5302)
@@ -21,6 +21,8 @@
import java.util.HashSet;
import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a>
@@ -41,6 +43,9 @@
}
/** . */
+ private static final Pattern pattern = Pattern.compile("^([0-9]+)" +
"(?:" + "(,)([0-9]+)?" + ")?$");
+
+ /** . */
private int index;
public RegExpParser(CharSequence s)
@@ -114,12 +119,12 @@
}
/**
- * expression -> assertion | '(' disjunction ')' | '('
'?' disjunction ')' | character | expression quantifier
- * assertion -> '^' | '$'
- * character -> '.' | escaped | character_class | literal
- * escaped -> '\' any char
- * quantifier -> '*' | '+' | '?' | '{' count
'}' | '{' count ',' '}' | '{' count ','
count '}'
- * literal -> todo
+ * expression -> assertion | '(' disjunction ')' | character
| expression quantifier
+ * assertion -> '^' | '$'
+ * character -> '.' | escaped | character_class | literal
+ * escaped -> '\' any char
+ * quantifier -> quantifier_prefix | quantifier_prefix ?
+ * quantifier_prefix -> '*' | '+' | '?' | '{' count
'}' | '{' count ',' '}' | '{' count ','
count '}'
*
* @return the expression
*/
@@ -215,16 +220,46 @@
{
case '*':
index++;
- return Quantifier.STAR;
+ return Quantifier.zeroOrMore(parseQuantifierMode());
case '+':
index++;
- return Quantifier.PLUS;
+ return Quantifier.oneOrMore(parseQuantifierMode());
case '?':
index++;
- return Quantifier.QUESTION_MARK;
+ return Quantifier.onceOrNotAtAll(parseQuantifierMode());
case '{':
index++;
- throw new UnsupportedOperationException();
+ int closingBrace = indexOf(index, '}', to);
+ if (closingBrace == -1)
+ {
+ throw new SyntaxException();
+ }
+ SubCharSequence sub = new SubCharSequence(s, index, closingBrace);
+ index = closingBrace + 1;
+ Matcher matcher = pattern.matcher(sub);
+ if (!matcher.matches())
+ {
+ throw new SyntaxException();
+ }
+ if (matcher.group(2) == null)
+ {
+ return Quantifier.exactly(
+ parseQuantifierMode(),
+ Integer.parseInt(matcher.group(1)));
+ }
+ else if (matcher.group(3) == null)
+ {
+ return Quantifier.atLeast(
+ parseQuantifierMode(),
+ Integer.parseInt(matcher.group(1)));
+ }
+ else
+ {
+ return Quantifier.between(
+ parseQuantifierMode(),
+ Integer.parseInt(matcher.group(1)),
+ Integer.parseInt(matcher.group(3)));
+ }
default:
return null;
}
@@ -235,6 +270,23 @@
}
}
+ private Quantifier.Mode parseQuantifierMode()
+ {
+ if (index < to)
+ {
+ switch (s.charAt(index))
+ {
+ case '?':
+ index++;
+ return Quantifier.Mode.RELUCTANT;
+ case '+':
+ index++;
+ return Quantifier.Mode.POSSESSIVE;
+ }
+ }
+ return Quantifier.Mode.GREEDY;
+ }
+
/**
* character_class -> '[' bracket_list ']' | '['
'^' bracket_list ']'
* bracket_term -> bracket_term | bracket_term bracket_term | bracket_term
'&' '&' bracket_term
Added:
portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/regexp/SubCharSequence.java
===================================================================
---
portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/regexp/SubCharSequence.java
(rev 0)
+++
portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/regexp/SubCharSequence.java 2010-11-26
20:50:07 UTC (rev 5302)
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+
+package org.exoplatform.web.controller.regexp;
+
+/**
+ * Should make it to org.gatein.common somehow.
+ *
+ * @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a>
+ * @version $Revision$
+ */
+public class SubCharSequence implements CharSequence
+{
+
+ /** . */
+ private final CharSequence s;
+
+ /** . */
+ private final int from;
+
+ /** . */
+ private final int to;
+
+ public SubCharSequence(CharSequence s, int from, int to)
+ {
+ if (s == null)
+ {
+ throw new NullPointerException("No null string accepted");
+ }
+ if (from < 0)
+ {
+ throw new IllegalArgumentException("No negative lower bound
accepted");
+ }
+ if (to > s.length())
+ {
+ throw new IllegalArgumentException("Upper bound cannot be greater than the
sequence length");
+ }
+ if (from > to)
+ {
+ throw new IllegalArgumentException("Upper bound cannot be lesser than the
lower bound");
+ }
+
+ //
+ this.s = s;
+ this.from = from;
+ this.to = to;
+ }
+
+ public int length()
+ {
+ return to - from;
+ }
+
+ public char charAt(int index)
+ {
+ if (index < 0)
+ {
+ throw new IndexOutOfBoundsException("Index cannot be negative");
+ }
+ index += from;
+ if (index >= to)
+ {
+ throw new IndexOutOfBoundsException("Index cannot be negative");
+ }
+ return s.charAt(index);
+ }
+
+ public CharSequence subSequence(int start, int end)
+ {
+ if (start < 0)
+ {
+ throw new IndexOutOfBoundsException("The start argument cannot be
negative");
+ }
+ if (end < 0)
+ {
+ throw new IndexOutOfBoundsException("The start argument cannot be
negative");
+ }
+ if (start > end)
+ {
+ throw new IndexOutOfBoundsException("The start argument cannot greater than
the end argument");
+ }
+ end += from;
+ if (end > to)
+ {
+ throw new IndexOutOfBoundsException("The end argument cannot greater than
the length");
+ }
+ return new SubCharSequence(s, from + start, end);
+ }
+
+ @Override
+ public String toString()
+ {
+ return s.subSequence(from, to).toString();
+ }
+}
Modified:
portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/regexp/TestParser.java
===================================================================
---
portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/regexp/TestParser.java 2010-11-26
19:21:57 UTC (rev 5301)
+++
portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/regexp/TestParser.java 2010-11-26
20:50:07 UTC (rev 5302)
@@ -100,18 +100,18 @@
}
return this;
}
- ParserTester assertParseEREDuplSymbol(Quantifier expectedQuantifier)
+ ParserTester assertParseQuantifier(int expectedIndex, Quantifier
expectedQuantifier)
{
int index = parser.getIndex();
if (expectedQuantifier != null)
{
assertEquals(expectedQuantifier, parser.parseQuantifierSymbol());
- assertEquals(index + 1, parser.getIndex());
+ assertEquals(expectedIndex, parser.getIndex());
}
else
{
assertNull(parser.parseQuantifierSymbol());
- assertEquals(index, parser.getIndex());
+ assertEquals(expectedIndex, parser.getIndex());
}
return this;
}
@@ -154,19 +154,28 @@
}
// missing stuff:
- // ()
- // +?
- // {0,2}
// escape in bracket
- public void testEREDuplSymbol()
+ public void testQuantifier()
{
- new ParserTester("*").assertParseEREDuplSymbol(Quantifier.STAR);
- new ParserTester("+").assertParseEREDuplSymbol(Quantifier.PLUS);
- new
ParserTester("?").assertParseEREDuplSymbol(Quantifier.QUESTION_MARK);
- new ParserTester("a").assertParseEREDuplSymbol(null);
- new ParserTester("").assertParseEREDuplSymbol(null);
+ new ParserTester("*").assertParseQuantifier(1,
Quantifier.zeroOrMore(Quantifier.Mode.GREEDY));
+ new ParserTester("+").assertParseQuantifier(1,
Quantifier.oneOrMore(Quantifier.Mode.GREEDY));
+ new ParserTester("?").assertParseQuantifier(1,
Quantifier.onceOrNotAtAll(Quantifier.Mode.GREEDY));
+ new ParserTester("*a").assertParseQuantifier(1,
Quantifier.zeroOrMore(Quantifier.Mode.GREEDY));
+ new ParserTester("+a").assertParseQuantifier(1,
Quantifier.oneOrMore(Quantifier.Mode.GREEDY));
+ new ParserTester("?a").assertParseQuantifier(1,
Quantifier.onceOrNotAtAll(Quantifier.Mode.GREEDY));
+ new ParserTester("*?").assertParseQuantifier(2,
Quantifier.zeroOrMore(Quantifier.Mode.RELUCTANT));
+ new ParserTester("+?").assertParseQuantifier(2,
Quantifier.oneOrMore(Quantifier.Mode.RELUCTANT));
+ new ParserTester("??").assertParseQuantifier(2,
Quantifier.onceOrNotAtAll(Quantifier.Mode.RELUCTANT));
+ new ParserTester("*+").assertParseQuantifier(2,
Quantifier.zeroOrMore(Quantifier.Mode.POSSESSIVE));
+ new ParserTester("++").assertParseQuantifier(2,
Quantifier.oneOrMore(Quantifier.Mode.POSSESSIVE));
+ new ParserTester("?+").assertParseQuantifier(2,
Quantifier.onceOrNotAtAll(Quantifier.Mode.POSSESSIVE));
+ new ParserTester("a").assertParseQuantifier(0, null);
+ new ParserTester("").assertParseQuantifier(0, null);
+ new ParserTester("{2}").assertParseQuantifier(3,
Quantifier.exactly(Quantifier.Mode.GREEDY, 2));
+ new ParserTester("{2,}").assertParseQuantifier(4,
Quantifier.atLeast(Quantifier.Mode.GREEDY, 2));
+ new ParserTester("{2,4}").assertParseQuantifier(5,
Quantifier.between(Quantifier.Mode.GREEDY, 2, 4));
}
public void testParseBracketExpression()
Added:
portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/regexp/TestSubCharSequence.java
===================================================================
---
portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/regexp/TestSubCharSequence.java
(rev 0)
+++
portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/regexp/TestSubCharSequence.java 2010-11-26
20:50:07 UTC (rev 5302)
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+
+package org.exoplatform.web.controller.regexp;
+
+import junit.framework.TestCase;
+
+/**
+ * @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a>
+ * @version $Revision$
+ */
+public class TestSubCharSequence extends TestCase
+{
+
+ private final CharSequence seq = new SubCharSequence("abcdef", 1, 5);
+
+ public void testState()
+ {
+ assertEquals(4, seq.length());
+ assertEquals('b', seq.charAt(0));
+ assertEquals('c', seq.charAt(1));
+ assertEquals('d', seq.charAt(2));
+ assertEquals('e', seq.charAt(3));
+ assertEquals("bcde", seq.toString());
+ }
+
+ public void testSubSequence()
+ {
+ CharSequence sub = seq.subSequence(1, 3);
+ assertEquals(2, sub.length());
+ assertEquals('c', sub.charAt(0));
+ assertEquals('d', sub.charAt(1));
+ assertEquals("cd", sub.toString());
+ }
+
+ public void testSubSequenceThrowsIOOBE()
+ {
+ assertSubSequenceThrowsIIOBE(-1, 3);
+ assertSubSequenceThrowsIIOBE(1, 5);
+ assertSubSequenceThrowsIIOBE(1, -1);
+ assertSubSequenceThrowsIIOBE(5, 1);
+ }
+
+ private void assertSubSequenceThrowsIIOBE(int start, int end)
+ {
+ try
+ {
+ seq.subSequence(start, end);
+ fail();
+ }
+ catch (IndexOutOfBoundsException e)
+ {
+ }
+ }
+
+ public void testCharAtThrowsIOOBE()
+ {
+ try
+ {
+ seq.charAt(-1);
+ fail();
+ }
+ catch (IndexOutOfBoundsException e)
+ {
+ }
+ try
+ {
+ seq.charAt(4);
+ fail();
+ }
+ catch (IndexOutOfBoundsException e)
+ {
+ }
+ }
+
+ public void testCtorThrowsNPE()
+ {
+ try
+ {
+ new SubCharSequence(null, 1, 5);
+ fail();
+ }
+ catch (NullPointerException e)
+ {
+ }
+ }
+
+ public void testCtorThrowsIAE()
+ {
+ assertCtorThrowsIAE("a", -1, 1);
+ assertCtorThrowsIAE("a", 0, 2);
+ assertCtorThrowsIAE("a", 1, 0);
+ }
+
+ private void assertCtorThrowsIAE(String s, int from, int to)
+ {
+ try
+ {
+ new SubCharSequence(s, from, to);
+ fail();
+ }
+ catch (IllegalArgumentException e)
+ {
+ }
+ }
+}