1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 __doc__ = \
21 """
22 pywurfl search algorithms
23 """
24
25 import re
26
27 from pywurfl.exceptions import DeviceNotFound
28
29
30 __author__ = "Armand Lynch <lyncha@users.sourceforge.net>"
31 __copyright__ = "Copyright 2006, Armand Lynch"
32 __license__ = "LGPL"
33 __url__ = "http://celljam.net/"
34
35
37 """
38 Base class for all pywurfl search algorithms
39 """
41 """
42 Every pywurfl algorithm class must define a __call__ method.
43
44 @param ua: The user agent
45 @type ua: string
46 @param devices: The devices object to search
47 @type devices: Devices
48 @rtype: Device
49 """
50 raise NotImplementedError
51
52
53 try:
54 import Levenshtein
55
57 """
58 Jaro-Winkler Search Algorithm
59 """
60
61 - def __init__(self, accuracy=1.0, weight=0.05):
62 """
63 @param accuracy: The tolerance that the Jaro-Winkler algorithm will
64 use to determine if a user agent matches
65 0.0 <= accuracy <= 1.0
66 @type accuracy: float
67 @param weight: The prefix weight is inverse value of common prefix
68 length sufficient to consider the strings
69 'identical' (excerpt from the Levenshtein module
70 documentation).
71 @type weight: float
72 """
73
74 self.accuracy = accuracy
75 self.weight = weight
76
78 """
79 @param ua: The user agent
80 @type ua: string
81 @param devices: The devices object to search
82 @type devices: Devices
83 @rtype: Device
84 @raises pywurfl.DeviceNotFound
85 """
86 match = max((Levenshtein.jaro_winkler(x, ua, self.weight), x) for
87 x in devices.devuas)
88 if match[0] >= self.accuracy:
89 return devices.devuas[match[1]]
90 else:
91 raise DeviceNotFound(ua)
92
93
95 """
96 Levenshtein distance Search Algorithm
97 """
98
100 """
101 @param ua: The user agent
102 @type ua: string
103 @param devices: The devices object to search
104 @type devices: Devices
105 @rtype: Device
106 """
107
108 match = max((Levenshtein.distance(ua, x), x) for x in
109 devices.devuas)
110 return devices.devuas[match[1]]
111
112 except ImportError:
113 pass
114
115
117 """
118 Tokenizer Search Algorithm
119 """
120 tokenize_chars = ('/', '.', '-', '_', ' ')
121
123 """
124 @param devwindow: If more than devwindow user agents match,
125 return empty device.
126 @type devwindow: integer
127 """
128 self.devwindow = devwindow
129
131 """
132 @param s: The user agent to tokenize
133 @type s: string
134 """
135 for d in self.tokenize_chars:
136 s = s.replace(d, ' ')
137 return [re.escape(x) for x in s.split()]
138
140 """
141 @param ua: The user agent
142 @type ua: string
143 @param devices: The devices object to search
144 @type devices: Devices
145 @rtype: Device
146 """
147 uas = devices.devuas.keys()
148 tokens = self._tokenize(ua)
149 regex = ''
150 for t in tokens:
151 if regex:
152 regex += '[\/\.\-_ ]*' + t
153 else:
154 regex += t
155
156 regex2 = regex + '.*'
157
158 uare = re.compile(regex2, re.I)
159 uas2 = [x for x in uas if uare.match(x)]
160
161
162
163
164
165 if len(uas2) == 0 and len(uas) > self.devwindow:
166 return devices.devids['generic']
167 elif len(uas2) == 0 and len(uas) <= self.devwindow:
168
169 return devices.devuas[uas[0]]
170
171
172 if len(uas2) == 1:
173
174 return devices.devuas[uas2[0]]
175
176
177 uas = uas2
178
179
180
181
182
183 if len(uas2) > self.devwindow:
184 return devices.devids['generic']
185 else:
186
187 return devices.devuas[uas2[0]]
188