Fixed an issue with "Fuzzy" pattern matching that would not find names at certain times.

For example, before the fix, you could face the following issue: Create a bunch of boxes with @create:
box, box1, box2, box3 ... Now try to examine 'box'. This would not work - the game would tell you that there
were multiple matches - it just found "box" in all entries and went with that. So despite there only being one
thing named solely "box", you could not target it! This fix resolves this by giving precedence to exact matches
whenever they exist. I have only done it for the support routine behind local_and_global_search() though, there
are other search functions that uses django directly for fuzzy __in searches. I don't know how to add a similar
functionality to them.
/Griatch
This commit is contained in:
Griatch 2009-08-30 20:18:56 +00:00
parent c5c8505582
commit 68217072a6
4 changed files with 50 additions and 19 deletions

View file

@ -8,6 +8,7 @@ from src.channels.models import CommChannelMembership, CommChannel
from src import defines_global
from src import ansi
from src.util import functions_general
from src.objects.models import Object
from src.cmdtable import GLOBAL_CMD_TABLE
#from src.imc2.models import IMC2ChannelMapping
#from src.imc2.packets import IMC2PacketIceMsgBroadcasted
@ -324,7 +325,7 @@ def cmd_cboot(command):
if objname[0] == '*':
player_boot = True
objname = objname[1:]
bootobj = source_object.search_for_object(objname)
bootobj = Object.objects.player_name_search(objname)
if not bootobj:
source_object.emit_to("Object '%s' not found." % objname)
return
@ -517,7 +518,7 @@ def cmd_cchown(command):
source_object.emit_to("You don't control this channel.")
return
#find the new owner
new_owner = source_object.search_for_object(pname)
new_owner = Object.objects.player_name_search(pname)
if not new_owner:
source_object.emit_to("New owner '%s' not found." % pname)
return

View file

@ -65,7 +65,7 @@ class IMC2Protocol(StatefulTelnetProtocol):
packet.imc2_protocol = self
packet_str = str(packet.assemble())
logger.log_infomsg("IMC2: SENT> %s" % packet_str)
#logger.log_infomsg("IMC2: SENT> %s" % packet_str)
self.sendLine(packet_str)
def _parse_auth_response(self, line):

View file

@ -16,6 +16,13 @@ from src.objects.util import object as util_object
from src import defines_global
from src import logger
class UniqueMatch(Exception):
"""
This allows a fuzzy match to give precedence to a perfect match.
"""
def __init__(self,matchobj):
self.matchobj = matchobj
class ObjectManager(models.Manager):
def num_total_players(self):
"""
@ -96,6 +103,12 @@ class ObjectManager(models.Manager):
ostring: (string) The string to match against.
dbref_only: (bool) Only compare dbrefs.
limit_types: (list of int) A list of Object type numbers to filter by.
Note that the fuzzy matching gives precedence to exact matches; so if your
search query matches an object in the list exactly, it will be the only result.
This means that if the list contains [box,box11,box12], the search string 'box'
will only match the first entry since it is exact. The search 'box1' will however
match both box11 and box12 since neither is an exact match.
"""
if dbref_only:
if limit_types:
@ -103,10 +116,13 @@ class ObjectManager(models.Manager):
else:
return [prospect for prospect in searchlist if prospect.dbref_match(ostring)]
else:
if limit_types:
return [prospect for prospect in searchlist if prospect.name_match(ostring, match_type=match_type) and prospect.type in limit_types]
else:
return [prospect for prospect in searchlist if prospect.name_match(ostring, match_type=match_type)]
try:
if limit_types:
return [prospect for prospect in searchlist if prospect.name_match(ostring, match_type=match_type) and prospect.type in limit_types]
else:
return [prospect for prospect in searchlist if prospect.name_match(ostring, match_type=match_type)]
except UniqueMatch, e:
return [e.matchobj]
def object_totals(self):
@ -233,10 +249,11 @@ class ObjectManager(models.Manager):
# name and dbref comparisons against search_query.
if search_contents:
local_matches += self.list_search_object_namestr(searcher.get_contents(),
search_query, limit_types)
search_query, limit_types)
if search_location:
local_matches += self.list_search_object_namestr(searcher.get_location().get_contents(),
search_query, limit_types=limit_types)
local_matches += \
self.list_search_object_namestr(searcher.get_location().get_contents(),
search_query, limit_types=limit_types)
return local_matches
def get_user_from_email(self, uemail):

View file

@ -11,6 +11,7 @@ from django.contrib.auth.models import User, Group
from django.conf import settings
from src.objects.util import object as util_object
from src.objects.managers.object import ObjectManager
from src.objects.managers.object import UniqueMatch
from src.objects.managers.attribute import AttributeManager
from src.config.models import ConfigValue
from src.ansi import ANSITable, parse_ansi
@ -160,6 +161,8 @@ class Object(models.Model):
source_object: (Object) The Object doing the searching
ostring: (str) The string to match object names against.
Obs - To find a player
append * to the start of ostring.
"""
# This is the object that gets the duplicate/no match emits.
if not emit_to_obj:
@ -950,20 +953,30 @@ class Object(models.Model):
NOTE: A 'name' can be a dbref or the actual name of the object. See
dbref_match for an exclusively name-based match.
The fuzzy match gives precedence to exact matches by raising the
UniqueMatch Exception.
"""
if util_object.is_dbref(oname):
# First character is a pound sign, looks to be a dbref.
return self.dbref_match(oname)
elif match_type == "exact":
# Exact matching
name_chunks = self.name.lower().split(';')
for chunk in name_chunks:
if oname.lower() == chunk:
return True
return False
else:
# Fuzzy matching.
return oname.lower() in self.name.lower()
# Check if this is an exact match
oname = oname.lower()
name_chunks = self.name.lower().split(';')
# True=1, False=0, so if any hit, sum(result)>0.
exact_match = sum(map(lambda o: oname == o, name_chunks)) > 0
if match_type == "exact":
#return result outright
return exact_match
if match_type == "fuzzy":
if exact_match:
#even if a fuzzy match, an exact match is worth more
raise UniqueMatch(self)
else:
#not an exact match; use fuzzy matching
return oname in self.name.lower()
def filter_contents_from_str(self, oname):
"""