mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			363 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			363 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* gnu/regexp/REMatch.java
 | |
|    Copyright (C) 2006 Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of GNU Classpath.
 | |
| 
 | |
| GNU Classpath is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation; either version 2, or (at your option)
 | |
| any later version.
 | |
| 
 | |
| GNU Classpath 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
 | |
| General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with GNU Classpath; see the file COPYING.  If not, write to the
 | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | |
| 02110-1301 USA.
 | |
| 
 | |
| Linking this library statically or dynamically with other modules is
 | |
| making a combined work based on this library.  Thus, the terms and
 | |
| conditions of the GNU General Public License cover the whole
 | |
| combination.
 | |
| 
 | |
| As a special exception, the copyright holders of this library give you
 | |
| permission to link this library with independent modules to produce an
 | |
| executable, regardless of the license terms of these independent
 | |
| modules, and to copy and distribute the resulting executable under
 | |
| terms of your choice, provided that you also meet, for each linked
 | |
| independent module, the terms and conditions of the license of that
 | |
| module.  An independent module is a module which is not derived from
 | |
| or based on this library.  If you modify this library, you may extend
 | |
| this exception to your version of the library, but you are not
 | |
| obligated to do so.  If you do not wish to do so, delete this
 | |
| exception statement from your version. */
 | |
| 
 | |
| 
 | |
| package gnu.java.util.regex;
 | |
| 
 | |
| import gnu.java.lang.CPStringBuilder;
 | |
| 
 | |
| import java.io.Serializable;
 | |
| 
 | |
| /**
 | |
|  * An instance of this class represents a match
 | |
|  * completed by a gnu.regexp matching function. It can be used
 | |
|  * to obtain relevant information about the location of a match
 | |
|  * or submatch.
 | |
|  *
 | |
|  * @author <A HREF="mailto:wes@cacas.org">Wes Biggs</A>
 | |
|  */
 | |
| public final class REMatch implements Serializable, Cloneable
 | |
| {
 | |
|   private String matchedText;
 | |
|   private CharIndexed matchedCharIndexed;
 | |
| 
 | |
|   // These variables are package scope for fast access within the engine
 | |
|   int eflags;                   // execution flags this match was made using
 | |
| 
 | |
|   // Offset in source text where match was tried.  This is zero-based;
 | |
|   // the actual position in the source text is given by (offset + anchor).
 | |
|   int offset;
 | |
| 
 | |
|   // Anchor position refers to the index into the source input
 | |
|   // at which the matching operation began.
 | |
|   // This is also useful for the ANCHORINDEX option.
 | |
|   int anchor;
 | |
| 
 | |
|   // Package scope; used by RE.
 | |
|   int index;                    // used while matching to mark current match position in input
 | |
|   // start1[i] is set when the i-th subexp starts. And start1[i] is copied
 | |
|   // to start[i] when the i-th subexp ends.  So start[i] keeps the previously
 | |
|   // assigned value while the i-th subexp is being processed. This makes
 | |
|   // backreference to the i-th subexp within the i-th subexp possible.
 | |
|   int[] start;                  // start positions (relative to offset) for each (sub)exp.
 | |
|   int[] start1;                 // start positions (relative to offset) for each (sub)exp.
 | |
|   int[] end;                    // end positions for the same
 | |
|   // start[i] == -1 or end[i] == -1 means that the start/end position is void.
 | |
|   // start[i] == p or end[i] == p where p < 0 and p != -1 means that
 | |
|   // the actual start/end position is (p+1). Start/end positions may
 | |
|   // become negative when the subexpression is in a RETokenLookBehind.
 | |
|   boolean empty;                // empty string matched. This flag is used only within
 | |
|   // RETokenRepeated.
 | |
| 
 | |
|   BacktrackStack backtrackStack;
 | |
| 
 | |
|   public Object clone ()
 | |
|   {
 | |
|     try
 | |
|     {
 | |
|       REMatch copy = (REMatch) super.clone ();
 | |
| 
 | |
|         copy.start = (int[]) start.clone ();
 | |
|         copy.start1 = (int[]) start1.clone ();
 | |
|         copy.end = (int[]) end.clone ();
 | |
| 
 | |
|         return copy;
 | |
|     }
 | |
|     catch (CloneNotSupportedException e)
 | |
|     {
 | |
|       throw new Error ();       // doesn't happen
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   void assignFrom (REMatch other)
 | |
|   {
 | |
|     start = other.start;
 | |
|     start1 = other.start1;
 | |
|     end = other.end;
 | |
|     index = other.index;
 | |
|     backtrackStack = other.backtrackStack;
 | |
|   }
 | |
| 
 | |
|   REMatch (int subs, int anchor, int eflags)
 | |
|   {
 | |
|     start = new int[subs + 1];
 | |
|     start1 = new int[subs + 1];
 | |
|     end = new int[subs + 1];
 | |
|     this.anchor = anchor;
 | |
|     this.eflags = eflags;
 | |
|     clear (anchor);
 | |
|   }
 | |
| 
 | |
|   void finish (CharIndexed text)
 | |
|   {
 | |
|     start[0] = 0;
 | |
|     CPStringBuilder sb = new CPStringBuilder ();
 | |
|     int i;
 | |
|     for (i = 0; i < end[0]; i++)
 | |
|       sb.append (text.charAt (i));
 | |
|     matchedText = sb.toString ();
 | |
|     matchedCharIndexed = text;
 | |
|     for (i = 0; i < start.length; i++)
 | |
|       {
 | |
|         // If any subexpressions didn't terminate, they don't count
 | |
|         // TODO check if this code ever gets hit
 | |
|         if ((start[i] == -1) ^ (end[i] == -1))
 | |
|           {
 | |
|             start[i] = -1;
 | |
|             end[i] = -1;
 | |
|           }
 | |
|       }
 | |
|     backtrackStack = null;
 | |
|   }
 | |
| 
 | |
|     /** Clears the current match and moves the offset to the new index. */
 | |
|   void clear (int index)
 | |
|   {
 | |
|     offset = index;
 | |
|     this.index = 0;
 | |
|     for (int i = 0; i < start.length; i++)
 | |
|       {
 | |
|         start[i] = start1[i] = end[i] = -1;
 | |
|       }
 | |
|     backtrackStack = null;
 | |
|   }
 | |
| 
 | |
|     /**
 | |
|      * Returns the string matching the pattern.  This makes it convenient
 | |
|      * to write code like the following:
 | |
|      * <P>
 | |
|      * <code>
 | |
|      * REMatch myMatch = myExpression.getMatch(myString);<br>
 | |
|      * if (myMatch != null) System.out.println("Regexp found: "+myMatch);
 | |
|      * </code>
 | |
|      */
 | |
|   public String toString ()
 | |
|   {
 | |
|     return matchedText;
 | |
|   }
 | |
| 
 | |
|     /**
 | |
|      * Returns the index within the input text where the match in its entirety
 | |
|      * began.
 | |
|      */
 | |
|   public int getStartIndex ()
 | |
|   {
 | |
|     return offset + start[0];
 | |
|   }
 | |
| 
 | |
|     /**
 | |
|      * Returns the index within the input string where the match in
 | |
|      * its entirety ends.  The return value is the next position after
 | |
|      * the end of the string; therefore, a match created by the
 | |
|      * following call:
 | |
|      *
 | |
|      * <P>
 | |
|      * <code>REMatch myMatch = myExpression.getMatch(myString);</code>
 | |
|      * <P>
 | |
|      * can be viewed (given that myMatch is not null) by creating
 | |
|      * <P>
 | |
|      * <code>String theMatch = myString.substring(myMatch.getStartIndex(),
 | |
|      * myMatch.getEndIndex());</code>
 | |
|      * <P>
 | |
|      * But you can save yourself that work, since the <code>toString()</code>
 | |
|      * method (above) does exactly that for you.
 | |
|      */
 | |
|   public int getEndIndex ()
 | |
|   {
 | |
|     return offset + end[0];
 | |
|   }
 | |
| 
 | |
|     /**
 | |
|      * Returns the string matching the given subexpression.  The subexpressions
 | |
|      * are indexed starting with one, not zero.  That is, the subexpression
 | |
|      * identified by the first set of parentheses in a regular expression
 | |
|      * could be retrieved from an REMatch by calling match.toString(1).
 | |
|      *
 | |
|      * @param sub Index of the subexpression.
 | |
|      */
 | |
|   public String toString (int sub)
 | |
|   {
 | |
|     if ((sub >= start.length) || sub < 0)
 | |
|       throw new IndexOutOfBoundsException ("No group " + sub);
 | |
|     if (start[sub] == -1)
 | |
|       return null;
 | |
|     if (start[sub] >= 0 && end[sub] <= matchedText.length ())
 | |
|       return (matchedText.substring (start[sub], end[sub]));
 | |
|     else
 | |
|       {
 | |
|         // This case occurs with RETokenLookAhead or RETokenLookBehind.
 | |
|         CPStringBuilder sb = new CPStringBuilder ();
 | |
|         int s = start[sub];
 | |
|         int e = end[sub];
 | |
|         if (s < 0)
 | |
|           s += 1;
 | |
|         if (e < 0)
 | |
|           e += 1;
 | |
|         for (int i = start[0] + s; i < start[0] + e; i++)
 | |
|           sb.append (matchedCharIndexed.charAt (i));
 | |
|         return sb.toString ();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|     /**
 | |
|      * Returns the index within the input string used to generate this match
 | |
|      * where subexpression number <i>sub</i> begins, or <code>-1</code> if
 | |
|      * the subexpression does not exist.  The initial position is zero.
 | |
|      *
 | |
|      * @param sub Subexpression index
 | |
|      * @deprecated Use getStartIndex(int) instead.
 | |
|      */
 | |
|   public int getSubStartIndex (int sub)
 | |
|   {
 | |
|     if (sub >= start.length)
 | |
|       return -1;
 | |
|     int x = start[sub];
 | |
|     return (x == -1) ? x : (x >= 0) ? offset + x : offset + x + 1;
 | |
|   }
 | |
| 
 | |
|     /**
 | |
|      * Returns the index within the input string used to generate this match
 | |
|      * where subexpression number <i>sub</i> begins, or <code>-1</code> if
 | |
|      * the subexpression does not exist.  The initial position is zero.
 | |
|      *
 | |
|      * @param sub Subexpression index
 | |
|      * @since gnu.regexp 1.1.0
 | |
|      */
 | |
|   public int getStartIndex (int sub)
 | |
|   {
 | |
|     if (sub >= start.length)
 | |
|       return -1;
 | |
|     int x = start[sub];
 | |
|     return (x == -1) ? x : (x >= 0) ? offset + x : offset + x + 1;
 | |
|   }
 | |
| 
 | |
|     /**
 | |
|      * Returns the index within the input string used to generate this match
 | |
|      * where subexpression number <i>sub</i> ends, or <code>-1</code> if
 | |
|      * the subexpression does not exist.  The initial position is zero.
 | |
|      *
 | |
|      * @param sub Subexpression index
 | |
|      * @deprecated Use getEndIndex(int) instead
 | |
|      */
 | |
|   public int getSubEndIndex (int sub)
 | |
|   {
 | |
|     if (sub >= start.length)
 | |
|       return -1;
 | |
|     int x = end[sub];
 | |
|     return (x == -1) ? x : (x >= 0) ? offset + x : offset + x + 1;
 | |
|   }
 | |
| 
 | |
|     /**
 | |
|      * Returns the index within the input string used to generate this match
 | |
|      * where subexpression number <i>sub</i> ends, or <code>-1</code> if
 | |
|      * the subexpression does not exist.  The initial position is zero.
 | |
|      *
 | |
|      * @param sub Subexpression index
 | |
|      */
 | |
|   public int getEndIndex (int sub)
 | |
|   {
 | |
|     if (sub >= start.length)
 | |
|       return -1;
 | |
|     int x = end[sub];
 | |
|     return (x == -1) ? x : (x >= 0) ? offset + x : offset + x + 1;
 | |
|   }
 | |
| 
 | |
|     /**
 | |
|      * Substitute the results of this match to create a new string.
 | |
|      * This is patterned after PERL, so the tokens to watch out for are
 | |
|      * <code>$0</code> through <code>$9</code>.  <code>$0</code> matches
 | |
|      * the full substring matched; <code>$<i>n</i></code> matches
 | |
|      * subexpression number <i>n</i>.
 | |
|      * <code>$10, $11, ...</code> may match the 10th, 11th, ... subexpressions
 | |
|      * if such subexpressions exist.
 | |
|      *
 | |
|      * @param input A string consisting of literals and <code>$<i>n</i></code> tokens.
 | |
|      */
 | |
|   public String substituteInto (String input)
 | |
|   {
 | |
|     // a la Perl, $0 is whole thing, $1 - $9 are subexpressions
 | |
|     CPStringBuilder output = new CPStringBuilder ();
 | |
|     int pos;
 | |
|     for (pos = 0; pos < input.length () - 1; pos++)
 | |
|       {
 | |
|         if ((input.charAt (pos) == '$')
 | |
|             && (Character.isDigit (input.charAt (pos + 1))))
 | |
|           {
 | |
|             int val = Character.digit (input.charAt (++pos), 10);
 | |
|             int pos1 = pos + 1;
 | |
|             while (pos1 < input.length () &&
 | |
|                    Character.isDigit (input.charAt (pos1)))
 | |
|               {
 | |
|                 int val1 =
 | |
|                   val * 10 + Character.digit (input.charAt (pos1), 10);
 | |
|                 if (val1 >= start.length)
 | |
|                   break;
 | |
|                 pos1++;
 | |
|                 val = val1;
 | |
|               }
 | |
|             pos = pos1 - 1;
 | |
| 
 | |
|             if (val < start.length)
 | |
|               {
 | |
|                 output.append (toString (val));
 | |
|               }
 | |
|           }
 | |
|         else
 | |
|           output.append (input.charAt (pos));
 | |
|       }
 | |
|     if (pos < input.length ())
 | |
|       output.append (input.charAt (pos));
 | |
|     return output.toString ();
 | |
|   }
 | |
| 
 | |
| /*  The following are used for debugging purpose
 | |
|     public static String d(REMatch m) {
 | |
|         if (m == null) return "null";
 | |
|         else return "[" + m.index + "]";
 | |
|     }
 | |
| 
 | |
|     public String substringUptoIndex(CharIndexed input) {
 | |
|         StringBuffer sb = new StringBuffer();
 | |
|         for (int i = 0; i < index; i++) {
 | |
|             sb.append(input.charAt(i));
 | |
|         }
 | |
|         return sb.toString();
 | |
|     }
 | |
| */
 | |
| 
 | |
| }
 |