cauchoregexpmodule.java

来自「RESIN 3.2 最新源码」· Java 代码 · 共 1,953 行 · 第 1/4 页

JAVA
1,953
字号
/* * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source 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 of the License, or * (at your option) any later version. * * Resin Open Source 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, or any warranty * of NON-INFRINGEMENT.  See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * *   Free Software Foundation, Inc. *   59 Temple Place, Suite 330 *   Boston, MA 02111-1307  USA * * @author Scott Ferguson */package com.caucho.quercus.lib.regexp;import com.caucho.quercus.QuercusException;import com.caucho.quercus.QuercusRuntimeException;import com.caucho.quercus.annotation.Optional;import com.caucho.quercus.annotation.Reference;import com.caucho.quercus.annotation.UsesSymbolTable;import com.caucho.quercus.env.*;import com.caucho.quercus.module.AbstractQuercusModule;import com.caucho.util.L10N;import com.caucho.util.LruCache;import java.io.IOException;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.logging.Level;import java.util.logging.Logger;public class CauchoRegexpModule  extends AbstractQuercusModule{  private static final Logger log =    Logger.getLogger(RegexpModule.class.getName());    private static final L10N L = new L10N(RegexpModule.class);  public static final int PREG_REPLACE_EVAL = 0x01;  public static final int PCRE_UTF8 = 0x02;  public static final int PREG_PATTERN_ORDER = 0x01;  public static final int PREG_SET_ORDER = 0x02;  public static final int PREG_OFFSET_CAPTURE = 0x04;  public static final int PREG_SPLIT_NO_EMPTY = 0x01;  public static final int PREG_SPLIT_DELIM_CAPTURE = 0x02;  public static final int PREG_SPLIT_OFFSET_CAPTURE = 0x04;  public static final int PREG_GREP_INVERT = 1;  // #2526, possible JIT/OS problem with max comparison  private static final long LONG_MAX = Long.MAX_VALUE - 1;  public static final boolean [] PREG_QUOTE = new boolean[256];  private static final LruCache<StringValue, Regexp> _regexpCache  = new LruCache<StringValue, Regexp>(1024);  private static final LruCache<StringValue, ArrayList<Replacement>> _replacementCache  = new LruCache<StringValue, ArrayList<Replacement>>(1024);  private static final HashMap<String, Value> _constMap  = new HashMap<String, Value>();  @Override  public String []getLoadedExtensions()  {    return new String[] { "pcre" };  }  /**   * Returns the index of the first match.   *   * @param env the calling environment   */  public static Value ereg(Env env,          Value pattern,          StringValue string,          @Optional @Reference Value regsV)  {    return eregImpl(env, pattern, string, regsV, false);  }  /**   * Returns the index of the first match.   *   * @param env the calling environment   */  public static Value eregi(Env env,          Value pattern,          StringValue string,          @Optional @Reference Value regsV)  {    return eregImpl(env, pattern, string, regsV, true);  }  /**   * Returns the index of the first match.   *   * @param env the calling environment   */  protected static Value eregImpl(Env env,                                  Value rawPattern,                                  StringValue string,                                  Value regsV,                                  boolean isCaseInsensitive)  {    // php/1511 : error when pattern argument is null or an empty string    if (rawPattern.length() == 0) {      env.warning(L.l("empty pattern argument"));      return BooleanValue.FALSE;    }    // php/1512 : non-string pattern argument is converted to    // an integer value and formatted as a string.    StringValue rawPatternStr;    if (! (rawPattern instanceof StringValue)) {      rawPatternStr = rawPattern.toLongValue().toStringValue();    } else {      rawPatternStr = rawPattern.toStringValue();    }    StringValue cleanPattern = cleanEregRegexp(env, rawPatternStr, false);    if (isCaseInsensitive)      cleanPattern = addDelimiters(env, cleanPattern, "/", "/i");    else      cleanPattern = addDelimiters(env, cleanPattern, "/", "/");    try {      Regexp regexp = getRegexp(env, cleanPattern);      RegexpState regexpState = new RegexpState(env, regexp, string);      if (! regexpState.find())        return BooleanValue.FALSE;      if (regsV != null && ! (regsV instanceof NullValue)) {        ArrayValue regs = new ArrayValueImpl();        regsV.set(regs);        regs.put(LongValue.ZERO, regexpState.group(env));        int count = regexpState.groupCount();        for (int i = 1; i < count; i++) {          StringValue group = regexpState.group(env, i);          Value value;          if (group == null || group.length() == 0)            value = BooleanValue.FALSE;          else            value = group;          regs.put(new LongValue(i), value);        }        int len = regexpState.end() - regexpState.start();        if (len == 0)          return LongValue.ONE;        else          return new LongValue(len);      }      else {        return LongValue.ONE;      }    } catch (IllegalRegexpException e) {      log.log(Level.FINE, e.getMessage(), e);      env.warning(e);            return BooleanValue.FALSE;    }  }  /**   * Returns the index of the first match.   *   * php/151u   * The array that preg_match (PHP 5) returns does not have trailing unmatched   * groups. Therefore, an unmatched group should not be added to the array   * unless a matched group appears after it.  A couple applications like   * Gallery2 expect this behavior in order to function correctly.   *    * Only preg_match and preg_match_all(PREG_SET_ORDER) exhibits this odd   * behavior.   *   * @param env the calling environment   */  public static Value preg_match(Env env,				 StringValue regexpValue,				 StringValue subject,				 @Optional @Reference Value matchRef,				 @Optional int flags,				 @Optional int offset)  {    try {      if (regexpValue.length() < 2) {        env.warning(L.l("Regexp pattern must have opening and closing delimiters"));        return LongValue.ZERO;      }      StringValue empty = subject.getEmptyString();            Regexp regexp = getRegexp(env, regexpValue);      RegexpState regexpState = new RegexpState(env, regexp, subject);      ArrayValue regs;      if (matchRef instanceof DefaultValue)        regs = null;      else        regs = new ArrayValueImpl();      if (regexpState == null || regexpState.exec(env, subject, offset) < 0) {        matchRef.set(regs);        return LongValue.ZERO;      }      boolean isOffsetCapture = (flags & PREG_OFFSET_CAPTURE) != 0;      if (regs != null) {        if (isOffsetCapture) {          ArrayValueImpl part = new ArrayValueImpl();          part.append(regexpState.group(env));          part.append(LongValue.create(regexpState.start()));          regs.put(LongValue.ZERO, part);        }        else          regs.put(LongValue.ZERO, regexpState.group(env));        int count = regexpState.groupCount();        for (int i = 1; i < count; i++) {          if (! regexpState.isMatchedGroup(i))            continue;                    StringValue group = regexpState.group(env, i);          if (isOffsetCapture) {            // php/151u            // add unmatched groups first            for (int j = regs.getSize(); j < i; j++) {              ArrayValue part = new ArrayValueImpl();              part.append(empty);              part.append(LongValue.MINUS_ONE);              regs.put(LongValue.create(j), part);            }            ArrayValueImpl part = new ArrayValueImpl();            part.append(group);            part.append(LongValue.create(regexpState.start(i)));            StringValue name = regexpState.getGroupName(i);            if (name != null)              regs.put(name, part);            regs.put(LongValue.create(i), part);          }          else {            // php/151u            // add unmatched groups first            for (int j = regs.getSize(); j < i; j++) {              regs.put(LongValue.create(j), empty);            }            StringValue name = regexp.getGroupName(i);            if (name != null)              regs.put(name, group);            regs.put(LongValue.create(i), group);          }        }        matchRef.set(regs);      }      return LongValue.ONE;    }    catch (IllegalRegexpException e) {      log.log(Level.FINE, e.getMessage(), e);      env.warning(e);            return BooleanValue.FALSE;    }  }  /**   * Returns the number of full pattern matches or FALSE on error.   *   * @param env the calling environment   */  public static Value preg_match_all(Env env,				     StringValue rawRegexp,				     StringValue subject,				     @Reference Value matchRef,				     @Optional("PREG_PATTERN_ORDER") int flags,				     @Optional int offset)  {    try {      if (rawRegexp.length() < 2) {	env.warning(L.l("Pattern must have at least opening and closing delimiters"));	return BooleanValue.FALSE;      }      if ((flags & PREG_PATTERN_ORDER) == 0) {	// php/152m	if ((flags & PREG_SET_ORDER) == 0) {	  flags = flags | PREG_PATTERN_ORDER;	}      }      else {	if ((flags & PREG_SET_ORDER) != 0) {	  env.warning((L.l("Cannot combine PREG_PATTER_ORDER and PREG_SET_ORDER")));	  return BooleanValue.FALSE;	}      }      Regexp regexp = getRegexp(env, rawRegexp);      RegexpState regexpState = new RegexpState(env, regexp, subject);      ArrayValue matches;      if (matchRef instanceof ArrayValue)	matches = (ArrayValue) matchRef;      else	matches = new ArrayValueImpl();      matches.clear();      matchRef.set(matches);      if ((flags & PREG_PATTERN_ORDER) != 0) {	return pregMatchAllPatternOrder(env,					regexpState,					subject,					matches,					flags,					offset);      }      else if ((flags & PREG_SET_ORDER) != 0) {	return pregMatchAllSetOrder(env,				    regexp,				    regexpState,				    subject,				    matches,				    flags,				    offset);      }      else	throw new UnsupportedOperationException();    }    catch (IllegalRegexpException e) {      log.log(Level.FINE, e.getMessage(), e);      env.warning(e);            return BooleanValue.FALSE;    }  }  /**   * Returns the index of the first match.   *   * @param env the calling environment   */  public static LongValue pregMatchAllPatternOrder(Env env,						   RegexpState regexpState,						   StringValue subject,						   ArrayValue matches,						   int flags,						   int offset)  {    int groupCount = regexpState == null ? 0 : regexpState.groupCount();    ArrayValue []matchList = new ArrayValue[groupCount + 1];    StringValue emptyStr = subject.getEmptyString();        for (int j = 0; j < groupCount; j++) {      ArrayValue values = new ArrayValueImpl();      Value patternName = regexpState.getGroupName(j);            // XXX: named subpatterns causing conflicts with array indexes?      if (patternName != null)        matches.put(patternName, values);      matches.put(values);      matchList[j] = values;    }    int count = 0;    while (regexpState.find()) {      count++;      for (int j = 0; j < groupCount; j++) {        ArrayValue values = matchList[j];                if (! regexpState.isMatchedGroup(j)) {          /*          if (j == groupCount || (flags & PREG_OFFSET_CAPTURE) == 0)            values.put(emptyStr);          else {            Value result = new ArrayValueImpl();                        result.put(emptyStr);            result.put(LongValue.MINUS_ONE);                        values.put(result);          }          */                    values.put(emptyStr);                      continue;        }        StringValue groupValue = regexpState.group(env, j);        Value result = NullValue.NULL;        if (groupValue != null) {          if ((flags & PREG_OFFSET_CAPTURE) != 0) {            result = new ArrayValueImpl();            result.put(groupValue);            result.put(LongValue.create(regexpState.getBegin(j)));          } else {            result = groupValue;          }        }        values.put(result);      }    }    return LongValue.create(count);  }  /**   * Returns the index of the first match.   *   * @param env the calling environment   */  private static LongValue pregMatchAllSetOrder(Env env,						Regexp regexp,						RegexpState regexpState,						StringValue subject,						ArrayValue matches,						int flags,						int offset)  {    if (regexpState == null || ! regexpState.find()) {      return LongValue.ZERO;    }    StringValue empty = subject.getEmptyString();        int count = 0;    do {      count++;      ArrayValue matchResult = new ArrayValueImpl();      matches.put(matchResult);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?