Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions rivescript/sorting.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from .regexp import RE
from . import utils
import re
from operator import itemgetter, attrgetter
from operator import attrgetter
import sys


Expand All @@ -31,20 +31,30 @@ class TriggerObj(object):
star: Number of wildcards (``*``), excluding alphabetical wildcards, and numeric wildcards
pound: Number of numeric wildcards (``#``)
under: Number of alphabetical wildcards (``_``)
option: Number of optional tags ("[man]" in "hey [man]")
option: Number of optional tags ("[man]" in "hey [man]"), assume that the template is properly formatted
"""

def __init__(self, pattern, index, weight, inherit = sys.maxsize):
self.alphabet = pattern # Sort according to alphabet order i.e. haha < hihi
self.index = index # For rearrange items in the sorted array
self.weight = - weight # Negative weight to place i.e. -100 < 0
self.inherit = inherit # Low inherit takes precedence i.e. 0 < 1
self.wordcount = - utils.word_count(pattern) # Length -2 < -1
self.len = -len(self.alphabet) # Length -10 < -5
self.star = self.alphabet.count('*') # Number of wildcards 0 < 1
self.pound = self.alphabet.count('#') # Number of numeric wildcards 0 < 1
self.under = self.alphabet.count('_') # Number of alphabetical wildcards 0 < 1
self.option = self.alphabet.count('[') # Assume that the template is properly formatted 0 < 1
self.wordcount = - utils.word_count(pattern) # Length -2 < -1. Use `utils` for counting choice of wildcards
self.len = -len(self.alphabet) # Length -10 < -5
self.star = self.alphabet.count('*') # Number of wildcards 0 < 1
self.pound = self.alphabet.count('#') # Number of numeric wildcards 0 < 1
self.under = self.alphabet.count('_') # Number of alphabetical wildcards 0 < 1
self.option = self.alphabet.count('[') + self.alphabet.count('(') # Number of option 0 < 1

if self.star > 0:
if self.pound == 0 & self.under == 0 & self.option == 0: # Place single star last in the rank
self.pound = sys.maxsize
self.under = sys.maxsize
self.option = sys.maxsize
if self.wordcount == 0: # The special case for single star "*", or a grey case "* *"
self.wordcount = sys.maxsize # Make sure template "hello *" > "*"
# Without any words number of stars does not matter, they all mean match any.
self.star = sys.maxsize # Make sure "*" is last in the list, "* love *" > "*"


def sort_trigger_set(triggers, exclude_previous=True, say=None):
Expand Down
73 changes: 73 additions & 0 deletions tests/test_sorting.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import unicode_literals, absolute_import

from rivescript.exceptions import RS_ERR_MATCH
from .config import RiveScriptTestCase

class SortingTriggersTest(RiveScriptTestCase):
"""Topic tests."""

def test_sorting_triggers(self):
self.new("""
+ * you *
- 1

+ * are *
- 2

+ * how are you *
- 3

+ * hallo ween *
- 4

+ (hi|hii)
- 5

+ hello
- 6

+ hey [man]
- 7

+ good morning
- 8

+ *
- 9

+ hel lo
- 10

+ hi *
- 11

+ hi [*]
- 12
""")

sorted_triggers = {trig[0]:position for position, trig in enumerate(self.rs._brain.master._sorted["topics"]['random'])}

# 1) Atomic is first matched.
self.assertLess(sorted_triggers['hello'],sorted_triggers['hey [man]'])

# 2) Sorted by number of words
self.assertLess(sorted_triggers['hel lo'],sorted_triggers['hello'])
self.assertLess(sorted_triggers['* hallo ween *'],sorted_triggers['* are *'])

# 3) Sorted by length by characters
self.assertLess(sorted_triggers['good morning'],sorted_triggers['hel lo'])

# 4) Sorted by alphabetical order
self.assertLess(sorted_triggers['* are *'],sorted_triggers['* you *'])

# 5) Sorted by number of wildcard triggers
self.assertLess(sorted_triggers['hi *'],sorted_triggers['* you *'])

# 6) The `super catch all` (only single star `*`) should be least priority
self.assertEqual(sorted_triggers['*'],max(sorted_triggers.values()))
self.assertLess(sorted_triggers['hi [*]'],sorted_triggers['*']) # another check but will be covered by max check above