All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.basistech.tclre.HsreMatcher Maven / Gradle / Ivy

There is a newer version: 0.14.14
Show newest version
/*
 * Copyright 2014 Basis Technology Corp.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.basistech.tclre;

import java.util.Collections;
import java.util.EnumSet;
import com.google.common.base.Objects;

/*
 * Matcher. This is an incomplete analog of {@link java.util.regex.Matcher}.
 */
final class HsreMatcher implements ReMatcher {

    private CharSequence data;
    private final EnumSet flags;
    private final HsrePattern pattern;
    private Runtime runtime;
    private int regionStart;
    private int regionEnd;
    private int nextFindOffset;
    // correction from Runtime.matches to us.
    private int matchOffset;

    HsreMatcher(HsrePattern pattern, CharSequence data, EnumSet flags) throws RegexException {
        this.pattern = pattern;
        this.data = data;
        this.flags = flags;
        regionStart = 0;
        regionEnd = data.length();

        String originalPattern = pattern.pattern();
    }

    /**
     * @return the pattern.
     */
    @Override
    public RePattern pattern() {
        return pattern;
    }

    /**
     * Look for a match; begin the search at a given offset.
     * @param startOffset the offset.
     * @return true for a match.
     */
    @Override
    public boolean find(int startOffset) throws RegexRuntimeException {
        return findInternal(pattern, startOffset, false);
    }

    private boolean findInternal(HsrePattern pat, int startOffset, boolean lookingAt) {
        if (startOffset < regionStart) {
            throw new IllegalArgumentException("Start offset less than region start");
        }

        // if lookingAt add the LOOKING_AT flag.
        EnumSet execFlags = flags;
        if (lookingAt) {
            execFlags = EnumSet.copyOf(flags);
            execFlags.add(ExecFlags.LOOKING_AT);
        }

        // TODO: this is a pessimization; we should be able to make one at construction and reuse it.
        runtime = new Runtime();
        try {
            boolean found = runtime.exec(pat, data.subSequence(startOffset, regionEnd), execFlags);
            if (found) {
                // note how much to add to the runtime.match offsets.
                matchOffset = startOffset;
                // and now end does the necessary correction on the offset value from 'runtime'.
                nextFindOffset = end();
            }
            return found;
        } catch (RegexException e) {
            throw new RegexRuntimeException(e);
        }
    }

    /**
     * Look for a match; begin the search at the start.
     * @return true for a match.
     */
    @Override
    public boolean find() throws RegexRuntimeException {
        return find(nextFindOffset);
    }

    /*
     * Called by all the 'resetting' functions.
     * Allows find to work as specified.
    */
    private void resetState() {
        // if there are any matches sitting in the runtime, eliminate.
        if (runtime != null && runtime.match != null) {
            runtime.match.clear();
        }
        nextFindOffset = regionStart;
    }

    @Override
    public ReMatcher region(int start, int end) throws RegexRuntimeException {
        regionStart = start;
        regionEnd = end;
        resetState();
        return this;
    }

    @Override
    public ReMatcher reset() throws RegexRuntimeException {
        regionStart = 0;
        regionEnd = data.length();
        resetState();
        return this;
    }

    @Override
    public ReMatcher reset(CharSequence newSequence) throws RegexRuntimeException {
        data = newSequence;
        regionStart = 0;
        regionEnd = data.length();
        resetState();
        return this;
    }

    @Override
    public ReMatcher flags(ExecFlags... flags) {
        this.flags().clear();
        Collections.addAll(this.flags, flags);
        return null;
    }

    @Override
    public EnumSet flags() {
        return flags;
    }


    @Override
    public boolean matches() throws RegexRuntimeException {
        return findInternal(pattern, regionStart, true)
                && start() == regionStart
                && end() == regionEnd;
    }

    @Override
    public int regionStart() {
        return regionStart;
    }

    @Override
    public int regionEnd() {
        return regionEnd;
    }

    @Override
    public boolean lookingAt() {
        return findInternal(pattern, regionStart, true);
    }

    @Override
    public int start() {
        return runtime.match.get(0).start + matchOffset;
    }

    @Override
    public int start(int group) {
        return runtime.match.get(group).start + matchOffset;
    }

    @Override
    public int end() {
        return runtime.match.get(0).end + matchOffset;
    }

    @Override
    public int end(int group) {
        return runtime.match.get(group).end + matchOffset;
    }

    @Override
    public String group() {
        return data.subSequence(start(), end()).toString();
    }

    @Override
    public String group(int group) {
        return data.subSequence(start(group), end(group)).toString();
    }

    @Override
    public int groupCount() {
        return runtime.match.size() - 1; // omit the 'group' for the whole match.
    }

    @Override
    public String toString() {
        return Objects.toStringHelper(this)
                .add("pattern", pattern)
                .add("flags", flags)
                .add("regionStart", regionStart)
                .add("regionEnd", regionEnd)
                .add("data", data)
                .toString();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy