Example usage for java.util.regex Matcher appendTail

List of usage examples for java.util.regex Matcher appendTail

Introduction

In this page you can find the example usage for java.util.regex Matcher appendTail.

Prototype

public StringBuilder appendTail(StringBuilder sb) 

Source Link

Document

Implements a terminal append-and-replace step.

Usage

From source file:com.dianping.lion.service.impl.DefaultConfigValueResolver.java

@Override
public String resolve(String configval, int envId) {
    if (configval == null) {
        return null;
    }/*from w  ww  .j  a v a2 s  .  c  om*/
    if (configval.contains(ServiceConstants.REF_CONFIG_PREFIX)) {
        try {
            Matcher matcher = ServiceConstants.REF_EXPR_PATTERN.matcher(configval);
            boolean referenceFound = false;
            StringBuffer buffer = new StringBuffer(configval.length() * 2);
            while (matcher.find()) {
                referenceFound = true;
                String refkey = matcher.group(1);
                Config refconfig = configService.findConfigByKey(refkey);
                if (refconfig == null) {
                    logger.warn("Referenced config[" + refkey + "] not found.");
                    return null;
                }
                ConfigInstance refinstance = configService.findInstance(refconfig.getId(), envId,
                        ConfigInstance.NO_CONTEXT);
                if (refinstance == null) {
                    logger.warn("Referenced config[" + refkey + "] with env[" + envId + "] not found.");
                    return null;
                }
                String refval = refinstance.getValue();
                if (refval == null) {
                    logger.warn("Reference null-valued config[" + refkey + "] with env[" + envId + "].");
                    return null;
                }
                String refparams = matcher.group(3);
                if (StringUtils.isNotBlank(refparams)) {
                    String[] paramList = StringUtils.split(refparams, "&");
                    for (String paramstr : paramList) {
                        String[] paramentry = StringUtils.split(paramstr, "=");
                        refval = StringUtils.replace(refval, "${" + paramentry[0] + "}", paramentry[1]);
                    }
                }
                matcher.appendReplacement(buffer, Matcher.quoteReplacement(refval));
            }
            if (referenceFound) {
                matcher.appendTail(buffer);
                return buffer.toString();
            }
        } catch (RuntimeException e) {
            logger.error("Resolve referenced config expression[" + configval + "] failed.", e);
            throw e;
        }
    }
    return configval;
}

From source file:com.nttec.everychan.ui.downloading.HtmlBuilder.java

private String fixComment(String comment) {
    comment = comment.replaceAll("(?i)<aibquote>", "<span class=\"unkfunc\">")
            .replaceAll("(?i)</aibquote>", "</span>").replaceAll("(?i)<aibspoiler>", "<span class=\"spoiler\">")
            .replaceAll("(?i)</aibspoiler>", "</span>");
    Matcher m = A_HREF_PATTERN.matcher(comment);
    if (!m.find())
        return comment;
    StringBuffer sb = new StringBuffer();
    do {/*w w w . j a va2 s .  c  o  m*/
        String group = m.group();
        String found = m.group(1);
        int oldPos = m.start(1) - m.start();
        int oldLen = found.length();

        String url;
        if (found.startsWith("#")) {
            try {
                String thisThreadUrl = chan.buildUrl(pageModel);
                int i = thisThreadUrl.indexOf('#');
                if (i != -1)
                    thisThreadUrl = thisThreadUrl.substring(0, i);
                String postNumber = chan.parseUrl(thisThreadUrl + found).postNumber;
                url = "#" + postNumber != null ? postNumber : pageModel.threadNumber;
            } catch (Exception e) {
                url = found;
            }
        } else {
            url = chan.fixRelativeUrl(found);
            try {
                UrlPageModel linkModel = chan.parseUrl(url);
                if (ChanModels.hashUrlPageModel(linkModel).equals(ChanModels.hashUrlPageModel(pageModel))) {
                    url = "#" + linkModel.postNumber;
                }
            } catch (Exception e) {
                /* ignore */ }
        }

        m.appendReplacement(sb, url.equals(found) ? group
                : (group.substring(0, oldPos) + url + group.substring(oldPos + oldLen)));
    } while (m.find());
    m.appendTail(sb);
    return sb.toString();
}

From source file:com.microsoft.tfs.client.common.ui.helpers.HTMLIncludeHelper.java

/**
 * <p>//from   w w w.j a v a 2 s . co  m
 * Transforms the given line, including referenced files by delegating to
 * the {@link HTMLIncludeResourceProvider}.
 * </p>
 *
 * <p>
 * Lines with text matching: %%%INCLUDE(file="filename")%%% will be
 * transformed by replacing the line with the given filename. The "format"
 * tag may also be specified with a value of "text" or "base64". If the
 * format is specified as "text", the file will be reinterpreted while being
 * included (ie, includes in included files will also be included.) If the
 * format is specified as "base64", the file will be included as base64
 * data.
 * </p>
 *
 * <p>
 * Examples:
 * </p>
 *
 * <p>
 * %%%INCLUDE(file="filename")%%% will include the resource specified by
 * "filename".
 * </p>
 *
 * <p>
 * %%%INCLUDE(file="filename", format="text")%%% will include the resource
 * specified by "filename". (This is identical to the above example.)
 * </p>
 *
 * <p>
 * %%%INCLUDE(file="filename", format="base64")%%% will include the base64
 * representation of the resource specified by "filename".
 * </p>
 *
 * @param input
 *        An input line from a resource
 * @return The line with any include statements transformed.
 * @throws IOException
 *         If any included resources could not be read
 */
private String transformIncludes(final String input) throws IOException {
    Check.notNull(input, "input"); //$NON-NLS-1$

    final Matcher includeMatcher = includePattern.matcher(input);
    final StringBuffer transformation = new StringBuffer();

    while (includeMatcher.find()) {
        if (includeMatcher.groupCount() != 1) {
            log.warn(MessageFormat.format("Invalid include statement: {0}", includeMatcher.toString())); //$NON-NLS-1$
            continue;
        }

        final Matcher optionMatcher = optionPattern.matcher(includeMatcher.group(1));
        String resourceName = null;
        String format = "text"; //$NON-NLS-1$

        while (optionMatcher.find()) {
            if (optionMatcher.groupCount() != 2) {
                log.warn(MessageFormat.format("Invalid include statement: {0}", includeMatcher.group(1))); //$NON-NLS-1$
                continue;
            }

            if ("file".equals(optionMatcher.group(1))) //$NON-NLS-1$
            {
                resourceName = optionMatcher.group(2);
            } else if ("format".equals(optionMatcher.group(1))) //$NON-NLS-1$
            {
                format = optionMatcher.group(2);
            }
        }

        if (resourceName == null) {
            log.warn(MessageFormat.format("Invalid include statement: {0}", includeMatcher.group(1))); //$NON-NLS-1$
        } else if ("base64".equals(format)) //$NON-NLS-1$
        {
            includeMatcher.appendReplacement(transformation, readResourceToBase64(resourceName));
        } else {
            includeMatcher.appendReplacement(transformation, readResource(resourceName));
        }
    }

    includeMatcher.appendTail(transformation);

    return transformation.toString();
}

From source file:com.ibm.jaggr.core.impl.AbstractAggregatorImpl.java

@Override
public String substituteProps(String str, SubstitutionTransformer transformer) {
    if (str == null) {
        return null;
    }/*from w ww. j  ava  2s .c o m*/
    StringBuffer buf = new StringBuffer();
    Matcher matcher = pattern.matcher(str);
    while (matcher.find()) {
        String propName = matcher.group(1);
        String propValue = getPropValue(propName);
        if (propValue != null) {
            if (transformer != null) {
                propValue = transformer.transform(propName, propValue);
            }
            matcher.appendReplacement(buf, propValue.replace("\\", "\\\\") //$NON-NLS-1$ //$NON-NLS-2$
                    .replace("$", "\\$") //$NON-NLS-1$ //$NON-NLS-2$
            );
        } else {
            matcher.appendReplacement(buf, "\\${" + propName + "}"); //$NON-NLS-1$ //$NON-NLS-2$
        }
    }
    matcher.appendTail(buf);
    return buf.toString();
}

From source file:com.threerings.getdown.data.Application.java

/** Replaces the application directory and version in any argument. */
protected String processArg(String arg) {
    arg = arg.replace("%APPDIR%", _appdir.getAbsolutePath());
    arg = arg.replace("%VERSION%", String.valueOf(_version));

    // if this argument contains %ENV.FOO% replace those with the associated values looked up
    // from the environment
    if (arg.contains(ENV_VAR_PREFIX)) {
        StringBuffer sb = new StringBuffer();
        Matcher matcher = ENV_VAR_PATTERN.matcher(arg);
        while (matcher.find()) {
            String varName = matcher.group(1), varValue = System.getenv(varName);
            if (varName == null)
                varName = "MISSING:" + varName;
            matcher.appendReplacement(sb, varValue);
        }/*ww  w  . java 2  s .  c om*/
        matcher.appendTail(sb);
        arg = sb.toString();
    }

    return arg;
}

From source file:org.pentaho.metadata.query.impl.sql.SqlGenerator.java

/**
 * Returns the generated SQL and additional metadata
 * //from  ww w.  j  a  v a  2s.c o  m
 * @param model
 *          The business model.
 * @param selections
 *          The selected business columns.
 * @param conditions
 *          The conditions to apply (null = no conditions).
 * @param orderBy
 *          The ordering (null = no order by clause).
 * @param databaseMeta
 *          The meta info which determines the SQL generated.
 * @param locale
 *          The locale.
 * @param parameters
 *        Parameters to be used during query generation.
 * @param genAsPreparedStatement
 *        Forces the method generate query as prepared statement.
 * @param disableDistinct
 *          If true, disables default behavior of using DISTINCT when there are no groupings.
 * @param limit
 *          Maximum number of rows to be returned during query execution.
 * @param securityConstraint
 *          If provided, applies a global security constraint to the query.
 * 
 * @return Returns a SQL query based on a column selection, conditions and a locale.
 */
protected MappedQuery getSQL(LogicalModel model, List<Selection> selections, List<Constraint> conditions,
        List<Order> orderBy, DatabaseMeta databaseMeta, String locale, Map<String, Object> parameters,
        boolean genAsPreparedStatement, boolean disableDistinct, int limit, Constraint securityConstraint)
        throws PentahoMetadataException {

    SQLQueryModel query = new SQLQueryModel();

    // Get settings for the query model
    Object val = null;
    val = model.getProperty("delay_outer_join_conditions"); //$NON-NLS-1$
    if ((val != null) && (val instanceof Boolean)) {
        query.setDelayOuterJoinConditions(((Boolean) val).booleanValue());
    }

    Map<String, String> columnsMap = new HashMap<String, String>();

    // generate the formula objects for constraints
    Map<Constraint, SqlOpenFormula> constraintFormulaMap = new HashMap<Constraint, SqlOpenFormula>();
    for (Constraint constraint : conditions) {
        SqlOpenFormula formula = new SqlOpenFormula(model, databaseMeta, constraint.getFormula(), null,
                parameters, genAsPreparedStatement);
        formula.parseAndValidate();
        constraintFormulaMap.put(constraint, formula);
    }
    if (securityConstraint != null) {
        SqlOpenFormula formula = new SqlOpenFormula(model, databaseMeta, securityConstraint.getFormula(), null,
                parameters, genAsPreparedStatement);
        formula.parseAndValidate();
        constraintFormulaMap.put(securityConstraint, formula);
    }

    // These are the tables involved in the field selection
    //
    List<LogicalTable> tabs = getTablesInvolved(model, selections, conditions, orderBy, constraintFormulaMap,
            parameters, genAsPreparedStatement, databaseMeta, locale, securityConstraint);

    // Now get the shortest path between these tables.
    Path path = getShortestPathBetween(model, tabs);
    if (path == null) {
        throw new PentahoMetadataException(
                Messages.getErrorString("SqlGenerator.ERROR_0002_FAILED_TO_FIND_PATH")); //$NON-NLS-1$
    }

    List<LogicalTable> usedBusinessTables = path.getUsedTables();
    if (path.size() == 0) {
        // just a selection from 1 table: pick any column...
        // Otherwise, why bother, right?
        if (selections.size() > 0) {
            usedBusinessTables.add(selections.get(0).getLogicalColumn().getLogicalTable());
        }
    }

    Map<LogicalTable, String> tableAliases = null;

    if (usedBusinessTables.size() > 0) {

        // generate tableAliases mapping

        int maxAliasNameWidth = SQLDialectFactory.getSQLDialect(databaseMeta).getMaxTableNameLength();
        tableAliases = new HashMap<LogicalTable, String>();
        for (LogicalTable table : usedBusinessTables) {
            String uniqueAlias = generateUniqueAlias(table.getId(), maxAliasNameWidth, tableAliases.values());
            tableAliases.put(table, uniqueAlias);
        }

        boolean group = hasFactsInIt(model, selections, conditions, constraintFormulaMap, parameters,
                genAsPreparedStatement, databaseMeta, locale);

        generateSelect(query, model, databaseMeta, selections, disableDistinct, limit, group, locale,
                tableAliases, columnsMap, parameters, genAsPreparedStatement);
        generateFromAndWhere(query, usedBusinessTables, model, path, conditions, tableAliases,
                constraintFormulaMap, parameters, genAsPreparedStatement, databaseMeta, locale);
        if (group) {
            generateGroupBy(query, model, selections, tableAliases, parameters, genAsPreparedStatement,
                    databaseMeta, locale);
        }
        generateOrderBy(query, model, orderBy, databaseMeta, locale, tableAliases, columnsMap, parameters,
                genAsPreparedStatement);

        if (securityConstraint != null) {
            // apply current table aliases
            SqlOpenFormula securityFormula = constraintFormulaMap.get(securityConstraint);
            securityFormula.setTableAliases(tableAliases);

            // generate sql
            String sqlFormula = securityFormula.generateSQL(locale);
            query.setSecurityConstraint(sqlFormula, securityFormula.hasAggregate());
        }
    }

    // this is available to classes that override sql generation behavior
    preprocessQueryModel(query, selections, tableAliases, databaseMeta);

    // Convert temporary param placements with Sql Prepared Statement ? values
    SQLDialectInterface dialect = SQLDialectFactory.getSQLDialect(databaseMeta);
    List<String> paramNames = null;
    String sql = dialect.generateSelectStatement(query);
    Pattern p = Pattern.compile("___PARAM\\[(.*?)\\]___"); //$NON-NLS-1$
    Matcher m = p.matcher(sql);
    StringBuffer sb = new StringBuffer();
    while (m.find()) {
        String paramName = m.group(1);
        String repl = "?";
        if (parameters.get(paramName) instanceof Object[]) {
            Object[] paramz = (Object[]) parameters.get(paramName);
            for (int i = 1; i < paramz.length; i++) {
                repl += ", ?";
            }
        }
        m.appendReplacement(sb, repl); //$NON-NLS-1$
        if (paramNames == null) {
            paramNames = new ArrayList<String>();
        }
        paramNames.add(paramName);
    }
    m.appendTail(sb);

    String sqlStr = sb.toString();
    if (logger.isTraceEnabled()) {
        logger.trace(sqlStr);
    }
    // this is available to classes that override sql generation behavior
    String sqlOutput = processGeneratedSql(sb.toString());

    return new MappedQuery(sqlOutput, columnsMap, selections, paramNames);
}

From source file:org.codice.ddf.spatial.ogc.wfs.v2_0_0.catalog.source.WfsFilterDelegate.java

/**
 * The WKT passed into the spatial methods has the coordinates ordered in LON/LAT. This method
 * will convert the WKT to LAT/LON ordering.
 *///w  w  w  .j a  v a  2  s.  co  m
private String convertWktToLatLonOrdering(String wktInLonLat) {

    if (Wfs20Constants.LAT_LON_ORDER.equals(coordinateOrder)) {
        LOGGER.debug("Converting WKT from LON/LAT coordinate ordering to LAT/LON coordinate ordering.");

        // Normalize all whitespace in WKT before processing.
        wktInLonLat = normalizeWhitespaceInWkt(wktInLonLat);

        Matcher matcher = COORD_PATTERN.matcher(wktInLonLat);

        StringBuffer stringBuffer = new StringBuffer();

        while (matcher.find()) {
            String lonLatCoord = matcher.group();
            String latLonCoord = StringUtils.reverseDelimited(lonLatCoord, ' ');
            LOGGER.debug("Converted LON/LAT coord: ({}) to LAT/LON coord: ({}).", lonLatCoord, latLonCoord);
            matcher.appendReplacement(stringBuffer, latLonCoord);
        }

        matcher.appendTail(stringBuffer);

        String wktInLatLon = stringBuffer.toString();
        LOGGER.debug("Original WKT with coords in LON/LAT ordering:  {}", wktInLonLat);
        LOGGER.debug("Converted WKT with coords in LAT/LON ordering: {}", wktInLatLon);

        return wktInLatLon;
    } else {
        LOGGER.debug("The configured CSW source requires coordinates in LON/LAT ordering.");
        return wktInLonLat;
    }
}

From source file:com.g3net.tool.StringUtils.java

/**
 * src?regex??????? ?(handler)/*  www.ja  va 2 s.co  m*/
 * ?????
 * 
 * @param src
 * @param regex
 *            ??:&(\\d+;)([a-z)+)
 * @param handleGroupIndex
 *            ???
 * @param hander
 *            ?
 * @param reservesGroups
 *            ???,?hander?handleGroupIndex
 *            ?reservesGroups?hander?regex? 
 * @return
 */
public static String replaceAll(String src, String regex, int handleGroupIndex, GroupHandler hander,
        int[] reservesGroups) {

    if (src == null || src.trim().length() == 0) {
        return "";
    }
    Matcher m = Pattern.compile(regex).matcher(src);

    StringBuffer sbuf = new StringBuffer();
    String replacementFirst = "";
    String replacementTail = "";
    if (reservesGroups != null && reservesGroups.length > 0) {
        Arrays.sort(reservesGroups);
        for (int i = 0; i < reservesGroups.length; i++) {
            if (reservesGroups[i] < handleGroupIndex) {
                replacementFirst = replacementFirst + "$" + reservesGroups[i];
            } else {
                replacementTail = replacementTail + "$" + reservesGroups[i];
            }
        }
    }

    // perform the replacements:
    while (m.find()) {
        String value = m.group(handleGroupIndex);

        String group = m.group();

        String handledStr = hander.handler(value);
        String replacement = "";
        if (reservesGroups == null) {
            int start0 = m.start();
            int end0 = m.end();
            int start = m.start(handleGroupIndex);
            int end = m.end(handleGroupIndex);
            int relativeStart = start - start0;
            int relativeEnd = end - start0;
            StringBuilder sbgroup = new StringBuilder(group);
            sbgroup = sbgroup.replace(relativeStart, relativeEnd, handledStr);
            replacement = sbgroup.toString();
        } else {
            replacement = replacementFirst + handledStr + replacementTail;
        }

        m.appendReplacement(sbuf, replacement);

    }
    // Put in the remainder of the text:
    m.appendTail(sbuf);
    return sbuf.toString();
    // return null;
}

From source file:org.opencastproject.execute.impl.ExecuteServiceImpl.java

/**
 * Does the actual processing//  www .ja  v a 2 s.  c  o  m
 *
 * @param arguments
 *          The list containing the program and its arguments
 * @param mp
 *          MediaPackage used in the operation
 * @param outFileName
 *          The name of the resulting file
 * @param expectedType
 *          The expected element type
 * @return A {@code String} containing the command output
 * @throws ExecuteException
 *           if some internal error occurred
 */
protected String doProcess(List<String> arguments, MediaPackage mp, String outFileName, Type expectedType)
        throws ExecuteException {

    String params = arguments.remove(1);

    File outFile = null;
    MediaPackageElement[] elementsByFlavor = null;

    try {
        if (outFileName != null) {
            // FIXME : Find a better way to place the output File
            File firstElement = workspace.get(mp.getElements()[0].getURI());
            outFile = new File(firstElement.getParentFile(), outFileName);
        }

        // Get the substitution pattern.
        // The following pattern matches, any construct with the form
        // #{name}
        // , where 'name' is the value of a certain property. It is stored in the backreference group 1.
        // Optionally, expressions can take a parameter, like
        // #{name(parameter)}
        // , where 'parameter' is the name of a certain parameter.
        // If specified, 'parameter' is stored in the group 2. Otherwise it's null.
        // Both name and parameter match any character sequence that does not contain {, }, ( or ) .
        Pattern pat = Pattern.compile("#\\{([^\\{\\}\\(\\)]+)(?:\\(([^\\{\\}\\(\\)]+)\\))?\\}");

        // Substitute the appearances of the patterns with the actual absolute paths
        Matcher matcher = pat.matcher(params);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            // group(1) = property. group(2) = (optional) parameter
            if (matcher.group(1).equals("id")) {
                matcher.appendReplacement(sb, mp.getIdentifier().toString());
            } else if (matcher.group(1).equals("flavor")) {
                elementsByFlavor = mp
                        .getElementsByFlavor(MediaPackageElementFlavor.parseFlavor(matcher.group(2)));
                if (elementsByFlavor.length == 0)
                    throw new ExecuteException(
                            "No elements in the MediaPackage match the flavor '" + matcher.group(1) + "'.");

                if (elementsByFlavor.length > 1)
                    logger.warn("Found more than one element with flavor '{}'. Using {} by default...",
                            matcher.group(1), elementsByFlavor[0].getIdentifier());

                File elementFile = workspace.get(elementsByFlavor[0].getURI());
                matcher.appendReplacement(sb, elementFile.getAbsolutePath());
            } else if (matcher.group(1).equals("out")) {
                matcher.appendReplacement(sb, outFile.getAbsolutePath());
            } else if (properties.get(matcher.group(1)) != null) {
                matcher.appendReplacement(sb, (String) properties.get(matcher.group(1)));
            } else if (bundleContext.getProperty(matcher.group(1)) != null) {
                matcher.appendReplacement(sb, bundleContext.getProperty(matcher.group(1)));
            }
        }
        matcher.appendTail(sb);
        params = sb.toString();
    } catch (IllegalArgumentException e) {
        throw new ExecuteException("Tag 'flavor' must specify a valid MediaPackage element flavor.", e);
    } catch (NotFoundException e) {
        throw new ExecuteException("The element '" + elementsByFlavor[0].getURI().toString()
                + "' does not exist in the workspace.", e);
    } catch (IOException e) {
        throw new ExecuteException("Error retrieving MediaPackage element from workspace: '"
                + elementsByFlavor[0].getURI().toString() + "'.", e);
    }

    arguments.addAll(splitParameters(params));

    return runCommand(arguments, outFile, expectedType);
}

From source file:org.esigate.impl.UrlRewriter.java

/**
 * Fixes all resources urls and returns the result.
 * //from w w w .  ja  v a2s  .com
 * @param input
 *            The html to be processed.
 * 
 * @param requestUrl
 *            The request URL.
 * @param baseUrlParam
 *            The base URL selected for this request.
 * @param visibleBaseUrl
 *            The base URL viewed by the browser.
 * @param absolute
 *            Should the rewritten urls contain the scheme host and port
 * 
 * @return the result of this renderer.
 */
public CharSequence rewriteHtml(CharSequence input, String requestUrl, String baseUrlParam,
        String visibleBaseUrl, boolean absolute) {
    StringBuffer result = new StringBuffer(input.length());
    Matcher m = URL_PATTERN.matcher(input);
    while (m.find()) {
        String url = input.subSequence(m.start(3) + 1, m.end(3) - 1).toString();
        String tag = m.group(0);
        String quote = input.subSequence(m.end(3) - 1, m.end(3)).toString();

        // Browsers tolerate urls with white spaces before or after
        String trimmedUrl = StringUtils.trim(url);

        String rewrittenUrl = url;

        trimmedUrl = unescapeHtml(trimmedUrl);

        if (trimmedUrl.isEmpty()) {
            LOG.debug("empty url kept unchanged");
        } else if (trimmedUrl.startsWith("#")) {
            LOG.debug("anchor url kept unchanged: [{}]", url);
        } else if (JAVASCRIPT_CONCATENATION_PATTERN.matcher(trimmedUrl).find()) {
            LOG.debug("url in javascript kept unchanged: [{}]", url);
        } else if (m.group(2).equalsIgnoreCase("content")) {
            if (META_REFRESH_PATTERN.matcher(tag).find()) {
                rewrittenUrl = rewriteRefresh(trimmedUrl, requestUrl, baseUrlParam, visibleBaseUrl);
                rewrittenUrl = escapeHtml(rewrittenUrl);
                LOG.debug("refresh url [{}] rewritten [{}]", url, rewrittenUrl);
            } else {
                LOG.debug("content attribute kept unchanged: [{}]", url);
            }
        } else {
            rewrittenUrl = rewriteUrl(trimmedUrl, requestUrl, baseUrlParam, visibleBaseUrl, absolute);
            rewrittenUrl = escapeHtml(rewrittenUrl);
            LOG.debug("url [{}] rewritten [{}]", url, rewrittenUrl);
        }

        m.appendReplacement(result, ""); // Copy what is between the previous match and the current match
        result.append("<");
        result.append(m.group(1));
        result.append(m.group(2));
        result.append("=");
        result.append(quote);
        result.append(rewrittenUrl);
        result.append(quote);
        if (m.groupCount() > 3) {
            result.append(m.group(4));
        }
        result.append(">");
    }

    m.appendTail(result); // Copy the reminder of the input

    return result;
}