ExpressionMatcher.java :  » Game » Arianne-RPG-0.83 » games » stendhal » server » entity » npc » parser » Java Open Source

Java Open Source » Game » Arianne RPG 0.83 
Arianne RPG 0.83 » games » stendhal » server » entity » npc » parser » ExpressionMatcher.java
package games.stendhal.server.entity.npc.parser;

import java.util.NoSuchElementException;
import java.util.StringTokenizer;

/**
 * ExpressionMatcher is used to compare Expression in various matching modes.
 *
 * @author Martin Fuchs
 */
public class ExpressionMatcher {
    public static final String PM_SEPARATOR = "|";

    // There are some patterns that can be used as leading flags in expression strings, e.g. "|EXACT|":
    static final String PM_TYPE_MATCH = "TYPE";
    static final String PM_EXACT_MATCH = "EXACT";
    static final String PM_SIMILAR_MATCH = "SIMILAR";
    static final String PM_ICASE_MATCH = "ICASE";
    static final String PM_JOKER_MATCH = "JOKER";


    /** Flag to enable type string matching. */
    protected boolean typeMatching = false;

    /** Flag to enforce exact expression matching. */
    protected boolean exactMatching = false;

    /** Flag to use similarity matching. */
    protected boolean similarMatching = false;

    /** Flag to enable case insensitive matching. */
    protected boolean caseInsensitive = false;

    /** Flag to enable joker matching. */
    protected boolean jokerMatching = false;

    /** Reset all matching flags. */
    public void clear() {
        typeMatching = false;
        exactMatching = false;
        similarMatching = false;
        caseInsensitive = false;
        jokerMatching = false;
    }

    /**
     * @param typeMatching
     *            the typeMatching to set
     */
    public void setTypeMatching(final boolean typeMatching) {
        this.typeMatching = typeMatching;
    }

    /**
     * @return the typeMatching
     */
    public boolean getTypeMatching() {
        return typeMatching;
    }

    /**
     * @param exactMatching
     *            the exactMatching to set
     */
    public void setExactMatching(final boolean exactMatching) {
        this.exactMatching = exactMatching;
    }

    /**
     * @return the exactMatching
     */
    public boolean getExactMatching() {
        return exactMatching;
    }

    /**
     * @param similarMatching
     *            the similarMatching to set
     */
    public void setSimilarMatching(final boolean similarMatching) {
        this.similarMatching = similarMatching;
    }

    /**
     * @return the similarMatching
     */
    public boolean getSimilarMatching() {
        return similarMatching;
    }

    /**
     * @param caseInsensitive
     *            the caseInsensitive to set
     */
    public void setCaseInsensitive(final boolean caseInsensitive) {
        this.caseInsensitive = caseInsensitive;
    }

    /**
     * @return the caseInsensitive
     */
    public boolean isCaseInsensitive() {
        return caseInsensitive;
    }

    /**
     * @return the jokerMatching
     */
    public boolean isJokerMatching() {
        return jokerMatching;
    }

    /**
     * @param jokerMatching
     *            the jokerMatching to set
     */
    public void setjokerMatching(final boolean jokerMatching) {
        this.jokerMatching = jokerMatching;
    }

    /**
     *
     * @return true if any of the available matching flags is set.
     */
    public boolean isAnyFlagSet() {
        return typeMatching || exactMatching || similarMatching || caseInsensitive || jokerMatching;
    }

    /**
     * @return true if none of the available matching flags is set.
     *
     * 
     */
    public boolean isEmpty() {
        return !isAnyFlagSet();
    }

    /**
     * Read leading matching flags from the given text string and return the remaining text.
     *
     * @param text
     * @return text without leading flags
     */
    public String readMatchingFlags(String text) {
        clear();

        if (text.startsWith(PM_SEPARATOR)) {
            final StringTokenizer tok = new StringTokenizer(text, PM_SEPARATOR);

            while (tok.hasMoreTokens()) {
                final String flag = tok.nextToken();

                if (flag.equals(PM_TYPE_MATCH)) {
                    typeMatching = true;
                } else if (flag.equals(PM_EXACT_MATCH)) {
                    exactMatching = true;
                } else if (flag.equals(PM_SIMILAR_MATCH)) {
                    similarMatching = true;
                } else if (flag.equals(PM_ICASE_MATCH)) {
                    caseInsensitive = true;
                } else if (flag.equals(PM_JOKER_MATCH)) {
                    jokerMatching = true;
                } else {
                    break;
                }

                text = text.substring(flag.length() + 1);
            }

            if (isAnyFlagSet()) {
                // strip the last separator character
                text = text.substring(1);
            }
        }

        return text;
    }

    /**
     * Parse the given text string and create a Sentence object using the current matching flags.
     *
     * @param text
     * @param ctx
     * @return parsed Sentence
     */
    Sentence parseSentence(String text, final ConversationContext ctx) {
        if (isEmpty()) {
            return ConversationParser.parse(text, ctx);
        }

        final Sentence sentence = new SentenceImplementation(ctx);

        // determine sentence type from trailing punctuation
        text = ConversationParser.getSentenceType(text.trim(), sentence);

        if (typeMatching) {
            readTypeMatchExpressions(text, ctx, sentence);
        } else if (exactMatching) {
            readSimpleExpressions(text, ctx, sentence);
        } else if (similarMatching) {
            readSimpleExpressions(text, ctx, sentence);
        } else if (jokerMatching) {
            readJokerExpressions(text, ctx, sentence);
        } else if (caseInsensitive) {
            readSimpleExpressions(text, ctx, sentence);
        }

        return sentence;
    }

    /**
     * Reads in the expressions from the given string in prepared form. The given text should be in the format:
     * "<expression>/<TYPESTRING> <expression>/<TYPESTRING> ..."
     *
     * @param text to be parsed
     * @param ctx 
     * @param sentence 
     */
    private void readTypeMatchExpressions(final String text, final ConversationContext ctx, final Sentence sentence) {
        final StringTokenizer tok = new StringTokenizer(text, "/");

        while (tok.hasMoreTokens()) {
            final String str = tok.nextToken();
            String typeStr;

            try {
                // remove the leading slash from the type string
                typeStr = tok.nextToken(" \t\n\r\f").substring(1);
            } catch (final NoSuchElementException e) {
                typeStr = "*";
            }

            final Expression expr = new Expression(str, typeStr);
            expr.setMatcher(this);
            sentence.expressions.add(expr);
        }
    }

    /**
     * Read in the words from the given string and create the Sentence object using this unchanged expressions.
     *
     * @param text to be parsed
     * @param ctx 
     * @param sentence 
     */
    private void readSimpleExpressions(final String text, final ConversationContext ctx, final Sentence sentence) {
        final StringTokenizer tok = new StringTokenizer(text);

        while (tok.hasMoreTokens()) {
            final String str = tok.nextToken();

            final Expression expr = new Expression(str);
            expr.setNormalized(str);
            expr.setMatcher(this);
            sentence.expressions.add(expr);
        }
    }

    /**
     * Read in the words from the given string and create the sentence using the same rules as in SentenceImplementation
     * with activated 'forMatching' flag.
     *
     * @param text to be parsed
     * @param ctx 
     * @param sentence 
     */
    private void readJokerExpressions(final String text, final ConversationContext ctx, final Sentence sentence) {
        final StringTokenizer tok = new StringTokenizer(text);

        while (tok.hasMoreTokens()) {
            final String str = tok.nextToken();

            final Expression expr = new Expression(str);

            if (ExpressionType.isTypeString(str)) {
                expr.setType(new ExpressionType(str));
                expr.setNormalized(Expression.JOKER);
            } else {
                expr.setNormalized(str);
            }

            expr.setMatcher(this);
            sentence.expressions.add(expr);
        }
    }

    /**
     * Match two Expressions using the mode in matchingFlags.
     *
     * @param expr1
     * @param expr2
     * @return true if 2 expression match 
     */
    public boolean match(final Expression expr1, final Expression expr2) {
        // In type matching mode, the word type has to match exactly.
        if (typeMatching) {
            if (!expr1.getTypeString().equals(expr2.getTypeString())) {
                return false;
            }
        }

        // If the original expression matches, return true.
        if (expr1.getOriginal().equals(expr2.getOriginal())) {
            return true;
        }

        if (caseInsensitive) {
            if (expr1.getOriginal().equalsIgnoreCase(expr2.getOriginal())) {
                return true;
            }
        }

        if (jokerMatching) {
            return expr1.sentenceMatchExpression(expr2);
        }

        if (similarMatching) {
            if (SimilarExprMatcher.isSimilar(expr1.getOriginal(), expr2.getOriginal(), 0.1)) {
                return true;
            }
        }

        // If no exact match is required, compare the normalized expressions.
        if (!exactMatching) {
            if (expr2.getNormalized().equals(Expression.JOKER)) {
                return true;
            }

            if (expr1.getNormalized().equals(expr2.getNormalized())) {
                return true;
            }

            if (caseInsensitive) {
                if (expr1.getNormalized().equalsIgnoreCase(expr2.getNormalized())) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Check for equality of two ExpressionMatcher objects.
     */
    @Override
    public boolean equals(final Object other) {
        if (this == other) {
            return true;
        } else if (other == null) {
            return false;
        } else if (other instanceof ExpressionMatcher) {
            final ExpressionMatcher o = (ExpressionMatcher) other;

            if (typeMatching != o.typeMatching) {
                return false;
            } else if (exactMatching != o.exactMatching) {
                return false;
            } else if (similarMatching != o.similarMatching) {
                return false;
            } else if (caseInsensitive != o.caseInsensitive) {
                return false;
            } else {
                return (jokerMatching == o.jokerMatching);
            }

        } else {
            return false;
        }
    }

    /**
     * Returns a hash code for this ExpressionMatcher object.
     */
    @Override
    public int hashCode() {
        int hash = 0;

        if (typeMatching) {
            hash |= 1;
        }

        if (exactMatching) {
            hash |= 2;
        }

        if (similarMatching) {
            hash |= 4;
        }

        if (caseInsensitive) {
            hash |= 8;
        }

        if (jokerMatching) {
            hash |= 0x10;
        }

        return hash;
    }

    /**
     * Return a simple string representation.
     */
    @Override
    public String toString() {
        final StringBuilder b = new StringBuilder();

        if (typeMatching) {
            b.append(PM_SEPARATOR);
            b.append(PM_TYPE_MATCH);
        }

        if (exactMatching) {
            b.append(PM_SEPARATOR);
            b.append(PM_EXACT_MATCH);
        }

        if (similarMatching) {
            b.append(PM_SEPARATOR);
            b.append(PM_SIMILAR_MATCH);
        }

        if (caseInsensitive) {
            b.append(PM_SEPARATOR);
            b.append(PM_ICASE_MATCH);
        }

        if (jokerMatching) {
            b.append(PM_SEPARATOR);
            b.append(PM_JOKER_MATCH);
        }

        return b.toString();
    }

}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.