org.languagetool.rules.RuleMatch.java Source code

Java tutorial

Introduction

Here is the source code for org.languagetool.rules.RuleMatch.java

Source

/* LanguageTool, a natural language style checker 
 * Copyright (C) 2005 Daniel Naber (http://www.danielnaber.de)
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
 * USA
 */
package org.languagetool.rules;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.languagetool.tools.StringTools;

/**
 * Information about an error rule that matches text and the position of the match.
 * See {@link org.languagetool.tools.ContextTools} for displaying errors in their original text context.
 * 
 * @author Daniel Naber
 */
public class RuleMatch implements Comparable<RuleMatch> {

    private static final Pattern SUGGESTION_PATTERN = Pattern.compile("<suggestion>(.*?)</suggestion>");

    private final Rule rule;
    private final OffsetPosition offsetPosition;
    private final String message;
    private final String shortMessage; // used e.g. for OOo/LO context menu

    private LinePosition linePosition = new LinePosition(-1, -1);
    private ColumnPosition columnPosition = new ColumnPosition(-1, -1);
    private List<String> suggestedReplacements = new ArrayList<>();

    /**
     * Creates a RuleMatch object, taking the rule that triggered
     * this match, position of the match and an explanation message.
     * This message is scanned for &lt;suggestion&gt;...&lt;/suggestion&gt;
     * to get suggested fixes for the problem detected by this rule.
     */
    public RuleMatch(Rule rule, int fromPos, int toPos, String message) {
        this(rule, fromPos, toPos, message, null, false, null);
    }

    /**
     * Creates a RuleMatch object, taking the rule that triggered
     * this match, position of the match and an explanation message.
     * This message is scanned for &lt;suggestion&gt;...&lt;/suggestion&gt;
     * to get suggested fixes for the problem detected by this rule.
     *
     * @param shortMessage used for example in OpenOffice/LibreOffice's context menu
     */
    public RuleMatch(Rule rule, int fromPos, int toPos, String message, String shortMessage) {
        this(rule, fromPos, toPos, message, shortMessage, false, null);
    }

    /**
     * Creates a RuleMatch object, taking the rule that triggered
     * this match, position of the match and an explanation message.
     * This message is scanned for &lt;suggestion&gt;...&lt;/suggestion&gt;
     * to get suggested fixes for the problem detected by this rule. 
     * 
     * @param shortMessage used for example in OpenOffice/LibreOffice's context menu (may be null)
     * @param startWithUppercase whether the original text at the position
     *    of the match starts with an uppercase character
     */
    public RuleMatch(Rule rule, int fromPos, int toPos, String message, String shortMessage,
            boolean startWithUppercase, String suggestionsOutMsg) {
        this.rule = rule;
        if (toPos <= fromPos) {
            throw new RuntimeException("fromPos (" + fromPos + ") must be less than toPos (" + toPos + ")");
        }
        this.offsetPosition = new OffsetPosition(fromPos, toPos);
        this.message = message;
        this.shortMessage = shortMessage;
        // extract suggestion from <suggestion>...</suggestion> in message:
        final Matcher matcher = SUGGESTION_PATTERN.matcher(message + suggestionsOutMsg);
        int pos = 0;
        while (matcher.find(pos)) {
            pos = matcher.end();
            String replacement = matcher.group(1);
            if (startWithUppercase) {
                replacement = StringTools.uppercaseFirstChar(replacement);
            }
            suggestedReplacements.add(replacement);
        }
    }

    public Rule getRule() {
        return rule;
    }

    /**
     * Set the line number in which the match occurs (zero-based).
     */
    public void setLine(final int fromLine) {
        linePosition = new LinePosition(fromLine, linePosition.getEnd());
    }

    /**
     * Get the line number in which the match occurs (zero-based).
     */
    public int getLine() {
        return linePosition.getStart();
    }

    /**
     * Set the line number in which the match ends (zero-based).
     */
    public void setEndLine(final int endLine) {
        linePosition = new LinePosition(linePosition.getStart(), endLine);
    }

    /**
     * Get the line number in which the match ends (zero-based).
     */
    public int getEndLine() {
        return linePosition.getEnd();
    }

    /**
     * Set the column number in which the match occurs (zero-based).
     */
    public void setColumn(final int column) {
        this.columnPosition = new ColumnPosition(column, columnPosition.getEnd());
    }

    /**
     * Get the column number in which the match occurs (zero-based).
     */
    public int getColumn() {
        return columnPosition.getStart();
    }

    /**
     * Set the column number in which the match ends (zero-based).
     */
    public void setEndColumn(final int endColumn) {
        this.columnPosition = new ColumnPosition(columnPosition.getStart(), endColumn);
    }

    /**
     * Get the column number in which the match ends (zero-based).
     */
    public int getEndColumn() {
        return columnPosition.getEnd();
    }

    /**
     * Position of the start of the error (in characters, zero-based).
     */
    public int getFromPos() {
        return offsetPosition.getStart();
    }

    /**
     * Position of the end of the error (in characters, zero-based).
     */
    public int getToPos() {
        return offsetPosition.getEnd();
    }

    /**
     * A human-readable explanation describing the error. This may contain
     * one or more corrections marked up with &lt;suggestion&gt;...&lt;/suggestion&gt;.
     * @see #getSuggestedReplacements()
     * @see #getShortMessage()
     */
    public String getMessage() {
        return message;
    }

    /**
     * A shorter human-readable explanation describing the error or an empty string
     * if no such explanation is available.
     * @see #getMessage()
     */
    public String getShortMessage() {
        return shortMessage;
    }

    /**
     * @see #getSuggestedReplacements()
     */
    public void setSuggestedReplacement(final String replacement) {
        Objects.requireNonNull(replacement, "replacement may be empty but not null");
        final List<String> replacements = new ArrayList<>();
        replacements.add(replacement);
        setSuggestedReplacements(replacements);
    }

    /**
     * @see #getSuggestedReplacements()
     */
    public void setSuggestedReplacements(final List<String> replacements) {
        this.suggestedReplacements = Objects.requireNonNull(replacements, "replacements may be empty but not null");
    }

    /**
     * The text fragments which might be an appropriate fix for the problem. One
     * of these fragments can be used to replace the old text between {@link #getFromPos()}
     * to {@link #getToPos()}.
     * @return unmodifiable list of String objects or an empty List
     */
    public List<String> getSuggestedReplacements() {
        return Collections.unmodifiableList(suggestedReplacements);
    }

    @Override
    public String toString() {
        return rule.getId() + ":" + offsetPosition + ":" + message;
    }

    /** Compare by start position. */
    @Override
    public int compareTo(final RuleMatch other) {
        Objects.requireNonNull(other);
        return Integer.compare(getFromPos(), other.getFromPos());
    }

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;
        RuleMatch other = (RuleMatch) o;
        return new EqualsBuilder().append(rule.getId(), other.rule.getId())
                .append(offsetPosition, other.offsetPosition).append(message, other.message)
                .append(suggestedReplacements, other.suggestedReplacements).isEquals();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(rule.getId()).append(offsetPosition).append(message)
                .append(suggestedReplacements).toHashCode();
    }

    static class OffsetPosition extends MatchPosition {
        OffsetPosition(int start, int end) {
            super(start, end);
        }
    }

    static class LinePosition extends MatchPosition {
        LinePosition(int start, int end) {
            super(start, end);
        }
    }

    static class ColumnPosition extends MatchPosition {
        ColumnPosition(int start, int end) {
            super(start, end);
        }
    }
}