Update of /cvsroot/arianne/stendhal/src/games/stendhal/server/entity/npc/parser In directory sc8-pr-cvs11.sourceforge.net:/tmp/cvs-serv13169/src/games/stendhal/server/entity/npc/parser Modified Files: Sentence.java ExpressionMatcher.java Expression.java SentenceImplementation.java Added Files: JokerExprMatcher.java Log Message: add JokerExprMatcher Index: ExpressionMatcher.java =================================================================== RCS file: /cvsroot/arianne/stendhal/src/games/stendhal/server/entity/npc/parser/ExpressionMatcher.java,v retrieving revision 1.10 retrieving revision 1.11 diff -C2 -d -r1.10 -r1.11 *** ExpressionMatcher.java 5 Mar 2008 22:42:23 -0000 1.10 --- ExpressionMatcher.java 6 Mar 2008 00:34:12 -0000 1.11 *************** *** 15,18 **** --- 15,19 ---- final static String PM_EXACT_MATCH = "EXACT"; final static String PM_ICASE_MATCH = "ICASE"; + final static String PM_JOKER_MATCH = "JOKER"; public final static String PM_SEPARATOR = "|"; *************** *** 27,30 **** --- 28,34 ---- protected boolean caseInsensitive = false; + /** Flag to enable joker matching. */ + protected boolean jokerMatching = false; + /** Reset all matching flags. */ public void clear() { *************** *** 32,35 **** --- 36,40 ---- exactMatching = false; caseInsensitive = false; + jokerMatching = false; } *************** *** 77,80 **** --- 82,99 ---- /** + * @return the jokerMatching + */ + public boolean isJokerMatching() { + return jokerMatching; + } + + /** + * @param jokerMatching the jokerMatching to set + */ + public void setjokerMatching(boolean jokerMatching) { + this.jokerMatching = jokerMatching; + } + + /** * Return true if any of the available matching flags is set. * *************** *** 82,86 **** */ public boolean isAnyFlagSet() { ! return typeMatching || exactMatching || caseInsensitive; } --- 101,105 ---- */ public boolean isAnyFlagSet() { ! return typeMatching || exactMatching || caseInsensitive || jokerMatching; } *************** *** 115,118 **** --- 134,139 ---- } else if (flag.equals(PM_ICASE_MATCH)) { caseInsensitive = true; + } else if (flag.equals(PM_JOKER_MATCH)) { + jokerMatching = true; } else { break; *************** *** 143,146 **** --- 164,169 ---- } else if (exactMatching) { return readExactExpressions(text, ctx); + } else if (jokerMatching) { + return readJokerExpressions(text, ctx); } else { return ConversationParser.parse(text, ctx); *************** *** 167,170 **** --- 190,194 ---- typeStr = tok.nextToken(" \t\n\r\f").substring(1); } catch(NoSuchElementException e) { + //TODO mf - handle invalid input syntax without causing a NoSuchElementException e.printStackTrace(); typeStr = "???"; *************** *** 201,204 **** --- 225,256 ---- /** + * 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: Text to be parsed + * @return Sentence + */ + private Sentence readJokerExpressions(String text, ConversationContext ctx) { + SentenceImplementation sentence = new SentenceImplementation(ctx); + + StringTokenizer tok = new StringTokenizer(text); + while (tok.hasMoreTokens()) { + String str = tok.nextToken(); + + Expression expr = new Expression(str); + + if (ExpressionType.isTypeString(str)) { + expr.setType(new ExpressionType(str)); + expr.setNormalized(Expression.JOKER); + } + + expr.setMatcher(this); + sentence.expressions.add(expr); + } + + return sentence; + } + + /** * Match two Expressions using the mode in matchingFlags. * *************** *** 226,231 **** --- 278,291 ---- } + if (jokerMatching) { + return expr1.sentenceMatchExpression(expr2); + } + // 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; *************** *** 260,263 **** --- 320,325 ---- } else if (caseInsensitive != o.caseInsensitive) { return false; + } else if (jokerMatching != o.jokerMatching) { + return false; } else { return true; *************** *** 287,290 **** --- 349,356 ---- } + if (jokerMatching) { + hash |= 8; + } + return hash; } *************** *** 312,315 **** --- 378,386 ---- } + if (jokerMatching) { + b.append(PM_SEPARATOR); + b.append(PM_JOKER_MATCH); + } + return b.toString(); } Index: SentenceImplementation.java =================================================================== RCS file: /cvsroot/arianne/stendhal/src/games/stendhal/server/entity/npc/parser/SentenceImplementation.java,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** SentenceImplementation.java 1 Mar 2008 21:58:38 -0000 1.9 --- SentenceImplementation.java 6 Mar 2008 00:34:12 -0000 1.10 *************** *** 92,96 **** if (ExpressionType.isTypeString(original)) { w.setType(new ExpressionType(original)); ! w.setNormalized(JOKER); } } --- 92,96 ---- if (ExpressionType.isTypeString(original)) { w.setType(new ExpressionType(original)); ! w.setNormalized(Expression.JOKER); } } *************** *** 164,168 **** // Don't persist expressions used for joker matching. boolean persist = context.getPersistNewWords() ! && (!context.isForMatching() || !original.contains(JOKER)); // Add the unknown word to the word list. --- 164,168 ---- // Don't persist expressions used for joker matching. boolean persist = context.getPersistNewWords() ! && (!context.isForMatching() || !original.contains(Expression.JOKER)); // Add the unknown word to the word list. *************** *** 429,434 **** // don't merge if there are joker expressions if (context.isForMatching()) { ! if (curr.getNormalized().contains(JOKER) ! || next.getNormalized().contains(JOKER)) { continue; } --- 429,434 ---- // don't merge if there are joker expressions if (context.isForMatching()) { ! if (curr.getNormalized().contains(Expression.JOKER) ! || next.getNormalized().contains(Expression.JOKER)) { continue; } *************** *** 585,591 **** // don't merge if there are joker expressions if (context.isForMatching()) { ! if (first.getNormalized().contains(JOKER) ! || second.getNormalized().contains(JOKER) ! || third.getNormalized().contains(JOKER)) { continue; } --- 585,591 ---- // don't merge if there are joker expressions if (context.isForMatching()) { ! if (first.getNormalized().contains(Expression.JOKER) ! || second.getNormalized().contains(Expression.JOKER) ! || third.getNormalized().contains(Expression.JOKER)) { continue; } Index: Expression.java =================================================================== RCS file: /cvsroot/arianne/stendhal/src/games/stendhal/server/entity/npc/parser/Expression.java,v retrieving revision 1.28 retrieving revision 1.29 diff -C2 -d -r1.28 -r1.29 *** Expression.java 5 Mar 2008 22:42:23 -0000 1.28 --- Expression.java 6 Mar 2008 00:34:12 -0000 1.29 *************** *** 3,6 **** --- 3,8 ---- import games.stendhal.common.ErrorDrain; + import java.util.regex.Pattern; + /** *************** *** 37,40 **** --- 39,45 ---- public static final Expression emptyExpression = new Expression("", ""); + /** JOKER is a joker String used in pattern matches. */ + protected static final String JOKER = "*"; + /** * Create an Expression from the given original string. *************** *** 372,375 **** --- 377,382 ---- public boolean matches(final Expression other) { if (other != null) { + // If there is no override by an ExpressionMatcher in 'other', use the + // default rule and compare the original strings. if (other.matcher == null) { if (original.equals(other.original)) { *************** *** 377,380 **** --- 384,395 ---- } } else { + // If both Expressions contain a matcher object, first compare this. + if (matcher != null) { + if (!matcher.equals(other.matcher)) { + return false; + } + } + + // Now call the matcher to look if the Expression matches the defined rule. return other.matcher.match(this, other); } *************** *** 392,395 **** --- 407,412 ---- public boolean matchesNormalized(final Expression other) { if (other != null) { + // If there is no override by an ExpressionMatcher in 'other', use the + // default rule and compare the normalized strings. if (other.matcher == null) { if (getNormalized().equals(other.getNormalized())) { *************** *** 397,400 **** --- 414,424 ---- } } else { + // If both Expressions contain a matcher object, first compare this. + if (matcher != null) { + if (!matcher.equals(other.matcher)) { + return false; + } + } + return other.matcher.match(this, other); } *************** *** 412,415 **** --- 436,441 ---- public boolean matchesNormalizedBeginning(final Expression other) { if (other != null) { + // If there is no override by an ExpressionMatcher in 'other', use the + // default rule and compare the normalized strings. if (other.matcher == null) { if (getNormalized().startsWith(other.getNormalized())) { *************** *** 417,420 **** --- 443,448 ---- } } + + // We don't use ExpressionMatcher here when searching only for matches at the Expression start. } *************** *** 423,426 **** --- 451,505 ---- /** + * Check if the Expression matches the given matching Expression. + * The matching object can contain explicit expressions, which are + * compared after normalizing, or ExpressionType specifiers like + * "VER" or "SUB*" in upper case. This defines the joker matching + * algorithm for sentence matching, which chooses automatically + * between word and type matching, depending on which of word and + * word type string is given. + * + * @param other + * @return + */ + boolean sentenceMatchExpression(Expression other) { + String matchString = other.getNormalized(); + + if (matchString.contains(JOKER)) { + if (matchString.equals(JOKER)) { + // Type string matching is identified by a single "*" as normalized string expression. + if (!matchesJokerString(getTypeString(), other.getTypeString())) { + return false; + } + } else { + // Look for a normalized string match against the string containing a joker character. + if (!matchesJokerString(getNormalized(), matchString)) { + return false; + } + } + } else if (!matchesNormalized(other)) { + return false; + } + + return true; + } + + /** + * Match the given String against a pattern String containing JOKER characters. + * + * @param str + * @param matchString + * @return + */ + public static boolean matchesJokerString(String str, String matchString) { + if (str.equals(JOKER)) { + // Empty strings do not match the "*" joker. + return str.length() > 0; + } else { + // Convert the joker string into a regular expression and let the Pattern class do the work. + return Pattern.compile(matchString.replace(JOKER, ".*")).matcher(str).find(); + } + } + + /** * Check for equality of two Expression objects. */ --- NEW FILE: JokerExprMatcher.java --- package games.stendhal.server.entity.npc.parser; /** * ExactExpressionMatcher creates an ExpressionMatcher for joker matching. * This mode uses the Expression.sentenceMatchExpression() function of sentence * matching, which chooses automatically between word and type matching. * * @author Martin Fuchs */ public class JokerExprMatcher extends ExpressionMatcher { public JokerExprMatcher() { jokerMatching = true; } } Index: Sentence.java =================================================================== RCS file: /cvsroot/arianne/stendhal/src/games/stendhal/server/entity/npc/parser/Sentence.java,v retrieving revision 1.53 retrieving revision 1.54 diff -C2 -d -r1.53 -r1.54 *** Sentence.java 2 Mar 2008 20:32:27 -0000 1.53 --- Sentence.java 6 Mar 2008 00:34:12 -0000 1.54 *************** *** 7,11 **** import java.util.List; import java.util.Set; - import java.util.regex.Pattern; /** --- 7,10 ---- *************** *** 28,34 **** protected SentenceType sentenceType = SentenceType.UNDEFINED; - /** JOKER is a joker String used in pattern matches. */ - protected static final String JOKER = "*"; - List<Expression> expressions = new ArrayList<Expression>(); --- 27,30 ---- *************** *** 645,663 **** } ! String matchString = e2.getNormalized(); ! ! if (matchString.contains(JOKER)) { ! if (matchString.equals(JOKER)) { ! // Type string matching is identified by a single "*" as normalized string expression. ! if (!matchesJokerString(e1.getTypeString(), e2.getTypeString())) { ! return false; ! } ! } else { ! // Look for a normalized string match towards the string containing a joker character. ! if (!matchesJokerString(e1.getNormalized(), matchString)) { ! return false; ! } ! } ! } else if (!e1.matchesNormalized(e2)) { return false; } --- 641,645 ---- } ! if (!e1.sentenceMatchExpression(e2)) { return false; } *************** *** 676,696 **** /** - * Match the given String towards a pattern String containing JOKER characters. - * - * @param str - * @param matchString - * @return - */ - private boolean matchesJokerString(String str, String matchString) { - if (str.equals(JOKER)) { - // Empty strings do not match the "*" joker. - return str.length() > 0; - } else { - // Convert the joker string into a regular expression and let the Pattern class do the work. - return Pattern.compile(matchString.replace(JOKER, ".*")).matcher(str).find(); - } - } - - /** * Searches for a matching item name in the given Set. * --- 658,661 ---- |