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 + -
显示快捷键?