[gatein-commits] gatein SVN: r5302 - in portal/branches/navcontroller/component/web/controller/src: test/java/org/exoplatform/web/controller/regexp and 1 other directory.

do-not-reply at jboss.org do-not-reply at jboss.org
Fri Nov 26 15:50:08 EST 2010


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 at 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 at 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 at 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 at 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)
+      {
+      }
+   }
+}



More information about the gatein-commits mailing list