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();
 | 
						|
    }
 | 
						|
*/
 | 
						|
 | 
						|
}
 |