emit(fixup(av[1]))
elif op is CHARSET:
code.extend(av)
+ elif op is BIGCHARSET:
+ code.extend(av)
elif op is CATEGORY:
if flags & SRE_FLAG_LOCALE:
emit(CHCODES[CH_LOCALE[av]])
return charset # cannot compress
except IndexError:
# character set contains unicode characters
- return charset
+ return _optimize_unicode(charset, fixup)
# compress character map
i = p = n = 0
runs = []
return out
else:
# use bitmap
- data = []
- m = 1; v = 0
- for c in charmap:
- if c:
- v = v + m
- m = m << 1
- if m > MAXCODE:
- data.append(v)
- m = 1; v = 0
+ data = _mk_bitmap(charmap)
out.append((CHARSET, data))
return out
return charset
+def _mk_bitmap(bits):
+ data = []
+ m = 1; v = 0
+ for c in bits:
+ if c:
+ v = v + m
+ m = m << 1
+ if m > MAXCODE:
+ data.append(v)
+ m = 1; v = 0
+ return data
+
+# To represent a big charset, first a bitmap of all characters in the
+# set is constructed. Then, this bitmap is sliced into chunks of 256
+# characters, duplicate chunks are eliminitated, and each chunk is
+# given a number. In the compiled expression, the charset is
+# represented by a 16-bit word sequence, consisting of one word for
+# the number of different chunks, a sequence of 256 bytes (128 words)
+# of chunk numbers indexed by their original chunk position, and a
+# sequence of chunks (16 words each).
+
+# Compression is normally good: in a typical charset, large ranges of
+# Unicode will be either completely excluded (e.g. if only cyrillic
+# letters are to be matched), or completely included (e.g. if large
+# subranges of Kanji match). These ranges will be represented by
+# chunks of all one-bits or all zero-bits.
+
+# Matching can be also done efficiently: the more significant byte of
+# the Unicode character is an index into the chunk number, and the
+# less significant byte is a bit index in the chunk (just like the
+# CHARSET matching).
+
+def _optimize_unicode(charset, fixup):
+ charmap = [0]*65536
+ negate = 0
+ for op, av in charset:
+ if op is NEGATE:
+ negate = 1
+ elif op is LITERAL:
+ charmap[fixup(av)] = 1
+ elif op is RANGE:
+ for i in range(fixup(av[0]), fixup(av[1])+1):
+ charmap[i] = 1
+ elif op is CATEGORY:
+ # XXX: could expand category
+ return charset # cannot compress
+ if negate:
+ for i in range(65536):
+ charmap[i] = not charmap[i]
+ comps = {}
+ mapping = [0]*256
+ block = 0
+ data = []
+ for i in range(256):
+ chunk = tuple(charmap[i*256:(i+1)*256])
+ new = comps.setdefault(chunk, block)
+ mapping[i] = new
+ if new == block:
+ block += 1
+ data += _mk_bitmap(chunk)
+ header = [block]
+ assert MAXCODE == 65535
+ for i in range(128):
+ header.append(mapping[2*i]+256*mapping[2*i+1])
+ data[0:0] = header
+ return [(BIGCHARSET, data)]
+
def _simple(av):
# check if av is a "simple" operator
lo, hi = av[2].getwidth()
* See the _sre.c file for information on usage and redistribution.
*/
-#define SRE_MAGIC 20010320
+#define SRE_MAGIC 20010701
#define SRE_OP_FAILURE 0
#define SRE_OP_SUCCESS 1
#define SRE_OP_ANY 2
#define SRE_OP_CALL 8
#define SRE_OP_CATEGORY 9
#define SRE_OP_CHARSET 10
-#define SRE_OP_GROUPREF 11
-#define SRE_OP_GROUPREF_IGNORE 12
-#define SRE_OP_IN 13
-#define SRE_OP_IN_IGNORE 14
-#define SRE_OP_INFO 15
-#define SRE_OP_JUMP 16
-#define SRE_OP_LITERAL 17
-#define SRE_OP_LITERAL_IGNORE 18
-#define SRE_OP_MARK 19
-#define SRE_OP_MAX_UNTIL 20
-#define SRE_OP_MIN_UNTIL 21
-#define SRE_OP_NOT_LITERAL 22
-#define SRE_OP_NOT_LITERAL_IGNORE 23
-#define SRE_OP_NEGATE 24
-#define SRE_OP_RANGE 25
-#define SRE_OP_REPEAT 26
-#define SRE_OP_REPEAT_ONE 27
-#define SRE_OP_SUBPATTERN 28
+#define SRE_OP_BIGCHARSET 11
+#define SRE_OP_GROUPREF 12
+#define SRE_OP_GROUPREF_IGNORE 13
+#define SRE_OP_IN 14
+#define SRE_OP_IN_IGNORE 15
+#define SRE_OP_INFO 16
+#define SRE_OP_JUMP 17
+#define SRE_OP_LITERAL 18
+#define SRE_OP_LITERAL_IGNORE 19
+#define SRE_OP_MARK 20
+#define SRE_OP_MAX_UNTIL 21
+#define SRE_OP_MIN_UNTIL 22
+#define SRE_OP_NOT_LITERAL 23
+#define SRE_OP_NOT_LITERAL_IGNORE 24
+#define SRE_OP_NEGATE 25
+#define SRE_OP_RANGE 26
+#define SRE_OP_REPEAT 27
+#define SRE_OP_REPEAT_ONE 28
+#define SRE_OP_SUBPATTERN 29
#define SRE_AT_BEGINNING 0
#define SRE_AT_BEGINNING_LINE 1
#define SRE_AT_BEGINNING_STRING 2