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-2009, 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 base_regex = '[\\'+'\\'.join(tokenize_chars)+']*'
122
124 """
125 @param devwindow: If more than devwindow user agents match,
126 return empty device.
127 @type devwindow: integer
128 """
129 self.devwindow = devwindow
130
132 """
133 @param s: The user agent to tokenize
134 @type s: string
135 """
136 for d in self.tokenize_chars:
137 s = s.replace(d, ' ')
138 return [re.escape(x) for x in s.split()]
139
141 """
142 @param ua: The user agent
143 @type ua: string
144 @param devices: The devices object to search
145 @type devices: Devices
146 @rtype: Device
147 """
148 uas = devices.devuas.keys()
149 tokens = self._tokenize(ua)
150 regex = ''
151 for t in tokens:
152 if regex:
153 regex += self.base_regex + t
154 else:
155 regex += t
156
157 regex2 = regex + '.*'
158
159 uare = re.compile(regex2, re.I)
160 uas2 = [x for x in uas if uare.match(x)]
161
162
163
164
165
166 if len(uas2) == 0 and len(uas) > self.devwindow:
167 return devices.devids['generic']
168 elif len(uas2) == 0 and len(uas) <= self.devwindow:
169
170 return devices.devuas[uas[0]]
171
172
173 if len(uas2) == 1:
174
175 return devices.devuas[uas2[0]]
176
177
178 uas = uas2
179
180
181
182
183
184 if len(uas2) > self.devwindow:
185 return devices.devids['generic']
186 else:
187
188 return devices.devuas[uas2[0]]
189