]> git.lizzy.rs Git - rust.git/commitdiff
Add a regex crate to the Rust distribution.
authorAndrew Gallant <jamslam@gmail.com>
Fri, 25 Apr 2014 04:27:24 +0000 (00:27 -0400)
committerAndrew Gallant <jamslam@gmail.com>
Fri, 25 Apr 2014 04:27:24 +0000 (00:27 -0400)
Also adds a regex_macros crate, which provides natively compiled
regular expressions with a syntax extension.

Closes #3591.

RFC: 0007-regexps

23 files changed:
mk/crates.mk
src/README.md
src/doc/index.md
src/etc/regex-match-tests.py [new file with mode: 0755]
src/etc/regex-unicode-tables.py [new file with mode: 0755]
src/libregex/compile.rs [new file with mode: 0644]
src/libregex/lib.rs [new file with mode: 0644]
src/libregex/parse.rs [new file with mode: 0644]
src/libregex/re.rs [new file with mode: 0644]
src/libregex/test/bench.rs [new file with mode: 0644]
src/libregex/test/matches.rs [new file with mode: 0644]
src/libregex/test/mod.rs [new file with mode: 0644]
src/libregex/test/tests.rs [new file with mode: 0644]
src/libregex/testdata/LICENSE [new file with mode: 0644]
src/libregex/testdata/README [new file with mode: 0644]
src/libregex/testdata/basic.dat [new file with mode: 0644]
src/libregex/testdata/nullsubexpr.dat [new file with mode: 0644]
src/libregex/testdata/repetition.dat [new file with mode: 0644]
src/libregex/unicode.rs [new file with mode: 0644]
src/libregex/vm.rs [new file with mode: 0644]
src/libregex_macros/lib.rs [new file with mode: 0644]
src/test/bench/shootout-regex-dna.rs [new file with mode: 0644]
src/test/compile-fail/syntax-extension-regex-invalid.rs [new file with mode: 0644]

index 28330010dc2acc6c3939498c7b991687c4480a1c..fc0afa6df62711d8d8ace9828c378d2f9192d729 100644 (file)
@@ -51,8 +51,8 @@
 
 TARGET_CRATES := libc std green rustuv native flate arena glob term semver \
                  uuid serialize sync getopts collections num test time rand \
-                workcache url log
-HOST_CRATES := syntax rustc rustdoc fourcc hexfloat
+                workcache url log regex
+HOST_CRATES := syntax rustc rustdoc fourcc hexfloat regex_macros
 CRATES := $(TARGET_CRATES) $(HOST_CRATES)
 TOOLS := compiletest rustdoc rustc
 
@@ -84,6 +84,8 @@ DEPS_rand := std
 DEPS_url := std collections
 DEPS_workcache := std serialize collections log
 DEPS_log := std sync
+DEPS_regex := std collections
+DEPS_regex_macros = syntax std regex
 
 TOOL_DEPS_compiletest := test green rustuv getopts
 TOOL_DEPS_rustdoc := rustdoc native
index 0ac310df1b866499fb9dcb3e086213252aa35709..de9a793bafc9645783d5c4286da27324b7e24ae2 100644 (file)
@@ -19,6 +19,7 @@ Source layout:
 | `libfourcc/`        | Data format identifier library                            |
 | `libgetopts/`       | Get command-line-options library                          |
 | `libglob/`          | Unix glob patterns library                                |
+| `libregex/`         | Regular expressions                                       |
 | `libsemver/`        | Rust's semantic versioning library                        |
 | `libserialize/`     | Encode-Decode types library                               |
 | `libsync/`          | Concurrency mechanisms and primitives                     |
index 57d75d7fc469e696febe086f5cf1789d6e0b1f01..0bfc9baaa1688ad6002cf881fd38935053a4389e 100644 (file)
@@ -41,6 +41,7 @@ li {list-style-type: none; }
 * [The `native` 1:1 threading runtime](native/index.html)
 * [The `num` arbitrary precision numerics library](num/index.html)
 * [The `rand` library for random numbers and distributions](rand/index.html)
+* [The `regex` library for regular expressions](regex/index.html)
 * [The `rustc` compiler](rustc/index.html)
 * [The `rustuv` M:N I/O library](rustuv/index.html)
 * [The `semver` version collation library](semver/index.html)
diff --git a/src/etc/regex-match-tests.py b/src/etc/regex-match-tests.py
new file mode 100755 (executable)
index 0000000..826af96
--- /dev/null
@@ -0,0 +1,109 @@
+#!/usr/bin/env python2
+
+# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+from __future__ import absolute_import, division, print_function
+import argparse
+import datetime
+import os.path as path
+
+
+def print_tests(tests):
+    print('\n'.join([test_tostr(t) for t in tests]))
+
+
+def read_tests(f):
+    basename, _ = path.splitext(path.basename(f))
+    tests = []
+    for lineno, line in enumerate(open(f), 1):
+        fields = filter(None, map(str.strip, line.split('\t')))
+        if not (4 <= len(fields) <= 5) \
+           or 'E' not in fields[0] or fields[0][0] == '#':
+            continue
+
+        opts, pat, text, sgroups = fields[0:4]
+        groups = []  # groups as integer ranges
+        if sgroups == 'NOMATCH':
+            groups = [None]
+        elif ',' in sgroups:
+            noparen = map(lambda s: s.strip('()'), sgroups.split(')('))
+            for g in noparen:
+                s, e = map(str.strip, g.split(','))
+                if s == '?' and e == '?':
+                    groups.append(None)
+                else:
+                    groups.append((int(s), int(e)))
+        else:
+            # This skips tests that should result in an error.
+            # There aren't many, so I think we can just capture those
+            # manually. Possibly fix this in future.
+            continue
+
+        if pat == 'SAME':
+            pat = tests[-1][1]
+        if '$' in opts:
+            pat = pat.decode('string_escape')
+            text = text.decode('string_escape')
+        if 'i' in opts:
+            pat = '(?i)%s' % pat
+
+        name = '%s_%d' % (basename, lineno)
+        tests.append((name, pat, text, groups))
+    return tests
+
+
+def test_tostr(t):
+    lineno, pat, text, groups = t
+    options = map(group_tostr, groups)
+    return 'mat!(match_%s, r"%s", r"%s", %s)' \
+           % (lineno, pat, '' if text == "NULL" else text, ', '.join(options))
+
+
+def group_tostr(g):
+    if g is None:
+        return 'None'
+    else:
+        return 'Some((%d, %d))' % (g[0], g[1])
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(
+        description='Generate match tests from an AT&T POSIX test file.')
+    aa = parser.add_argument
+    aa('files', nargs='+',
+       help='A list of dat AT&T POSIX test files. See src/libregexp/testdata')
+    args = parser.parse_args()
+
+    tests = []
+    for f in args.files:
+        tests += read_tests(f)
+
+    tpl = '''// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+
+// DO NOT EDIT. Automatically generated by 'src/etc/regexp-match-tests'
+// on {date}.
+'''
+    print(tpl.format(date=str(datetime.datetime.now())))
+
+    for f in args.files:
+        print('// Tests from %s' % path.basename(f))
+        print_tests(read_tests(f))
+        print('')
diff --git a/src/etc/regex-unicode-tables.py b/src/etc/regex-unicode-tables.py
new file mode 100755 (executable)
index 0000000..5dc4047
--- /dev/null
@@ -0,0 +1,183 @@
+#!/usr/bin/env python2
+
+# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+from __future__ import absolute_import, division, print_function
+import argparse
+from collections import defaultdict
+import csv
+import datetime
+import urllib2
+
+BASE_URL = 'http://www.unicode.org/Public/6.3.0/ucd/'
+DATA = 'UnicodeData.txt'
+SCRIPTS = 'Scripts.txt'
+
+# Mapping taken from Table 12 from:
+# http://www.unicode.org/reports/tr44/#General_Category_Values
+expanded_categories = {
+    'Lu': ['LC', 'L'], 'Ll': ['LC', 'L'], 'Lt': ['LC', 'L'],
+    'Lm': ['L'], 'Lo': ['L'],
+    'Mn': ['M'], 'Mc': ['M'], 'Me': ['M'],
+    'Nd': ['N'], 'Nl': ['N'], 'No': ['No'],
+    'Pc': ['P'], 'Pd': ['P'], 'Ps': ['P'], 'Pe': ['P'],
+    'Pi': ['P'], 'Pf': ['P'], 'Po': ['P'],
+    'Sm': ['S'], 'Sc': ['S'], 'Sk': ['S'], 'So': ['S'],
+    'Zs': ['Z'], 'Zl': ['Z'], 'Zp': ['Z'],
+    'Cc': ['C'], 'Cf': ['C'], 'Cs': ['C'], 'Co': ['C'], 'Cn': ['C'],
+}
+
+
+def as_4byte_uni(n):
+    s = hex(n)[2:]
+    return '\\U%s%s' % ('0' * (8 - len(s)), s)
+
+
+def expand_cat(c):
+    return expanded_categories.get(c, []) + [c]
+
+
+def is_valid_unicode(n):
+    return 0 <= n <= 0xD7FF or 0xE000 <= n <= 0x10FFFF
+
+
+def read_cats(f):
+    assigned = defaultdict(list)
+    for row in csv.reader(f, delimiter=';'):
+        (hex, cats) = (int(row[0], 16), expand_cat(row[2]))
+        if not is_valid_unicode(hex):
+            continue
+        for cat in cats:
+            assigned[cat].append(hex)
+    return assigned
+
+
+def read_scripts(f):
+    assigned = defaultdict(list)
+    for line in f:
+        line = line.strip()
+        if not line or line.startswith('#'):
+            continue
+        hexes, name = map(str.strip, line.split(';'))[:2]
+        name = name[:name.index('#')].strip()
+        if '..' not in hexes:
+            hex = int(hexes, 16)
+            if is_valid_unicode(hex):
+                assigned[name].append(hex)
+        else:
+            hex1, hex2 = map(lambda s: int(s, 16), hexes.split('..'))
+            for hex in xrange(hex1, hex2 + 1):
+                if is_valid_unicode(hex):
+                    assigned[name].append(hex)
+    return assigned
+
+
+def group(letters):
+    letters = sorted(set(letters))
+    grouped = []
+    cur_start = letters.pop(0)
+    cur_end = cur_start
+    for letter in letters:
+        assert letter > cur_end, \
+            'cur_end: %s, letter: %s' % (hex(cur_end), hex(letter))
+
+        if letter == cur_end + 1:
+            cur_end = letter
+        else:
+            grouped.append((cur_start, cur_end))
+            cur_start, cur_end = letter, letter
+    grouped.append((cur_start, cur_end))
+    return grouped
+
+
+def ranges_to_rust(rs):
+    rs = ("('%s', '%s')" % (as_4byte_uni(s), as_4byte_uni(e)) for s, e in rs)
+    return ',\n    '.join(rs)
+
+
+def groups_to_rust(groups):
+    rust_groups = []
+    for group_name in sorted(groups):
+        rust_groups.append('("%s", &[\n    %s\n    ]),'
+                           % (group_name, ranges_to_rust(groups[group_name])))
+    return '\n'.join(rust_groups)
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(
+        description='Generate Unicode character class tables.')
+    aa = parser.add_argument
+    aa('--local', action='store_true',
+       help='When set, Scripts.txt and UnicodeData.txt will be read from '
+            'the CWD.')
+    aa('--base-url', type=str, default=BASE_URL,
+       help='The base URL to use for downloading Unicode data files.')
+    args = parser.parse_args()
+
+    if args.local:
+        cats = read_cats(open(DATA))
+        scripts = read_scripts(open(SCRIPTS))
+    else:
+        cats = read_cats(urllib2.urlopen(args.base_url + '/' + DATA))
+        scripts = read_scripts(urllib2.urlopen(args.base_url + '/' + SCRIPTS))
+
+    # Get Rust code for all Unicode general categories and scripts.
+    combined = dict(cats, **scripts)
+    unigroups = groups_to_rust({k: group(letters)
+                                for k, letters in combined.items()})
+
+    # Now get Perl character classes that are Unicode friendly.
+    perld = range(ord('0'), ord('9') + 1)
+    dgroups = ranges_to_rust(group(perld + cats['Nd'][:]))
+
+    perls = map(ord, ['\t', '\n', '\x0C', '\r', ' '])
+    sgroups = ranges_to_rust(group(perls + cats['Z'][:]))
+
+    low, up = (range(ord('a'), ord('z') + 1), range(ord('A'), ord('Z') + 1))
+    perlw = [ord('_')] + perld + low + up
+    wgroups = ranges_to_rust(group(perlw + cats['L'][:]))
+
+    tpl = '''// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// DO NOT EDIT. Automatically generated by 'src/etc/regexp-unicode-tables'
+// on {date}.
+
+use parse::{{Class, NamedClasses}};
+
+pub static UNICODE_CLASSES: NamedClasses = &[
+
+{groups}
+
+];
+
+pub static PERLD: Class = &[
+    {dgroups}
+];
+
+pub static PERLS: Class = &[
+    {sgroups}
+];
+
+pub static PERLW: Class = &[
+    {wgroups}
+];
+'''
+    now = datetime.datetime.now()
+    print(tpl.format(date=str(now), groups=unigroups,
+                     dgroups=dgroups, sgroups=sgroups, wgroups=wgroups))
diff --git a/src/libregex/compile.rs b/src/libregex/compile.rs
new file mode 100644 (file)
index 0000000..3987d75
--- /dev/null
@@ -0,0 +1,274 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Enable this to squash warnings due to exporting pieces of the representation
+// for use with the regex! macro. See lib.rs for explanation.
+#![allow(visible_private_types)]
+
+use std::cmp;
+use std::iter;
+use parse;
+use parse::{
+    Flags, FLAG_EMPTY,
+    Nothing, Literal, Dot, Class, Begin, End, WordBoundary, Capture, Cat, Alt,
+    Rep,
+    ZeroOne, ZeroMore, OneMore,
+};
+
+type InstIdx = uint;
+
+#[deriving(Show, Clone)]
+pub enum Inst {
+    // When a Match instruction is executed, the current thread is successful.
+    Match,
+
+    // The OneChar instruction matches a literal character.
+    // The flags indicate whether to do a case insensitive match.
+    OneChar(char, Flags),
+
+    // The CharClass instruction tries to match one input character against
+    // the range of characters given.
+    // The flags indicate whether to do a case insentivie match and whether
+    // the character class is negated or not.
+    CharClass(Vec<(char, char)>, Flags),
+
+    // Matches any character except new lines.
+    // The flags indicate whether to include the '\n' character.
+    Any(Flags),
+
+    // Matches the beginning of the string, consumes no characters.
+    // The flags indicate whether it matches if the preceding character
+    // is a new line.
+    EmptyBegin(Flags),
+
+    // Matches the end of the string, consumes no characters.
+    // The flags indicate whether it matches if the proceding character
+    // is a new line.
+    EmptyEnd(Flags),
+
+    // Matches a word boundary (\w on one side and \W \A or \z on the other),
+    // and consumes no character.
+    // The flags indicate whether this matches a word boundary or something
+    // that isn't a word boundary.
+    EmptyWordBoundary(Flags),
+
+    // Saves the current position in the input string to the Nth save slot.
+    Save(uint),
+
+    // Jumps to the instruction at the index given.
+    Jump(InstIdx),
+
+    // Jumps to the instruction at the first index given. If that leads to
+    // a failing state, then the instruction at the second index given is
+    // tried.
+    Split(InstIdx, InstIdx),
+}
+
+/// Program represents a compiled regular expression. Once an expression is
+/// compiled, its representation is immutable and will never change.
+///
+/// All of the data in a compiled expression is wrapped in "MaybeStatic" or
+/// "MaybeOwned" types so that a `Program` can be represented as static data.
+/// (This makes it convenient and efficient for use with the `regex!` macro.)
+#[deriving(Clone)]
+pub struct Program {
+    /// A sequence of instructions.
+    pub insts: Vec<Inst>,
+    /// If the regular expression requires a literal prefix in order to have a
+    /// match, that prefix is stored here. (It's used in the VM to implement
+    /// an optimization.)
+    pub prefix: ~str,
+}
+
+impl Program {
+    /// Compiles a Regex given its AST.
+    pub fn new(ast: ~parse::Ast) -> (Program, ~[Option<~str>]) {
+        let mut c = Compiler {
+            insts: Vec::with_capacity(100),
+            names: Vec::with_capacity(10),
+        };
+
+        c.insts.push(Save(0));
+        c.compile(ast);
+        c.insts.push(Save(1));
+        c.insts.push(Match);
+
+        // Try to discover a literal string prefix.
+        // This is a bit hacky since we have to skip over the initial
+        // 'Save' instruction.
+        let mut pre = StrBuf::with_capacity(5);
+        for i in iter::range(1, c.insts.len()) {
+            match *c.insts.get(i) {
+                OneChar(c, FLAG_EMPTY) => pre.push_char(c),
+                _ => break
+            }
+        }
+
+        let names = c.names.as_slice().into_owned();
+        let prog = Program {
+            insts: c.insts,
+            prefix: pre.into_owned(),
+        };
+        (prog, names)
+    }
+
+    /// Returns the total number of capture groups in the regular expression.
+    /// This includes the zeroth capture.
+    pub fn num_captures(&self) -> uint {
+        let mut n = 0;
+        for inst in self.insts.iter() {
+            match *inst {
+                Save(c) => n = cmp::max(n, c+1),
+                _ => {}
+            }
+        }
+        // There's exactly 2 Save slots for every capture.
+        n / 2
+    }
+}
+
+struct Compiler<'r> {
+    insts: Vec<Inst>,
+    names: Vec<Option<~str>>,
+}
+
+// The compiler implemented here is extremely simple. Most of the complexity
+// in this crate is in the parser or the VM.
+// The only tricky thing here is patching jump/split instructions to point to
+// the right instruction.
+impl<'r> Compiler<'r> {
+    fn compile(&mut self, ast: ~parse::Ast) {
+        match ast {
+            ~Nothing => {},
+            ~Literal(c, flags) => self.push(OneChar(c, flags)),
+            ~Dot(nl) => self.push(Any(nl)),
+            ~Class(ranges, flags) =>
+                self.push(CharClass(ranges, flags)),
+            ~Begin(flags) => self.push(EmptyBegin(flags)),
+            ~End(flags) => self.push(EmptyEnd(flags)),
+            ~WordBoundary(flags) => self.push(EmptyWordBoundary(flags)),
+            ~Capture(cap, name, x) => {
+                let len = self.names.len();
+                if cap >= len {
+                    self.names.grow(10 + cap - len, &None)
+                }
+                *self.names.get_mut(cap) = name;
+
+                self.push(Save(2 * cap));
+                self.compile(x);
+                self.push(Save(2 * cap + 1));
+            }
+            ~Cat(xs) => {
+                for x in xs.move_iter() {
+                    self.compile(x)
+                }
+            }
+            ~Alt(x, y) => {
+                let split = self.empty_split(); // push: split 0, 0
+                let j1 = self.insts.len();
+                self.compile(x);                // push: insts for x
+                let jmp = self.empty_jump();    // push: jmp 0
+                let j2 = self.insts.len();
+                self.compile(y);                // push: insts for y
+                let j3 = self.insts.len();
+
+                self.set_split(split, j1, j2);  // split 0, 0 -> split j1, j2
+                self.set_jump(jmp, j3);         // jmp 0      -> jmp j3
+            }
+            ~Rep(x, ZeroOne, g) => {
+                let split = self.empty_split();
+                let j1 = self.insts.len();
+                self.compile(x);
+                let j2 = self.insts.len();
+
+                if g.is_greedy() {
+                    self.set_split(split, j1, j2);
+                } else {
+                    self.set_split(split, j2, j1);
+                }
+            }
+            ~Rep(x, ZeroMore, g) => {
+                let j1 = self.insts.len();
+                let split = self.empty_split();
+                let j2 = self.insts.len();
+                self.compile(x);
+                let jmp = self.empty_jump();
+                let j3 = self.insts.len();
+
+                self.set_jump(jmp, j1);
+                if g.is_greedy() {
+                    self.set_split(split, j2, j3);
+                } else {
+                    self.set_split(split, j3, j2);
+                }
+            }
+            ~Rep(x, OneMore, g) => {
+                let j1 = self.insts.len();
+                self.compile(x);
+                let split = self.empty_split();
+                let j2 = self.insts.len();
+
+                if g.is_greedy() {
+                    self.set_split(split, j1, j2);
+                } else {
+                    self.set_split(split, j2, j1);
+                }
+            }
+        }
+    }
+
+    /// Appends the given instruction to the program.
+    #[inline]
+    fn push(&mut self, x: Inst) {
+        self.insts.push(x)
+    }
+
+    /// Appends an *empty* `Split` instruction to the program and returns
+    /// the index of that instruction. (The index can then be used to "patch"
+    /// the actual locations of the split in later.)
+    #[inline]
+    fn empty_split(&mut self) -> InstIdx {
+        self.insts.push(Split(0, 0));
+        self.insts.len() - 1
+    }
+
+    /// Sets the left and right locations of a `Split` instruction at index
+    /// `i` to `pc1` and `pc2`, respectively.
+    /// If the instruction at index `i` isn't a `Split` instruction, then
+    /// `fail!` is called.
+    #[inline]
+    fn set_split(&mut self, i: InstIdx, pc1: InstIdx, pc2: InstIdx) {
+        let split = self.insts.get_mut(i);
+        match *split {
+            Split(_, _) => *split = Split(pc1, pc2),
+            _ => fail!("BUG: Invalid split index."),
+        }
+    }
+
+    /// Appends an *empty* `Jump` instruction to the program and returns the
+    /// index of that instruction.
+    #[inline]
+    fn empty_jump(&mut self) -> InstIdx {
+        self.insts.push(Jump(0));
+        self.insts.len() - 1
+    }
+
+    /// Sets the location of a `Jump` instruction at index `i` to `pc`.
+    /// If the instruction at index `i` isn't a `Jump` instruction, then
+    /// `fail!` is called.
+    #[inline]
+    fn set_jump(&mut self, i: InstIdx, pc: InstIdx) {
+        let jmp = self.insts.get_mut(i);
+        match *jmp {
+            Jump(_) => *jmp = Jump(pc),
+            _ => fail!("BUG: Invalid jump index."),
+        }
+    }
+}
diff --git a/src/libregex/lib.rs b/src/libregex/lib.rs
new file mode 100644 (file)
index 0000000..7dd27f1
--- /dev/null
@@ -0,0 +1,425 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This crate provides a native implementation of regular expressions that is
+//! heavily based on RE2 both in syntax and in implementation. Notably,
+//! backreferences and arbitrary lookahead/lookbehind assertions are not
+//! provided. In return, regular expression searching provided by this package
+//! has excellent worst case performance. The specific syntax supported is
+//! documented further down.
+//!
+//! This crate's documentation provides some simple examples, describes Unicode
+//! support and exhaustively lists the supported syntax. For more specific
+//! details on the API, please see the documentation for the `Regex` type.
+//!
+//! # First example: find a date
+//!
+//! General use of regular expressions in this package involves compiling an
+//! expression and then using it to search, split or replace text. For example,
+//! to confirm that some text resembles a date:
+//!
+//! ```rust
+//! use regex::Regex;
+//! let re = match Regex::new(r"^\d{4}-\d{2}-\d{2}$") {
+//!     Ok(re) => re,
+//!     Err(err) => fail!("{}", err),
+//! };
+//! assert_eq!(re.is_match("2014-01-01"), true);
+//! ```
+//!
+//! Notice the use of the `^` and `$` anchors. In this crate, every expression
+//! is executed with an implicit `.*?` at the beginning and end, which allows
+//! it to match anywhere in the text. Anchors can be used to ensure that the
+//! full text matches an expression.
+//!
+//! This example also demonstrates the utility of raw strings in Rust, which
+//! are just like regular strings except they are prefixed with an `r` and do
+//! not process any escape sequences. For example, `"\\d"` is the same
+//! expression as `r"\d"`.
+//!
+//! # The `regex!` macro
+//!
+//! Rust's compile time meta-programming facilities provide a way to write a
+//! `regex!` macro which compiles regular expressions *when your program
+//! compiles*. Said differently, if you only use `regex!` to build regular
+//! expressions in your program, then your program cannot compile with an
+//! invalid regular expression. Moreover, the `regex!` macro compiles the
+//! given expression to native Rust code, which makes it much faster for
+//! searching text.
+//!
+//! Since `regex!` provides compiled regular expressions that are both safer
+//! and faster to use, you should use them whenever possible. The only
+//! requirement for using them is that you have a string literal corresponding
+//! to your expression. Otherwise, it is indistinguishable from an expression
+//! compiled at runtime with `Regex::new`.
+//!
+//! To use the `regex!` macro, you must enable the `phase` feature and import
+//! the `regex_macros` crate as a syntax extension:
+//!
+//! ```rust
+//! #![feature(phase)]
+//! #[phase(syntax)]
+//! extern crate regex_macros;
+//! extern crate regex;
+//!
+//! fn main() {
+//!     let re = regex!(r"^\d{4}-\d{2}-\d{2}$");
+//!     assert_eq!(re.is_match("2014-01-01"), true);
+//! }
+//! ```
+//!
+//! There are a few things worth mentioning about using the `regex!` macro.
+//! Firstly, the `regex!` macro *only* accepts string *literals*.
+//! Secondly, the `regex` crate *must* be linked with the name `regex` since
+//! the generated code depends on finding symbols in the `regex` crate.
+//!
+//! The only downside of using the `regex!` macro is that it can increase the
+//! size of your program's binary since it generates specialized Rust code.
+//! The extra size probably won't be significant for a small number of
+//! expressions, but 100+ calls to `regex!` will probably result in a
+//! noticeably bigger binary.
+//!
+//! # Example: iterating over capture groups
+//!
+//! This crate provides convenient iterators for matching an expression
+//! repeatedly against a search string to find successive non-overlapping
+//! matches. For example, to find all dates in a string and be able to access
+//! them by their component pieces:
+//!
+//! ```rust
+//! # #![feature(phase)]
+//! # extern crate regex; #[phase(syntax)] extern crate regex_macros;
+//! # fn main() {
+//! let re = regex!(r"(\d{4})-(\d{2})-(\d{2})");
+//! let text = "2012-03-14, 2013-01-01 and 2014-07-05";
+//! for cap in re.captures_iter(text) {
+//!     println!("Month: {} Day: {} Year: {}", cap.at(2), cap.at(3), cap.at(1));
+//! }
+//! // Output:
+//! // Month: 03 Day: 14 Year: 2012
+//! // Month: 01 Day: 01 Year: 2013
+//! // Month: 07 Day: 05 Year: 2014
+//! # }
+//! ```
+//!
+//! Notice that the year is in the capture group indexed at `1`. This is
+//! because the *entire match* is stored in the capture group at index `0`.
+//!
+//! # Example: replacement with named capture groups
+//!
+//! Building on the previous example, perhaps we'd like to rearrange the date
+//! formats. This can be done with text replacement. But to make the code
+//! clearer, we can *name*  our capture groups and use those names as variables
+//! in our replacement text:
+//!
+//! ```rust
+//! # #![feature(phase)]
+//! # extern crate regex; #[phase(syntax)] extern crate regex_macros;
+//! # fn main() {
+//! let re = regex!(r"(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})");
+//! let before = "2012-03-14, 2013-01-01 and 2014-07-05";
+//! let after = re.replace_all(before, "$m/$d/$y");
+//! assert_eq!(after.as_slice(), "03/14/2012, 01/01/2013 and 07/05/2014");
+//! # }
+//! ```
+//!
+//! The `replace` methods are actually polymorphic in the replacement, which
+//! provides more flexibility than is seen here. (See the documentation for
+//! `Regex::replace` for more details.)
+//!
+//! # Pay for what you use
+//!
+//! With respect to searching text with a regular expression, there are three
+//! questions that can be asked:
+//!
+//! 1. Does the text match this expression?
+//! 2. If so, where does it match?
+//! 3. Where are the submatches?
+//!
+//! Generally speaking, this crate could provide a function to answer only #3,
+//! which would subsume #1 and #2 automatically. However, it can be
+//! significantly more expensive to compute the location of submatches, so it's
+//! best not to do it if you don't need to.
+//!
+//! Therefore, only use what you need. For example, don't use `find` if you
+//! only need to test if an expression matches a string. (Use `is_match`
+//! instead.)
+//!
+//! # Unicode
+//!
+//! This implementation executes regular expressions **only** on sequences of
+//! UTF8 codepoints while exposing match locations as byte indices.
+//!
+//! Currently, only naive case folding is supported. Namely, when matching
+//! case insensitively, the characters are first converted to their uppercase
+//! forms and then compared.
+//!
+//! Regular expressions themselves are also **only** interpreted as a sequence
+//! of UTF8 codepoints. This means you can embed Unicode characters directly
+//! into your expression:
+//!
+//! ```rust
+//! # #![feature(phase)]
+//! # extern crate regex; #[phase(syntax)] extern crate regex_macros;
+//! # fn main() {
+//! let re = regex!(r"(?i)Δ+");
+//! assert_eq!(re.find("ΔδΔ"), Some((0, 6)));
+//! # }
+//! ```
+//!
+//! Finally, Unicode general categories and scripts are available as character
+//! classes. For example, you can match a sequence of numerals, Greek or
+//! Cherokee letters:
+//!
+//! ```rust
+//! # #![feature(phase)]
+//! # extern crate regex; #[phase(syntax)] extern crate regex_macros;
+//! # fn main() {
+//! let re = regex!(r"[\pN\p{Greek}\p{Cherokee}]+");
+//! assert_eq!(re.find("abcΔᎠβⅠᏴγδⅡxyz"), Some((3, 23)));
+//! # }
+//! ```
+//!
+//! # Syntax
+//!
+//! The syntax supported in this crate is almost in an exact correspondence
+//! with the syntax supported by RE2.
+//!
+//! ## Matching one character
+//!
+//! <pre class="rust">
+//! .           any character except new line (includes new line with s flag)
+//! [xyz]       A character class matching either x, y or z.
+//! [^xyz]      A character class matching any character except x, y and z.
+//! [a-z]       A character class matching any character in range a-z.
+//! \d          Perl character class ([0-9])
+//! \D          Negated Perl character class ([^0-9])
+//! [:alpha:]   ASCII character class ([A-Za-z])
+//! [:^alpha:]  Negated ASCII character class ([^A-Za-z])
+//! \pN         One letter name Unicode character class
+//! \p{Greek}   Unicode character class (general category or script)
+//! \PN         Negated one letter name Unicode character class
+//! \P{Greek}   negated Unicode character class (general category or script)
+//! </pre>
+//!
+//! Any named character class may appear inside a bracketed `[...]` character
+//! class. For example, `[\p{Greek}\pN]` matches any Greek or numeral
+//! character.
+//!
+//! ## Composites
+//!
+//! <pre class="rust">
+//! xy    concatenation (x followed by y)
+//! x|y   alternation (x or y, prefer x)
+//! </pre>
+//!
+//! ## Repetitions
+//!
+//! <pre class="rust">
+//! x*        zero or more of x (greedy)
+//! x+        one or more of x (greedy)
+//! x?        zero or one of x (greedy)
+//! x*?       zero or more of x (ungreedy)
+//! x+?       one or more of x (ungreedy)
+//! x??       zero or one of x (ungreedy)
+//! x{n,m}    at least n and at most x (greedy)
+//! x{n,}     at least n x (greedy)
+//! x{n}      exactly n x
+//! x{n,m}?   at least n and at most x (ungreedy)
+//! x{n,}?    at least n x (ungreedy)
+//! x{n}?     exactly n x
+//! </pre>
+//!
+//! ## Empty matches
+//!
+//! <pre class="rust">
+//! ^     the beginning of text (or start-of-line with multi-line mode)
+//! $     the end of text (or end-of-line with multi-line mode)
+//! \A    only the beginning of text (even with multi-line mode enabled)
+//! \z    only the end of text (even with multi-line mode enabled)
+//! \b    a Unicode word boundary (\w on one side and \W, \A, or \z on other)
+//! \B    not a Unicode word boundary
+//! </pre>
+//!
+//! ## Grouping and flags
+//!
+//! <pre class="rust">
+//! (exp)          numbered capture group (indexed by opening parenthesis)
+//! (?P&lt;name&gt;exp)  named (also numbered) capture group (allowed chars: [_0-9a-zA-Z])
+//! (?:exp)        non-capturing group
+//! (?flags)       set flags within current group
+//! (?flags:exp)   set flags for exp (non-capturing)
+//! </pre>
+//!
+//! Flags are each a single character. For example, `(?x)` sets the flag `x`
+//! and `(?-x)` clears the flag `x`. Multiple flags can be set or cleared at
+//! the same time: `(?xy)` sets both the `x` and `y` flags and `(?x-y)` sets
+//! the `x` flag and clears the `y` flag.
+//!
+//! All flags are by default disabled. They are:
+//!
+//! <pre class="rust">
+//! i     case insensitive
+//! m     multi-line mode: ^ and $ match begin/end of line
+//! s     allow . to match \n
+//! U     swap the meaning of x* and x*?
+//! </pre>
+//!
+//! Here's an example that matches case insensitively for only part of the
+//! expression:
+//!
+//! ```rust
+//! # #![feature(phase)]
+//! # extern crate regex; #[phase(syntax)] extern crate regex_macros;
+//! # fn main() {
+//! let re = regex!(r"(?i)a+(?-i)b+");
+//! let cap = re.captures("AaAaAbbBBBb").unwrap();
+//! assert_eq!(cap.at(0), "AaAaAbb");
+//! # }
+//! ```
+//!
+//! Notice that the `a+` matches either `a` or `A`, but the `b+` only matches
+//! `b`.
+//!
+//! ## Escape sequences
+//!
+//! <pre class="rust">
+//! \*         literal *, works for any punctuation character: \.+*?()|[]{}^$
+//! \a         bell (\x07)
+//! \f         form feed (\x0C)
+//! \t         horizontal tab
+//! \n         new line
+//! \r         carriage return
+//! \v         vertical tab (\x0B)
+//! \123       octal character code (up to three digits)
+//! \x7F       hex character code (exactly two digits)
+//! \x{10FFFF} any hex character code corresponding to a valid UTF8 codepoint
+//! </pre>
+//!
+//! ## Perl character classes (Unicode friendly)
+//!
+//! <pre class="rust">
+//! \d     digit ([0-9] + \p{Nd})
+//! \D     not digit
+//! \s     whitespace ([\t\n\f\r ] + \p{Z})
+//! \S     not whitespace
+//! \w     word character ([0-9A-Za-z_] + \p{L})
+//! \W     not word character
+//! </pre>
+//!
+//! ## ASCII character classes
+//!
+//! <pre class="rust">
+//! [:alnum:]    alphanumeric ([0-9A-Za-z])
+//! [:alpha:]    alphabetic ([A-Za-z])
+//! [:ascii:]    ASCII ([\x00-\x7F])
+//! [:blank:]    blank ([\t ])
+//! [:cntrl:]    control ([\x00-\x1F\x7F])
+//! [:digit:]    digits ([0-9])
+//! [:graph:]    graphical ([!-~])
+//! [:lower:]    lower case ([a-z])
+//! [:print:]    printable ([ -~])
+//! [:punct:]    punctuation ([!-/:-@[-`{-~])
+//! [:space:]    whitespace ([\t\n\v\f\r ])
+//! [:upper:]    upper case ([A-Z])
+//! [:word:]     word characters ([0-9A-Za-z_])
+//! [:xdigit:]   hex digit ([0-9A-Fa-f])
+//! </pre>
+//!
+//! # Untrusted input
+//!
+//! There are two factors to consider here: untrusted regular expressions and
+//! untrusted search text.
+//!
+//! Currently, there are no counter-measures in place to prevent a malicious
+//! user from writing an expression that may use a lot of resources. One such
+//! example is to repeat counted repetitions: `((a{100}){100}){100}` will try
+//! to repeat the `a` instruction `100^3` times. Essentially, this means it's
+//! very easy for an attacker to exhaust your system's memory if they are
+//! allowed to execute arbitrary regular expressions. A possible solution to
+//! this is to impose a hard limit on the size of a compiled expression, but it
+//! does not yet exist.
+//!
+//! The story is a bit better with untrusted search text, since this crate's
+//! implementation provides `O(nm)` search where `n` is the number of
+//! characters in the search text and `m` is the number of instructions in a
+//! compiled expression.
+
+#![crate_id = "regex#0.11-pre"]
+#![crate_type = "rlib"]
+#![crate_type = "dylib"]
+#![experimental]
+#![license = "MIT/ASL2"]
+#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+       html_root_url = "http://static.rust-lang.org/doc/master")]
+
+#![feature(macro_rules, phase)]
+#![deny(missing_doc)]
+
+extern crate collections;
+#[cfg(test)]
+extern crate stdtest = "test";
+#[cfg(test)]
+extern crate rand;
+
+// During tests, this links with the `regex` crate so that the `regex!` macro
+// can be tested.
+#[cfg(test)]
+extern crate regex;
+
+pub use parse::Error;
+pub use re::{Regex, Captures, SubCaptures, SubCapturesPos};
+pub use re::{FindCaptures, FindMatches};
+pub use re::{Replacer, NoExpand, RegexSplits, RegexSplitsN};
+pub use re::{quote, is_match};
+
+mod compile;
+mod parse;
+mod re;
+mod vm;
+
+#[cfg(test)]
+mod test;
+
+/// The `program` module exists to support the `regex!` macro. Do not use.
+#[doc(hidden)]
+pub mod native {
+    // Exporting this stuff is bad form, but it's necessary for two reasons.
+    // Firstly, the `regex!` syntax extension is in a different crate and
+    // requires access to the representation of a regex (particularly the
+    // instruction set) in order to compile to native Rust. This could be
+    // mitigated if `regex!` was defined in the same crate, but this has
+    // undesirable consequences (such as requiring a dependency on
+    // `libsyntax`).
+    //
+    // Secondly, the code generated generated by `regex!` must *also* be able
+    // to access various functions in this crate to reduce code duplication
+    // and to provide a value with precisely the same `Regex` type in this
+    // crate. This, AFAIK, is impossible to mitigate.
+    //
+    // On the bright side, `rustdoc` lets us hide this from the public API
+    // documentation.
+    pub use compile::{
+        Program,
+        OneChar, CharClass, Any, Save, Jump, Split,
+        Match, EmptyBegin, EmptyEnd, EmptyWordBoundary,
+    };
+    pub use parse::{
+        FLAG_EMPTY, FLAG_NOCASE, FLAG_MULTI, FLAG_DOTNL,
+        FLAG_SWAP_GREED, FLAG_NEGATED,
+    };
+    pub use re::{Dynamic, Native};
+    pub use vm::{
+        MatchKind, Exists, Location, Submatches,
+        StepState, StepMatchEarlyReturn, StepMatch, StepContinue,
+        CharReader, find_prefix,
+    };
+}
diff --git a/src/libregex/parse.rs b/src/libregex/parse.rs
new file mode 100644 (file)
index 0000000..27510f0
--- /dev/null
@@ -0,0 +1,1028 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::char;
+use std::cmp;
+use std::fmt;
+use std::iter;
+use std::num;
+use std::str;
+
+/// Static data containing Unicode ranges for general categories and scripts.
+use self::unicode::{UNICODE_CLASSES, PERLD, PERLS, PERLW};
+#[allow(visible_private_types)]
+pub mod unicode;
+
+/// The maximum number of repetitions allowed with the `{n,m}` syntax.
+static MAX_REPEAT: uint = 1000;
+
+/// Error corresponds to something that can go wrong while parsing
+/// a regular expression.
+///
+/// (Once an expression is compiled, it is not possible to produce an error
+/// via searching, splitting or replacing.)
+pub struct Error {
+    /// The *approximate* character index of where the error occurred.
+    pub pos: uint,
+    /// A message describing the error.
+    pub msg: ~str,
+}
+
+impl fmt::Show for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f.buf, "Regex syntax error near position {}: {}",
+               self.pos, self.msg)
+    }
+}
+
+/// Represents the abstract syntax of a regular expression.
+/// It is showable so that error messages resulting from a bug can provide
+/// useful information.
+/// It is cloneable so that expressions can be repeated for the counted
+/// repetition feature. (No other copying is done.)
+///
+/// Note that this representation prevents one from reproducing the regex as
+/// it was typed. (But it could be used to reproduce an equivalent regex.)
+#[deriving(Show, Clone)]
+pub enum Ast {
+    Nothing,
+    Literal(char, Flags),
+    Dot(Flags),
+    Class(Vec<(char, char)>, Flags),
+    Begin(Flags),
+    End(Flags),
+    WordBoundary(Flags),
+    Capture(uint, Option<~str>, ~Ast),
+    // Represent concatenation as a flat vector to avoid blowing the
+    // stack in the compiler.
+    Cat(Vec<~Ast>),
+    Alt(~Ast, ~Ast),
+    Rep(~Ast, Repeater, Greed),
+}
+
+#[deriving(Show, Eq, Clone)]
+pub enum Repeater {
+    ZeroOne,
+    ZeroMore,
+    OneMore,
+}
+
+#[deriving(Show, Clone)]
+pub enum Greed {
+    Greedy,
+    Ungreedy,
+}
+
+impl Greed {
+    pub fn is_greedy(&self) -> bool {
+        match *self {
+            Greedy => true,
+            _ => false,
+        }
+    }
+
+    fn swap(self, swapped: bool) -> Greed {
+        if !swapped { return self }
+        match self {
+            Greedy => Ungreedy,
+            Ungreedy => Greedy,
+        }
+    }
+}
+
+/// BuildAst is a regrettable type that represents intermediate state for
+/// constructing an abstract syntax tree. Its central purpose is to facilitate
+/// parsing groups and alternations while also maintaining a stack of flag
+/// state.
+#[deriving(Show)]
+enum BuildAst {
+    Ast(~Ast),
+    Paren(Flags, uint, ~str), // '('
+    Bar, // '|'
+}
+
+impl BuildAst {
+    fn paren(&self) -> bool {
+        match *self {
+            Paren(_, _, _) => true,
+            _ => false,
+        }
+    }
+
+    fn flags(&self) -> Flags {
+        match *self {
+            Paren(flags, _, _) => flags,
+            _ => fail!("Cannot get flags from {}", self),
+        }
+    }
+
+    fn capture(&self) -> Option<uint> {
+        match *self {
+            Paren(_, 0, _) => None,
+            Paren(_, c, _) => Some(c),
+            _ => fail!("Cannot get capture group from {}", self),
+        }
+    }
+
+    fn capture_name(&self) -> Option<~str> {
+        match *self {
+            Paren(_, 0, _) => None,
+            Paren(_, _, ref name) => {
+                if name.len() == 0 {
+                    None
+                } else {
+                    Some(name.clone())
+                }
+            }
+            _ => fail!("Cannot get capture name from {}", self),
+        }
+    }
+
+    fn bar(&self) -> bool {
+        match *self {
+            Bar => true,
+            _ => false,
+        }
+    }
+
+    fn unwrap(self) -> Result<~Ast, Error> {
+        match self {
+            Ast(x) => Ok(x),
+            _ => fail!("Tried to unwrap non-AST item: {}", self),
+        }
+    }
+}
+
+/// Flags represents all options that can be twiddled by a user in an
+/// expression.
+pub type Flags = u8;
+
+pub static FLAG_EMPTY:      u8 = 0;
+pub static FLAG_NOCASE:     u8 = 1 << 0; // i
+pub static FLAG_MULTI:      u8 = 1 << 1; // m
+pub static FLAG_DOTNL:      u8 = 1 << 2; // s
+pub static FLAG_SWAP_GREED: u8 = 1 << 3; // U
+pub static FLAG_NEGATED:    u8 = 1 << 4; // char class or not word boundary
+
+struct Parser<'a> {
+    // The input, parsed only as a sequence of UTF8 code points.
+    chars: Vec<char>,
+    // The index of the current character in the input.
+    chari: uint,
+    // The intermediate state representing the AST.
+    stack: Vec<BuildAst>,
+    // The current set of flags.
+    flags: Flags,
+    // The total number of capture groups.
+    // Incremented each time an opening left paren is seen (assuming it is
+    // opening a capture group).
+    caps: uint,
+    // A set of all capture group names used only to detect duplicates.
+    names: Vec<~str>,
+}
+
+pub fn parse(s: &str) -> Result<~Ast, Error> {
+    Parser {
+        chars: s.chars().collect(),
+        chari: 0,
+        stack: vec!(),
+        flags: FLAG_EMPTY,
+        caps: 0,
+        names: vec!(),
+    }.parse()
+}
+
+impl<'a> Parser<'a> {
+    fn parse(&mut self) -> Result<~Ast, Error> {
+        loop {
+            let c = self.cur();
+            match c {
+                '?' | '*' | '+' => try!(self.push_repeater(c)),
+                '\\' => {
+                    let ast = try!(self.parse_escape());
+                    self.push(ast)
+                }
+                '{' => try!(self.parse_counted()),
+                '[' => match self.try_parse_ascii() {
+                    None => try!(self.parse_class()),
+                    Some(class) => self.push(class),
+                },
+                '(' => {
+                    if self.peek_is(1, '?') {
+                        try!(self.expect('?'))
+                        try!(self.parse_group_opts())
+                    } else {
+                        self.caps += 1;
+                        self.stack.push(Paren(self.flags, self.caps, ~""))
+                    }
+                }
+                ')' => {
+                    let catfrom = try!(
+                        self.pos_last(false, |x| x.paren() || x.bar()));
+                    try!(self.concat(catfrom));
+
+                    let altfrom = try!(self.pos_last(false, |x| x.paren()));
+                    // Before we smush the alternates together and pop off the
+                    // left paren, let's grab the old flags and see if we
+                    // need a capture.
+                    let (cap, cap_name, oldflags) = {
+                        let paren = self.stack.get(altfrom-1);
+                        (paren.capture(), paren.capture_name(), paren.flags())
+                    };
+                    try!(self.alternate(altfrom));
+                    self.flags = oldflags;
+
+                    // If this was a capture, pop what we just pushed in
+                    // alternate and make it a capture.
+                    if cap.is_some() {
+                        let ast = try!(self.pop_ast());
+                        self.push(~Capture(cap.unwrap(), cap_name, ast));
+                    }
+                }
+                '|' => {
+                    let catfrom = try!(
+                        self.pos_last(true, |x| x.paren() || x.bar()));
+                    try!(self.concat(catfrom));
+
+                    self.stack.push(Bar);
+                }
+                _ => try!(self.push_literal(c)),
+            }
+            if !self.next_char() {
+                break
+            }
+        }
+
+        // Try to improve error handling. At this point, there should be
+        // no remaining open parens.
+        if self.stack.iter().any(|x| x.paren()) {
+            return self.err("Unclosed parenthesis.")
+        }
+        let catfrom = try!(self.pos_last(true, |x| x.bar()));
+        try!(self.concat(catfrom));
+        try!(self.alternate(0));
+
+        assert!(self.stack.len() == 1);
+        self.pop_ast()
+    }
+
+    fn noteof(&mut self, expected: &str) -> Result<(), Error> {
+        match self.next_char() {
+            true => Ok(()),
+            false => self.err(format!("Expected {} but got EOF.", expected)),
+        }
+    }
+
+    fn expect(&mut self, expected: char) -> Result<(), Error> {
+        match self.next_char() {
+            true if self.cur() == expected => Ok(()),
+            true => self.err(format!("Expected '{}' but got '{}'.",
+                                     expected, self.cur())),
+            false => self.err(format!("Expected '{}' but got EOF.", expected)),
+        }
+    }
+
+    fn next_char(&mut self) -> bool {
+        self.chari += 1;
+        self.chari < self.chars.len()
+    }
+
+    fn pop_ast(&mut self) -> Result<~Ast, Error> {
+        match self.stack.pop().unwrap().unwrap() {
+            Err(e) => Err(e),
+            Ok(ast) => Ok(ast),
+        }
+    }
+
+    fn push(&mut self, ast: ~Ast) {
+        self.stack.push(Ast(ast))
+    }
+
+    fn push_repeater(&mut self, c: char) -> Result<(), Error> {
+        if self.stack.len() == 0 {
+            return self.err(
+                "A repeat operator must be preceded by a valid expression.")
+        }
+        let rep: Repeater = match c {
+            '?' => ZeroOne, '*' => ZeroMore, '+' => OneMore,
+            _ => fail!("Not a valid repeater operator."),
+        };
+
+        match self.peek(1) {
+            Some('*') | Some('+') =>
+                return self.err(
+                    "Double repeat operators are not supported."),
+            _ => {},
+        }
+        let ast = try!(self.pop_ast());
+        match ast {
+            ~Begin(_) | ~End(_) | ~WordBoundary(_) =>
+                return self.err(
+                    "Repeat arguments cannot be empty width assertions."),
+            _ => {}
+        }
+        let greed = try!(self.get_next_greedy());
+        self.push(~Rep(ast, rep, greed));
+        Ok(())
+    }
+
+    fn push_literal(&mut self, c: char) -> Result<(), Error> {
+        match c {
+            '.' => {
+                self.push(~Dot(self.flags))
+            }
+            '^' => {
+                self.push(~Begin(self.flags))
+            }
+            '$' => {
+                self.push(~End(self.flags))
+            }
+            _ => {
+                self.push(~Literal(c, self.flags))
+            }
+        }
+        Ok(())
+    }
+
+    // Parses all forms of character classes.
+    // Assumes that '[' is the current character.
+    fn parse_class(&mut self) -> Result<(), Error> {
+        let negated =
+            if self.peek_is(1, '^') {
+                try!(self.expect('^'))
+                FLAG_NEGATED
+            } else {
+                FLAG_EMPTY
+            };
+        let mut ranges: Vec<(char, char)> = vec!();
+        let mut alts: Vec<~Ast> = vec!();
+
+        if self.peek_is(1, ']') {
+            try!(self.expect(']'))
+            ranges.push((']', ']'))
+        }
+        while self.peek_is(1, '-') {
+            try!(self.expect('-'))
+            ranges.push(('-', '-'))
+        }
+        loop {
+            try!(self.noteof("a closing ']' or a non-empty character class)"))
+            let mut c = self.cur();
+            match c {
+                '[' =>
+                    match self.try_parse_ascii() {
+                        Some(~Class(asciis, flags)) => {
+                            alts.push(~Class(asciis, flags ^ negated));
+                            continue
+                        }
+                        Some(ast) =>
+                            fail!("Expected Class AST but got '{}'", ast),
+                        // Just drop down and try to add as a regular character.
+                        None => {},
+                    },
+                '\\' => {
+                    match try!(self.parse_escape()) {
+                        ~Class(asciis, flags) => {
+                            alts.push(~Class(asciis, flags ^ negated));
+                            continue
+                        }
+                        ~Literal(c2, _) => c = c2, // process below
+                        ~Begin(_) | ~End(_) | ~WordBoundary(_) =>
+                            return self.err(
+                                "\\A, \\z, \\b and \\B are not valid escape \
+                                 sequences inside a character class."),
+                        ast => fail!("Unexpected AST item '{}'", ast),
+                    }
+                }
+                _ => {},
+            }
+            match c {
+                ']' => {
+                    if ranges.len() > 0 {
+                        let flags = negated | (self.flags & FLAG_NOCASE);
+                        let mut ast = ~Class(combine_ranges(ranges), flags);
+                        for alt in alts.move_iter() {
+                            ast = ~Alt(alt, ast)
+                        }
+                        self.push(ast);
+                    } else if alts.len() > 0 {
+                        let mut ast = alts.pop().unwrap();
+                        for alt in alts.move_iter() {
+                            ast = ~Alt(alt, ast)
+                        }
+                        self.push(ast);
+                    }
+                    return Ok(())
+                }
+                c => {
+                    if self.peek_is(1, '-') && !self.peek_is(2, ']') {
+                        try!(self.expect('-'))
+                        try!(self.noteof("not a ']'"))
+                        let c2 = self.cur();
+                        if c2 < c {
+                            return self.err(format!(
+                                "Invalid character class range '{}-{}'", c, c2))
+                        }
+                        ranges.push((c, self.cur()))
+                    } else {
+                        ranges.push((c, c))
+                    }
+                }
+            }
+        }
+    }
+
+    // Tries to parse an ASCII character class of the form [:name:].
+    // If successful, returns an AST character class corresponding to name
+    // and moves the parser to the final ']' character.
+    // If unsuccessful, no state is changed and None is returned.
+    // Assumes that '[' is the current character.
+    fn try_parse_ascii(&mut self) -> Option<~Ast> {
+        if !self.peek_is(1, ':') {
+            return None
+        }
+        let closer =
+            match self.pos(']') {
+                Some(i) => i,
+                None => return None,
+            };
+        if *self.chars.get(closer-1) != ':' {
+            return None
+        }
+        if closer - self.chari <= 3 {
+            return None
+        }
+        let mut name_start = self.chari + 2;
+        let negated =
+            if self.peek_is(2, '^') {
+                name_start += 1;
+                FLAG_NEGATED
+            } else {
+                FLAG_EMPTY
+            };
+        let name = self.slice(name_start, closer - 1);
+        match find_class(ASCII_CLASSES, name) {
+            None => None,
+            Some(ranges) => {
+                self.chari = closer;
+                let flags = negated | (self.flags & FLAG_NOCASE);
+                Some(~Class(combine_ranges(ranges), flags))
+            }
+        }
+    }
+
+    // Parses counted repetition. Supports:
+    // {n}, {n,}, {n,m}, {n}?, {n,}? and {n,m}?
+    // Assumes that '{' is the current character.
+    // Returns either an error or moves the parser to the final '}' character.
+    // (Or the '?' character if not greedy.)
+    fn parse_counted(&mut self) -> Result<(), Error> {
+        // Scan until the closing '}' and grab the stuff in {}.
+        let start = self.chari;
+        let closer =
+            match self.pos('}') {
+                Some(i) => i,
+                None => return self.err(format!(
+                    "No closing brace for counted repetition starting at \
+                     position {}.", start)),
+            };
+        self.chari = closer;
+        let greed = try!(self.get_next_greedy());
+        let inner = str::from_chars(
+            self.chars.as_slice().slice(start + 1, closer));
+
+        // Parse the min and max values from the regex.
+        let (mut min, mut max): (uint, Option<uint>);
+        if !inner.contains(",") {
+            min = try!(self.parse_uint(inner));
+            max = Some(min);
+        } else {
+            let pieces: Vec<&str> = inner.splitn(',', 1).collect();
+            let (smin, smax) = (*pieces.get(0), *pieces.get(1));
+            if smin.len() == 0 {
+                return self.err("Max repetitions cannot be specified \
+                                    without min repetitions.")
+            }
+            min = try!(self.parse_uint(smin));
+            max =
+                if smax.len() == 0 {
+                    None
+                } else {
+                    Some(try!(self.parse_uint(smax)))
+                };
+        }
+
+        // Do some bounds checking and make sure max >= min.
+        if min > MAX_REPEAT {
+            return self.err(format!(
+                "{} exceeds maximum allowed repetitions ({})",
+                min, MAX_REPEAT));
+        }
+        if max.is_some() {
+            let m = max.unwrap();
+            if m > MAX_REPEAT {
+                return self.err(format!(
+                    "{} exceeds maximum allowed repetitions ({})",
+                    m, MAX_REPEAT));
+            }
+            if m < min {
+                return self.err(format!(
+                    "Max repetitions ({}) cannot be smaller than min \
+                     repetitions ({}).", m, min));
+            }
+        }
+
+        // Now manipulate the AST be repeating elements.
+        if max.is_none() {
+            // Require N copies of what's on the stack and then repeat it.
+            let ast = try!(self.pop_ast());
+            for _ in iter::range(0, min) {
+                self.push(ast.clone())
+            }
+            self.push(~Rep(ast, ZeroMore, greed));
+        } else {
+            // Require N copies of what's on the stack and then repeat it
+            // up to M times optionally.
+            let ast = try!(self.pop_ast());
+            for _ in iter::range(0, min) {
+                self.push(ast.clone())
+            }
+            if max.is_some() {
+                for _ in iter::range(min, max.unwrap()) {
+                    self.push(~Rep(ast.clone(), ZeroOne, greed))
+                }
+            }
+            // It's possible that we popped something off the stack but
+            // never put anything back on it. To keep things simple, add
+            // a no-op expression.
+            if min == 0 && (max.is_none() || max == Some(0)) {
+                self.push(~Nothing)
+            }
+        }
+        Ok(())
+    }
+
+    // Parses all escape sequences.
+    // Assumes that '\' is the current character.
+    fn parse_escape(&mut self) -> Result<~Ast, Error> {
+        try!(self.noteof("an escape sequence following a '\\'"))
+
+        let c = self.cur();
+        if is_punct(c) {
+            return Ok(~Literal(c, FLAG_EMPTY))
+        }
+        match c {
+            'a' => Ok(~Literal('\x07', FLAG_EMPTY)),
+            'f' => Ok(~Literal('\x0C', FLAG_EMPTY)),
+            't' => Ok(~Literal('\t', FLAG_EMPTY)),
+            'n' => Ok(~Literal('\n', FLAG_EMPTY)),
+            'r' => Ok(~Literal('\r', FLAG_EMPTY)),
+            'v' => Ok(~Literal('\x0B', FLAG_EMPTY)),
+            'A' => Ok(~Begin(FLAG_EMPTY)),
+            'z' => Ok(~End(FLAG_EMPTY)),
+            'b' => Ok(~WordBoundary(FLAG_EMPTY)),
+            'B' => Ok(~WordBoundary(FLAG_NEGATED)),
+            '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7' => Ok(try!(self.parse_octal())),
+            'x' => Ok(try!(self.parse_hex())),
+            'p' | 'P' => Ok(try!(self.parse_unicode_name())),
+            'd' | 'D' | 's' | 'S' | 'w' | 'W' => {
+                let ranges = perl_unicode_class(c);
+                let mut flags = self.flags & FLAG_NOCASE;
+                if c.is_uppercase() { flags |= FLAG_NEGATED }
+                Ok(~Class(ranges, flags))
+            }
+            _ => self.err(format!("Invalid escape sequence '\\\\{}'", c)),
+        }
+    }
+
+    // Parses a unicode character class name, either of the form \pF where
+    // F is a one letter unicode class name or of the form \p{name} where
+    // name is the unicode class name.
+    // Assumes that \p or \P has been read (and 'p' or 'P' is the current
+    // character).
+    fn parse_unicode_name(&mut self) -> Result<~Ast, Error> {
+        let negated = if self.cur() == 'P' { FLAG_NEGATED } else { FLAG_EMPTY };
+        let mut name: ~str;
+        if self.peek_is(1, '{') {
+            try!(self.expect('{'))
+            let closer =
+                match self.pos('}') {
+                    Some(i) => i,
+                    None => return self.err(format!(
+                        "Missing '\\}' for unclosed '\\{' at position {}",
+                        self.chari)),
+                };
+            if closer - self.chari + 1 == 0 {
+                return self.err("No Unicode class name found.")
+            }
+            name = self.slice(self.chari + 1, closer);
+            self.chari = closer;
+        } else {
+            if self.chari + 1 >= self.chars.len() {
+                return self.err("No single letter Unicode class name found.")
+            }
+            name = self.slice(self.chari + 1, self.chari + 2);
+            self.chari += 1;
+        }
+        match find_class(UNICODE_CLASSES, name) {
+            None => return self.err(format!(
+                "Could not find Unicode class '{}'", name)),
+            Some(ranges) => {
+                Ok(~Class(ranges, negated | (self.flags & FLAG_NOCASE)))
+            }
+        }
+    }
+
+    // Parses an octal number, up to 3 digits.
+    // Assumes that \n has been read, where n is the first digit.
+    fn parse_octal(&mut self) -> Result<~Ast, Error> {
+        let start = self.chari;
+        let mut end = start + 1;
+        let (d2, d3) = (self.peek(1), self.peek(2));
+        if d2 >= Some('0') && d2 <= Some('7') {
+            try!(self.noteof("expected octal character in [0-7]"))
+            end += 1;
+            if d3 >= Some('0') && d3 <= Some('7') {
+                try!(self.noteof("expected octal character in [0-7]"))
+                end += 1;
+            }
+        }
+        let s = self.slice(start, end);
+        match num::from_str_radix::<u32>(s, 8) {
+            Some(n) => Ok(~Literal(try!(self.char_from_u32(n)), FLAG_EMPTY)),
+            None => self.err(format!(
+                "Could not parse '{}' as octal number.", s)),
+        }
+    }
+
+    // Parse a hex number. Either exactly two digits or anything in {}.
+    // Assumes that \x has been read.
+    fn parse_hex(&mut self) -> Result<~Ast, Error> {
+        if !self.peek_is(1, '{') {
+            try!(self.expect('{'))
+            return self.parse_hex_two()
+        }
+        let start = self.chari + 2;
+        let closer =
+            match self.pos('}') {
+                None => return self.err(format!(
+                    "Missing '\\}' for unclosed '\\{' at position {}", start)),
+                Some(i) => i,
+            };
+        self.chari = closer;
+        self.parse_hex_digits(self.slice(start, closer))
+    }
+
+    // Parses a two-digit hex number.
+    // Assumes that \xn has been read, where n is the first digit and is the
+    // current character.
+    // After return, parser will point at the second digit.
+    fn parse_hex_two(&mut self) -> Result<~Ast, Error> {
+        let (start, end) = (self.chari, self.chari + 2);
+        let bad = self.slice(start - 2, self.chars.len());
+        try!(self.noteof(format!("Invalid hex escape sequence '{}'", bad)))
+        self.parse_hex_digits(self.slice(start, end))
+    }
+
+    // Parses `s` as a hexadecimal number.
+    fn parse_hex_digits(&self, s: &str) -> Result<~Ast, Error> {
+        match num::from_str_radix::<u32>(s, 16) {
+            Some(n) => Ok(~Literal(try!(self.char_from_u32(n)), FLAG_EMPTY)),
+            None => self.err(format!(
+                "Could not parse '{}' as hex number.", s)),
+        }
+    }
+
+    // Parses a named capture.
+    // Assumes that '(?P<' has been consumed and that the current character
+    // is '<'.
+    // When done, parser will be at the closing '>' character.
+    fn parse_named_capture(&mut self) -> Result<(), Error> {
+        try!(self.noteof("a capture name"))
+        let closer =
+            match self.pos('>') {
+                Some(i) => i,
+                None => return self.err("Capture name must end with '>'."),
+            };
+        if closer - self.chari == 0 {
+            return self.err("Capture names must have at least 1 character.")
+        }
+        let name = self.slice(self.chari, closer);
+        if !name.chars().all(is_valid_cap) {
+            return self.err(
+                "Capture names can only have underscores, letters and digits.")
+        }
+        if self.names.contains(&name) {
+            return self.err(format!("Duplicate capture group name '{}'.", name))
+        }
+        self.names.push(name.clone());
+        self.chari = closer;
+        self.caps += 1;
+        self.stack.push(Paren(self.flags, self.caps, name));
+        Ok(())
+    }
+
+    // Parses non-capture groups and options.
+    // Assumes that '(?' has already been consumed and '?' is the current
+    // character.
+    fn parse_group_opts(&mut self) -> Result<(), Error> {
+        if self.peek_is(1, 'P') && self.peek_is(2, '<') {
+            try!(self.expect('P')) try!(self.expect('<'))
+            return self.parse_named_capture()
+        }
+        let start = self.chari;
+        let mut flags = self.flags;
+        let mut sign = 1;
+        let mut saw_flag = false;
+        loop {
+            try!(self.noteof("expected non-empty set of flags or closing ')'"))
+            match self.cur() {
+                'i' => { flags = flags | FLAG_NOCASE;     saw_flag = true},
+                'm' => { flags = flags | FLAG_MULTI;      saw_flag = true},
+                's' => { flags = flags | FLAG_DOTNL;      saw_flag = true},
+                'U' => { flags = flags | FLAG_SWAP_GREED; saw_flag = true},
+                '-' => {
+                    if sign < 0 {
+                        return self.err(format!(
+                            "Cannot negate flags twice in '{}'.",
+                            self.slice(start, self.chari + 1)))
+                    }
+                    sign = -1;
+                    saw_flag = false;
+                    flags = flags ^ flags;
+                }
+                ':' | ')' => {
+                    if sign < 0 {
+                        if !saw_flag {
+                            return self.err(format!(
+                                "A valid flag does not follow negation in '{}'",
+                                self.slice(start, self.chari + 1)))
+                        }
+                        flags = flags ^ flags;
+                    }
+                    if self.cur() == ':' {
+                        // Save the old flags with the opening paren.
+                        self.stack.push(Paren(self.flags, 0, ~""));
+                    }
+                    self.flags = flags;
+                    return Ok(())
+                }
+                _ => return self.err(format!(
+                    "Unrecognized flag '{}'.", self.cur())),
+            }
+        }
+    }
+
+    // Peeks at the next character and returns whether it's ungreedy or not.
+    // If it is, then the next character is consumed.
+    fn get_next_greedy(&mut self) -> Result<Greed, Error> {
+        Ok(if self.peek_is(1, '?') {
+            try!(self.expect('?'))
+            Ungreedy
+        } else {
+            Greedy
+        }.swap(self.flags & FLAG_SWAP_GREED > 0))
+    }
+
+    // Searches the stack (starting at the top) until it finds an expression
+    // for which `pred` returns true. The index of that expression in the
+    // stack is returned.
+    // If there's no match, then one of two things happens depending on the
+    // values of `allow_start`. When it's true, then `0` will be returned.
+    // Otherwise, an error will be returned.
+    // Generally, `allow_start` is only true when you're *not* expecting an
+    // opening parenthesis.
+    fn pos_last(&self, allow_start: bool, pred: |&BuildAst| -> bool)
+               -> Result<uint, Error> {
+        let from = match self.stack.iter().rev().position(pred) {
+            Some(i) => i,
+            None => {
+                if allow_start {
+                    self.stack.len()
+                } else {
+                    return self.err("No matching opening parenthesis.")
+                }
+            }
+        };
+        // Adjust index since 'from' is for the reversed stack.
+        // Also, don't include the '(' or '|'.
+        Ok(self.stack.len() - from)
+    }
+
+    // concat starts at `from` in the parser's stack and concatenates all
+    // expressions up to the top of the stack. The resulting concatenation is
+    // then pushed on to the stack.
+    // Usually `from` corresponds to the position of an opening parenthesis,
+    // a '|' (alternation) or the start of the entire expression.
+    fn concat(&mut self, from: uint) -> Result<(), Error> {
+        let ast = try!(self.build_from(from, concat_flatten));
+        self.push(ast);
+        Ok(())
+    }
+
+    // concat starts at `from` in the parser's stack and alternates all
+    // expressions up to the top of the stack. The resulting alternation is
+    // then pushed on to the stack.
+    // Usually `from` corresponds to the position of an opening parenthesis
+    // or the start of the entire expression.
+    // This will also drop any opening parens or alternation bars found in
+    // the intermediate AST.
+    fn alternate(&mut self, mut from: uint) -> Result<(), Error> {
+        // Unlike in the concatenation case, we want 'build_from' to continue
+        // all the way to the opening left paren (so it will be popped off and
+        // thrown away). But be careful with overflow---we can't count on the
+        // open paren to be there.
+        if from > 0 { from = from - 1}
+        let ast = try!(self.build_from(from, Alt));
+        self.push(ast);
+        Ok(())
+    }
+
+    // build_from combines all AST elements starting at 'from' in the
+    // parser's stack using 'mk' to combine them. If any such element is not an
+    // AST then it is popped off the stack and ignored.
+    fn build_from(&mut self, from: uint, mk: |~Ast, ~Ast| -> Ast)
+                 -> Result<~Ast, Error> {
+        if from >= self.stack.len() {
+            return self.err("Empty group or alternate not allowed.")
+        }
+
+        let mut combined = try!(self.pop_ast());
+        let mut i = self.stack.len();
+        while i > from {
+            i = i - 1;
+            match self.stack.pop().unwrap() {
+                Ast(x) => combined = ~mk(x, combined),
+                _ => {},
+            }
+        }
+        Ok(combined)
+    }
+
+    fn parse_uint(&self, s: &str) -> Result<uint, Error> {
+        match from_str::<uint>(s) {
+            Some(i) => Ok(i),
+            None => self.err(format!(
+                "Expected an unsigned integer but got '{}'.", s)),
+        }
+    }
+
+    fn char_from_u32(&self, n: u32) -> Result<char, Error> {
+        match char::from_u32(n) {
+            Some(c) => Ok(c),
+            None => self.err(format!(
+                "Could not decode '{}' to unicode character.", n)),
+        }
+    }
+
+    fn pos(&self, c: char) -> Option<uint> {
+        self.chars.iter()
+            .skip(self.chari).position(|&c2| c2 == c).map(|i| self.chari + i)
+    }
+
+    fn err<T>(&self, msg: &str) -> Result<T, Error> {
+        Err(Error {
+            pos: self.chari,
+            msg: msg.to_owned(),
+        })
+    }
+
+    fn peek(&self, offset: uint) -> Option<char> {
+        if self.chari + offset >= self.chars.len() {
+            return None
+        }
+        Some(*self.chars.get(self.chari + offset))
+    }
+
+    fn peek_is(&self, offset: uint, is: char) -> bool {
+        self.peek(offset) == Some(is)
+    }
+
+    fn cur(&self) -> char {
+        *self.chars.get(self.chari)
+    }
+
+    fn slice(&self, start: uint, end: uint) -> ~str {
+        str::from_chars(self.chars.as_slice().slice(start, end))
+    }
+}
+
+// Given an unordered collection of character ranges, combine_ranges returns
+// an ordered sequence of character ranges where no two ranges overlap. They
+// are ordered from least to greatest (using start position).
+fn combine_ranges(unordered: Vec<(char, char)>) -> Vec<(char, char)> {
+    // Returns true iff the two character classes overlap or share a boundary.
+    // e.g., ('a', 'g') and ('h', 'm') would return true.
+    fn should_merge((a, b): (char, char), (x, y): (char, char)) -> bool {
+        cmp::max(a, x) as u32 <= cmp::min(b, y) as u32 + 1
+    }
+
+    // This is currently O(n^2), but I think with sufficient cleverness,
+    // it can be reduced to O(n) **if necessary**.
+    let mut ordered: Vec<(char, char)> = Vec::with_capacity(unordered.len());
+    for (us, ue) in unordered.move_iter() {
+        let (mut us, mut ue) = (us, ue);
+        assert!(us <= ue);
+        let mut which: Option<uint> = None;
+        for (i, &(os, oe)) in ordered.iter().enumerate() {
+            if should_merge((us, ue), (os, oe)) {
+                us = cmp::min(us, os);
+                ue = cmp::max(ue, oe);
+                which = Some(i);
+                break
+            }
+        }
+        match which {
+            None => ordered.push((us, ue)),
+            Some(i) => *ordered.get_mut(i) = (us, ue),
+        }
+    }
+    ordered.sort();
+    ordered
+}
+
+// Constructs a Unicode friendly Perl character class from \d, \s or \w
+// (or any of their negated forms). Note that this does not handle negation.
+fn perl_unicode_class(which: char) -> Vec<(char, char)> {
+    match which.to_lowercase() {
+        'd' => Vec::from_slice(PERLD),
+        's' => Vec::from_slice(PERLS),
+        'w' => Vec::from_slice(PERLW),
+        _ => unreachable!(),
+    }
+}
+
+// Returns a concatenation of two expressions. This also guarantees that a
+// `Cat` expression will never be a direct child of another `Cat` expression.
+fn concat_flatten(x: ~Ast, y: ~Ast) -> Ast {
+    match (x, y) {
+        (~Cat(mut xs), ~Cat(ys)) => { xs.push_all_move(ys); Cat(xs) }
+        (~Cat(mut xs), ast) => { xs.push(ast); Cat(xs) }
+        (ast, ~Cat(mut xs)) => { xs.unshift(ast); Cat(xs) }
+        (ast1, ast2) => Cat(vec!(ast1, ast2)),
+    }
+}
+
+pub fn is_punct(c: char) -> bool {
+    match c {
+        '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' |
+        '[' | ']' | '{' | '}' | '^' | '$' => true,
+        _ => false,
+    }
+}
+
+fn is_valid_cap(c: char) -> bool {
+    c == '_' || (c >= '0' && c <= '9')
+    || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
+}
+
+fn find_class(classes: NamedClasses, name: &str) -> Option<Vec<(char, char)>> {
+    match classes.bsearch(|&(s, _)| s.cmp(&name)) {
+        Some(i) => Some(Vec::from_slice(classes[i].val1())),
+        None => None,
+    }
+}
+
+type Class = &'static [(char, char)];
+type NamedClasses = &'static [(&'static str, Class)];
+
+static ASCII_CLASSES: NamedClasses = &[
+    // Classes must be in alphabetical order so that bsearch works.
+    // [:alnum:]      alphanumeric (== [0-9A-Za-z])
+    // [:alpha:]      alphabetic (== [A-Za-z])
+    // [:ascii:]      ASCII (== [\x00-\x7F])
+    // [:blank:]      blank (== [\t ])
+    // [:cntrl:]      control (== [\x00-\x1F\x7F])
+    // [:digit:]      digits (== [0-9])
+    // [:graph:]      graphical (== [!-~])
+    // [:lower:]      lower case (== [a-z])
+    // [:print:]      printable (== [ -~] == [ [:graph:]])
+    // [:punct:]      punctuation (== [!-/:-@[-`{-~])
+    // [:space:]      whitespace (== [\t\n\v\f\r ])
+    // [:upper:]      upper case (== [A-Z])
+    // [:word:]       word characters (== [0-9A-Za-z_])
+    // [:xdigit:]     hex digit (== [0-9A-Fa-f])
+    // Taken from: http://golang.org/pkg/regex/syntax/
+    ("alnum", &[('0', '9'), ('A', 'Z'), ('a', 'z')]),
+    ("alpha", &[('A', 'Z'), ('a', 'z')]),
+    ("ascii", &[('\x00', '\x7F')]),
+    ("blank", &[(' ', ' '), ('\t', '\t')]),
+    ("cntrl", &[('\x00', '\x1F'), ('\x7F', '\x7F')]),
+    ("digit", &[('0', '9')]),
+    ("graph", &[('!', '~')]),
+    ("lower", &[('a', 'z')]),
+    ("print", &[(' ', '~')]),
+    ("punct", &[('!', '/'), (':', '@'), ('[', '`'), ('{', '~')]),
+    ("space", &[('\t', '\t'), ('\n', '\n'), ('\x0B', '\x0B'), ('\x0C', '\x0C'),
+                ('\r', '\r'), (' ', ' ')]),
+    ("upper", &[('A', 'Z')]),
+    ("word", &[('0', '9'), ('A', 'Z'), ('a', 'z'), ('_', '_')]),
+    ("xdigit", &[('0', '9'), ('A', 'F'), ('a', 'f')]),
+];
diff --git a/src/libregex/re.rs b/src/libregex/re.rs
new file mode 100644 (file)
index 0000000..da3ebae
--- /dev/null
@@ -0,0 +1,870 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use collections::HashMap;
+use std::fmt;
+use std::from_str::from_str;
+use std::str::{MaybeOwned, Owned, Slice};
+
+use compile::Program;
+use parse;
+use vm;
+use vm::{CaptureLocs, MatchKind, Exists, Location, Submatches};
+
+/// Escapes all regular expression meta characters in `text` so that it may be
+/// safely used in a regular expression as a literal string.
+pub fn quote(text: &str) -> ~str {
+    let mut quoted = StrBuf::with_capacity(text.len());
+    for c in text.chars() {
+        if parse::is_punct(c) {
+            quoted.push_char('\\')
+        }
+        quoted.push_char(c);
+    }
+    quoted.into_owned()
+}
+
+/// Tests if the given regular expression matches somewhere in the text given.
+///
+/// If there was a problem compiling the regular expression, an error is
+/// returned.
+///
+/// To find submatches, split or replace text, you'll need to compile an
+/// expression first.
+///
+/// Note that you should prefer the `regex!` macro when possible. For example,
+/// `regex!("...").is_match("...")`.
+pub fn is_match(regex: &str, text: &str) -> Result<bool, parse::Error> {
+    Regex::new(regex).map(|r| r.is_match(text))
+}
+
+/// Regex is a compiled regular expression, represented as either a sequence
+/// of bytecode instructions (dynamic) or as a specialized Rust function
+/// (native). It can be used to search, split
+/// or replace text. All searching is done with an implicit `.*?` at the
+/// beginning and end of an expression. To force an expression to match the
+/// whole string (or a prefix or a suffix), you must use an anchor like `^` or
+/// `$` (or `\A` and `\z`).
+///
+/// While this crate will handle Unicode strings (whether in the regular
+/// expression or in the search text), all positions returned are **byte
+/// indices**. Every byte index is guaranteed to be at a UTF8 codepoint
+/// boundary.
+///
+/// The lifetimes `'r` and `'t` in this crate correspond to the lifetime of a
+/// compiled regular expression and text to search, respectively.
+///
+/// The only methods that allocate new strings are the string replacement
+/// methods. All other methods (searching and splitting) return borrowed
+/// pointers into the string given.
+///
+/// # Examples
+///
+/// Find the location of a US phone number:
+///
+/// ```rust
+/// # use regex::Regex;
+/// let re = match Regex::new("[0-9]{3}-[0-9]{3}-[0-9]{4}") {
+///     Ok(re) => re,
+///     Err(err) => fail!("{}", err),
+/// };
+/// assert_eq!(re.find("phone: 111-222-3333"), Some((7, 19)));
+/// ```
+///
+/// You can also use the `regex!` macro to compile a regular expression when
+/// you compile your program:
+///
+/// ```rust
+/// #![feature(phase)]
+/// extern crate regex;
+/// #[phase(syntax)] extern crate regex_macros;
+///
+/// fn main() {
+///     let re = regex!(r"\d+");
+///     assert_eq!(re.find("123 abc"), Some((0, 3)));
+/// }
+/// ```
+///
+/// Given an incorrect regular expression, `regex!` will cause the Rust
+/// compiler to produce a compile time error.
+/// Note that `regex!` will compile the expression to native Rust code, which
+/// makes it much faster when searching text.
+/// More details about the `regex!` macro can be found in the `regex` crate
+/// documentation.
+#[deriving(Clone)]
+#[allow(visible_private_types)]
+pub struct Regex {
+    /// The representation of `Regex` is exported to support the `regex!`
+    /// syntax extension. Do not rely on it.
+    ///
+    /// See the comments for the `program` module in `lib.rs` for a more
+    /// detailed explanation for what `regex!` requires.
+    #[doc(hidden)]
+    pub original: ~str,
+    #[doc(hidden)]
+    pub names: ~[Option<~str>],
+    #[doc(hidden)]
+    pub p: MaybeNative,
+}
+
+impl fmt::Show for Regex {
+    /// Shows the original regular expression.
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f.buf, "{}", self.original)
+    }
+}
+
+pub enum MaybeNative {
+    Dynamic(Program),
+    Native(fn(MatchKind, &str, uint, uint) -> Vec<Option<uint>>),
+}
+
+impl Clone for MaybeNative {
+    fn clone(&self) -> MaybeNative {
+        match *self {
+            Dynamic(ref p) => Dynamic(p.clone()),
+            Native(fp) => Native(fp),
+        }
+    }
+}
+
+impl Regex {
+    /// Compiles a dynamic regular expression. Once compiled, it can be
+    /// used repeatedly to search, split or replace text in a string.
+    ///
+    /// When possible, you should prefer the `regex!` macro since it is
+    /// safer and always faster.
+    ///
+    /// If an invalid expression is given, then an error is returned.
+    pub fn new(re: &str) -> Result<Regex, parse::Error> {
+        let ast = try!(parse::parse(re));
+        let (prog, names) = Program::new(ast);
+        Ok(Regex { original: re.to_owned(), names: names, p: Dynamic(prog) })
+    }
+
+    /// Returns true if and only if the regex matches the string given.
+    ///
+    /// # Example
+    ///
+    /// Test if some text contains at least one word with exactly 13
+    /// characters:
+    ///
+    /// ```rust
+    /// # #![feature(phase)]
+    /// # extern crate regex; #[phase(syntax)] extern crate regex_macros;
+    /// # fn main() {
+    /// let text = "I categorically deny having triskaidekaphobia.";
+    /// let matched = regex!(r"\b\w{13}\b").is_match(text);
+    /// assert!(matched);
+    /// # }
+    /// ```
+    pub fn is_match(&self, text: &str) -> bool {
+        has_match(&exec(self, Exists, text))
+    }
+
+    /// Returns the start and end byte range of the leftmost-first match in
+    /// `text`. If no match exists, then `None` is returned.
+    ///
+    /// Note that this should only be used if you want to discover the position
+    /// of the match. Testing the existence of a match is faster if you use
+    /// `is_match`.
+    ///
+    /// # Example
+    ///
+    /// Find the start and end location of every word with exactly 13
+    /// characters:
+    ///
+    /// ```rust
+    /// # #![feature(phase)]
+    /// # extern crate regex; #[phase(syntax)] extern crate regex_macros;
+    /// # fn main() {
+    /// let text = "I categorically deny having triskaidekaphobia.";
+    /// let pos = regex!(r"\b\w{13}\b").find(text);
+    /// assert_eq!(pos, Some((2, 15)));
+    /// # }
+    /// ```
+    pub fn find(&self, text: &str) -> Option<(uint, uint)> {
+        let caps = exec(self, Location, text);
+        if has_match(&caps) {
+            Some((caps.get(0).unwrap(), caps.get(1).unwrap()))
+        } else {
+            None
+        }
+    }
+
+    /// Returns an iterator for each successive non-overlapping match in
+    /// `text`, returning the start and end byte indices with respect to
+    /// `text`.
+    ///
+    /// # Example
+    ///
+    /// Find the start and end location of the first word with exactly 13
+    /// characters:
+    ///
+    /// ```rust
+    /// # #![feature(phase)]
+    /// # extern crate regex; #[phase(syntax)] extern crate regex_macros;
+    /// # fn main() {
+    /// let text = "Retroactively relinquishing remunerations is reprehensible.";
+    /// for pos in regex!(r"\b\w{13}\b").find_iter(text) {
+    ///     println!("{}", pos);
+    /// }
+    /// // Output:
+    /// // (0, 13)
+    /// // (14, 27)
+    /// // (28, 41)
+    /// // (45, 58)
+    /// # }
+    /// ```
+    pub fn find_iter<'r, 't>(&'r self, text: &'t str) -> FindMatches<'r, 't> {
+        FindMatches {
+            re: self,
+            search: text,
+            last_end: 0,
+            last_match: None,
+        }
+    }
+
+    /// Returns the capture groups corresponding to the leftmost-first
+    /// match in `text`. Capture group `0` always corresponds to the entire
+    /// match. If no match is found, then `None` is returned.
+    ///
+    /// You should only use `captures` if you need access to submatches.
+    /// Otherwise, `find` is faster for discovering the location of the overall
+    /// match.
+    ///
+    /// # Examples
+    ///
+    /// Say you have some text with movie names and their release years,
+    /// like "'Citizen Kane' (1941)". It'd be nice if we could search for text
+    /// looking like that, while also extracting the movie name and its release
+    /// year separately.
+    ///
+    /// ```rust
+    /// # #![feature(phase)]
+    /// # extern crate regex; #[phase(syntax)] extern crate regex_macros;
+    /// # fn main() {
+    /// let re = regex!(r"'([^']+)'\s+\((\d{4})\)");
+    /// let text = "Not my favorite movie: 'Citizen Kane' (1941).";
+    /// let caps = re.captures(text).unwrap();
+    /// assert_eq!(caps.at(1), "Citizen Kane");
+    /// assert_eq!(caps.at(2), "1941");
+    /// assert_eq!(caps.at(0), "'Citizen Kane' (1941)");
+    /// # }
+    /// ```
+    ///
+    /// Note that the full match is at capture group `0`. Each subsequent
+    /// capture group is indexed by the order of its opening `(`.
+    ///
+    /// We can make this example a bit clearer by using *named* capture groups:
+    ///
+    /// ```rust
+    /// # #![feature(phase)]
+    /// # extern crate regex; #[phase(syntax)] extern crate regex_macros;
+    /// # fn main() {
+    /// let re = regex!(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)");
+    /// let text = "Not my favorite movie: 'Citizen Kane' (1941).";
+    /// let caps = re.captures(text).unwrap();
+    /// assert_eq!(caps.name("title"), "Citizen Kane");
+    /// assert_eq!(caps.name("year"), "1941");
+    /// assert_eq!(caps.at(0), "'Citizen Kane' (1941)");
+    /// # }
+    /// ```
+    ///
+    /// Here we name the capture groups, which we can access with the `name`
+    /// method. Note that the named capture groups are still accessible with
+    /// `at`.
+    ///
+    /// The `0`th capture group is always unnamed, so it must always be
+    /// accessed with `at(0)`.
+    pub fn captures<'t>(&self, text: &'t str) -> Option<Captures<'t>> {
+        let caps = exec(self, Submatches, text);
+        Captures::new(self, text, caps)
+    }
+
+    /// Returns an iterator over all the non-overlapping capture groups matched
+    /// in `text`. This is operationally the same as `find_iter` (except it
+    /// yields information about submatches).
+    ///
+    /// # Example
+    ///
+    /// We can use this to find all movie titles and their release years in
+    /// some text, where the movie is formatted like "'Title' (xxxx)":
+    ///
+    /// ```rust
+    /// # #![feature(phase)]
+    /// # extern crate regex; #[phase(syntax)] extern crate regex_macros;
+    /// # fn main() {
+    /// let re = regex!(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)");
+    /// let text = "'Citizen Kane' (1941), 'The Wizard of Oz' (1939), 'M' (1931).";
+    /// for caps in re.captures_iter(text) {
+    ///     println!("Movie: {}, Released: {}", caps.name("title"), caps.name("year"));
+    /// }
+    /// // Output:
+    /// // Movie: Citizen Kane, Released: 1941
+    /// // Movie: The Wizard of Oz, Released: 1939
+    /// // Movie: M, Released: 1931
+    /// # }
+    /// ```
+    pub fn captures_iter<'r, 't>(&'r self, text: &'t str)
+                                -> FindCaptures<'r, 't> {
+        FindCaptures {
+            re: self,
+            search: text,
+            last_match: None,
+            last_end: 0,
+        }
+    }
+
+    /// Returns an iterator of substrings of `text` delimited by a match
+    /// of the regular expression.
+    /// Namely, each element of the iterator corresponds to text that *isn't*
+    /// matched by the regular expression.
+    ///
+    /// This method will *not* copy the text given.
+    ///
+    /// # Example
+    ///
+    /// To split a string delimited by arbitrary amounts of spaces or tabs:
+    ///
+    /// ```rust
+    /// # #![feature(phase)]
+    /// # extern crate regex; #[phase(syntax)] extern crate regex_macros;
+    /// # fn main() {
+    /// let re = regex!(r"[ \t]+");
+    /// let fields: Vec<&str> = re.split("a b \t  c\td    e").collect();
+    /// assert_eq!(fields, vec!("a", "b", "c", "d", "e"));
+    /// # }
+    /// ```
+    pub fn split<'r, 't>(&'r self, text: &'t str) -> RegexSplits<'r, 't> {
+        RegexSplits {
+            finder: self.find_iter(text),
+            last: 0,
+        }
+    }
+
+    /// Returns an iterator of at most `limit` substrings of `text` delimited
+    /// by a match of the regular expression. (A `limit` of `0` will return no
+    /// substrings.)
+    /// Namely, each element of the iterator corresponds to text that *isn't*
+    /// matched by the regular expression.
+    /// The remainder of the string that is not split will be the last element
+    /// in the iterator.
+    ///
+    /// This method will *not* copy the text given.
+    ///
+    /// # Example
+    ///
+    /// Get the first two words in some text:
+    ///
+    /// ```rust
+    /// # #![feature(phase)]
+    /// # extern crate regex; #[phase(syntax)] extern crate regex_macros;
+    /// # fn main() {
+    /// let re = regex!(r"\W+");
+    /// let fields: Vec<&str> = re.splitn("Hey! How are you?", 3).collect();
+    /// assert_eq!(fields, vec!("Hey", "How", "are you?"));
+    /// # }
+    /// ```
+    pub fn splitn<'r, 't>(&'r self, text: &'t str, limit: uint)
+                         -> RegexSplitsN<'r, 't> {
+        RegexSplitsN {
+            splits: self.split(text),
+            cur: 0,
+            limit: limit,
+        }
+    }
+
+    /// Replaces the leftmost-first match with the replacement provided.
+    /// The replacement can be a regular string (where `$N` and `$name` are
+    /// expanded to match capture groups) or a function that takes the matches'
+    /// `Captures` and returns the replaced string.
+    ///
+    /// If no match is found, then a copy of the string is returned unchanged.
+    ///
+    /// # Examples
+    ///
+    /// Note that this function is polymorphic with respect to the replacement.
+    /// In typical usage, this can just be a normal string:
+    ///
+    /// ```rust
+    /// # #![feature(phase)]
+    /// # extern crate regex; #[phase(syntax)] extern crate regex_macros;
+    /// # fn main() {
+    /// let re = regex!("[^01]+");
+    /// assert_eq!(re.replace("1078910", "").as_slice(), "1010");
+    /// # }
+    /// ```
+    ///
+    /// But anything satisfying the `Replacer` trait will work. For example,
+    /// a closure of type `|&Captures| -> ~str` provides direct access to the
+    /// captures corresponding to a match. This allows one to access
+    /// submatches easily:
+    ///
+    /// ```rust
+    /// # #![feature(phase)]
+    /// # extern crate regex; #[phase(syntax)] extern crate regex_macros;
+    /// # use regex::Captures; fn main() {
+    /// let re = regex!(r"([^,\s]+),\s+(\S+)");
+    /// let result = re.replace("Springsteen, Bruce", |caps: &Captures| {
+    ///     format!("{} {}", caps.at(2), caps.at(1))
+    /// });
+    /// assert_eq!(result.as_slice(), "Bruce Springsteen");
+    /// # }
+    /// ```
+    ///
+    /// But this is a bit cumbersome to use all the time. Instead, a simple
+    /// syntax is supported that expands `$name` into the corresponding capture
+    /// group. Here's the last example, but using this expansion technique
+    /// with named capture groups:
+    ///
+    /// ```rust
+    /// # #![feature(phase)]
+    /// # extern crate regex; #[phase(syntax)] extern crate regex_macros;
+    /// # fn main() {
+    /// let re = regex!(r"(?P<last>[^,\s]+),\s+(?P<first>\S+)");
+    /// let result = re.replace("Springsteen, Bruce", "$first $last");
+    /// assert_eq!(result.as_slice(), "Bruce Springsteen");
+    /// # }
+    /// ```
+    ///
+    /// Note that using `$2` instead of `$first` or `$1` instead of `$last`
+    /// would produce the same result. To write a literal `$` use `$$`.
+    ///
+    /// Finally, sometimes you just want to replace a literal string with no
+    /// submatch expansion. This can be done by wrapping a string with
+    /// `NoExpand`:
+    ///
+    /// ```rust
+    /// # #![feature(phase)]
+    /// # extern crate regex; #[phase(syntax)] extern crate regex_macros;
+    /// # fn main() {
+    /// use regex::NoExpand;
+    ///
+    /// let re = regex!(r"(?P<last>[^,\s]+),\s+(\S+)");
+    /// let result = re.replace("Springsteen, Bruce", NoExpand("$2 $last"));
+    /// assert_eq!(result.as_slice(), "$2 $last");
+    /// # }
+    /// ```
+    pub fn replace<R: Replacer>(&self, text: &str, rep: R) -> StrBuf {
+        self.replacen(text, 1, rep)
+    }
+
+    /// Replaces all non-overlapping matches in `text` with the
+    /// replacement provided. This is the same as calling `replacen` with
+    /// `limit` set to `0`.
+    ///
+    /// See the documentation for `replace` for details on how to access
+    /// submatches in the replacement string.
+    pub fn replace_all<R: Replacer>(&self, text: &str, rep: R) -> StrBuf {
+        self.replacen(text, 0, rep)
+    }
+
+    /// Replaces at most `limit` non-overlapping matches in `text` with the
+    /// replacement provided. If `limit` is 0, then all non-overlapping matches
+    /// are replaced.
+    ///
+    /// See the documentation for `replace` for details on how to access
+    /// submatches in the replacement string.
+    pub fn replacen<R: Replacer>
+                   (&self, text: &str, limit: uint, mut rep: R) -> StrBuf {
+        let mut new = StrBuf::with_capacity(text.len());
+        let mut last_match = 0u;
+        let mut i = 0;
+        for cap in self.captures_iter(text) {
+            // It'd be nicer to use the 'take' iterator instead, but it seemed
+            // awkward given that '0' => no limit.
+            if limit > 0 && i >= limit {
+                break
+            }
+            i += 1;
+
+            let (s, e) = cap.pos(0).unwrap(); // captures only reports matches
+            new.push_str(text.slice(last_match, s));
+            new.push_str(rep.reg_replace(&cap).as_slice());
+            last_match = e;
+        }
+        new.append(text.slice(last_match, text.len()))
+    }
+}
+
+/// NoExpand indicates literal string replacement.
+///
+/// It can be used with `replace` and `replace_all` to do a literal
+/// string replacement without expanding `$name` to their corresponding
+/// capture groups.
+///
+/// `'r` is the lifetime of the literal text.
+pub struct NoExpand<'t>(pub &'t str);
+
+/// Replacer describes types that can be used to replace matches in a string.
+pub trait Replacer {
+    /// Returns a possibly owned string that is used to replace the match
+    /// corresponding the the `caps` capture group.
+    ///
+    /// The `'a` lifetime refers to the lifetime of a borrowed string when
+    /// a new owned string isn't needed (e.g., for `NoExpand`).
+    fn reg_replace<'a>(&'a mut self, caps: &Captures) -> MaybeOwned<'a>;
+}
+
+impl<'t> Replacer for NoExpand<'t> {
+    fn reg_replace<'a>(&'a mut self, _: &Captures) -> MaybeOwned<'a> {
+        let NoExpand(s) = *self;
+        Slice(s)
+    }
+}
+
+impl<'t> Replacer for &'t str {
+    fn reg_replace<'a>(&'a mut self, caps: &Captures) -> MaybeOwned<'a> {
+        Owned(caps.expand(*self).into_owned())
+    }
+}
+
+impl<'a> Replacer for |&Captures|: 'a -> ~str {
+    fn reg_replace<'r>(&'r mut self, caps: &Captures) -> MaybeOwned<'r> {
+        Owned((*self)(caps).into_owned())
+    }
+}
+
+/// Yields all substrings delimited by a regular expression match.
+///
+/// `'r` is the lifetime of the compiled expression and `'t` is the lifetime
+/// of the string being split.
+pub struct RegexSplits<'r, 't> {
+    finder: FindMatches<'r, 't>,
+    last: uint,
+}
+
+impl<'r, 't> Iterator<&'t str> for RegexSplits<'r, 't> {
+    fn next(&mut self) -> Option<&'t str> {
+        let text = self.finder.search;
+        match self.finder.next() {
+            None => {
+                if self.last >= text.len() {
+                    None
+                } else {
+                    let s = text.slice(self.last, text.len());
+                    self.last = text.len();
+                    Some(s)
+                }
+            }
+            Some((s, e)) => {
+                let matched = text.slice(self.last, s);
+                self.last = e;
+                Some(matched)
+            }
+        }
+    }
+}
+
+/// Yields at most `N` substrings delimited by a regular expression match.
+///
+/// The last substring will be whatever remains after splitting.
+///
+/// `'r` is the lifetime of the compiled expression and `'t` is the lifetime
+/// of the string being split.
+pub struct RegexSplitsN<'r, 't> {
+    splits: RegexSplits<'r, 't>,
+    cur: uint,
+    limit: uint,
+}
+
+impl<'r, 't> Iterator<&'t str> for RegexSplitsN<'r, 't> {
+    fn next(&mut self) -> Option<&'t str> {
+        let text = self.splits.finder.search;
+        if self.cur >= self.limit {
+            None
+        } else {
+            self.cur += 1;
+            if self.cur >= self.limit {
+                Some(text.slice(self.splits.last, text.len()))
+            } else {
+                self.splits.next()
+            }
+        }
+    }
+}
+
+/// Captures represents a group of captured strings for a single match.
+///
+/// The 0th capture always corresponds to the entire match. Each subsequent
+/// index corresponds to the next capture group in the regex.
+/// If a capture group is named, then the matched string is *also* available
+/// via the `name` method. (Note that the 0th capture is always unnamed and so
+/// must be accessed with the `at` method.)
+///
+/// Positions returned from a capture group are always byte indices.
+///
+/// `'t` is the lifetime of the matched text.
+pub struct Captures<'t> {
+    text: &'t str,
+    locs: CaptureLocs,
+    named: Option<HashMap<~str, uint>>,
+}
+
+impl<'t> Captures<'t> {
+    fn new(re: &Regex, search: &'t str, locs: CaptureLocs)
+          -> Option<Captures<'t>> {
+        if !has_match(&locs) {
+            return None
+        }
+
+        let named =
+            if re.names.len() == 0 {
+                None
+            } else {
+                let mut named = HashMap::new();
+                for (i, name) in re.names.iter().enumerate() {
+                    match name {
+                        &None => {},
+                        &Some(ref name) => {
+                            named.insert(name.to_owned(), i);
+                        }
+                    }
+                }
+                Some(named)
+            };
+        Some(Captures {
+            text: search,
+            locs: locs,
+            named: named,
+        })
+    }
+
+    /// Returns the start and end positions of the Nth capture group.
+    /// Returns `None` if `i` is not a valid capture group or if the capture
+    /// group did not match anything.
+    /// The positions returned are *always* byte indices with respect to the
+    /// original string matched.
+    pub fn pos(&self, i: uint) -> Option<(uint, uint)> {
+        let (s, e) = (i * 2, i * 2 + 1);
+        if e >= self.locs.len() || self.locs.get(s).is_none() {
+            // VM guarantees that each pair of locations are both Some or None.
+            return None
+        }
+        Some((self.locs.get(s).unwrap(), self.locs.get(e).unwrap()))
+    }
+
+    /// Returns the matched string for the capture group `i`.
+    /// If `i` isn't a valid capture group or didn't match anything, then the
+    /// empty string is returned.
+    pub fn at(&self, i: uint) -> &'t str {
+        match self.pos(i) {
+            None => "",
+            Some((s, e)) => {
+                self.text.slice(s, e)
+            }
+        }
+    }
+
+    /// Returns the matched string for the capture group named `name`.
+    /// If `name` isn't a valid capture group or didn't match anything, then
+    /// the empty string is returned.
+    pub fn name(&self, name: &str) -> &'t str {
+        match self.named {
+            None => "",
+            Some(ref h) => {
+                match h.find_equiv(&name) {
+                    None => "",
+                    Some(i) => self.at(*i),
+                }
+            }
+        }
+    }
+
+    /// Creates an iterator of all the capture groups in order of appearance
+    /// in the regular expression.
+    pub fn iter(&'t self) -> SubCaptures<'t> {
+        SubCaptures { idx: 0, caps: self, }
+    }
+
+    /// Creates an iterator of all the capture group positions in order of
+    /// appearance in the regular expression. Positions are byte indices
+    /// in terms of the original string matched.
+    pub fn iter_pos(&'t self) -> SubCapturesPos<'t> {
+        SubCapturesPos { idx: 0, caps: self, }
+    }
+
+    /// Expands all instances of `$name` in `text` to the corresponding capture
+    /// group `name`.
+    ///
+    /// `name` may be an integer corresponding to the index of the
+    /// capture group (counted by order of opening parenthesis where `0` is the
+    /// entire match) or it can be a name (consisting of letters, digits or
+    /// underscores) corresponding to a named capture group.
+    ///
+    /// If `name` isn't a valid capture group (whether the name doesn't exist or
+    /// isn't a valid index), then it is replaced with the empty string.
+    ///
+    /// To write a literal `$` use `$$`.
+    pub fn expand(&self, text: &str) -> StrBuf {
+        // How evil can you get?
+        // FIXME: Don't use regexes for this. It's completely unnecessary.
+        let re = Regex::new(r"(^|[^$]|\b)\$(\w+)").unwrap();
+        let text = re.replace_all(text, |refs: &Captures| -> ~str {
+            let (pre, name) = (refs.at(1), refs.at(2));
+            pre + match from_str::<uint>(name) {
+                None => self.name(name).to_owned(),
+                Some(i) => self.at(i).to_owned(),
+            }
+        });
+        let re = Regex::new(r"\$\$").unwrap();
+        re.replace_all(text.as_slice(), NoExpand("$"))
+    }
+}
+
+impl<'t> Container for Captures<'t> {
+    /// Returns the number of captured groups.
+    #[inline]
+    fn len(&self) -> uint {
+        self.locs.len() / 2
+    }
+}
+
+/// An iterator over capture groups for a particular match of a regular
+/// expression.
+///
+/// `'t` is the lifetime of the matched text.
+pub struct SubCaptures<'t> {
+    idx: uint,
+    caps: &'t Captures<'t>,
+}
+
+impl<'t> Iterator<&'t str> for SubCaptures<'t> {
+    fn next(&mut self) -> Option<&'t str> {
+        if self.idx < self.caps.len() {
+            self.idx += 1;
+            Some(self.caps.at(self.idx - 1))
+        } else {
+            None
+        }
+    }
+}
+
+/// An iterator over capture group positions for a particular match of a
+/// regular expression.
+///
+/// Positions are byte indices in terms of the original string matched.
+///
+/// `'t` is the lifetime of the matched text.
+pub struct SubCapturesPos<'t> {
+    idx: uint,
+    caps: &'t Captures<'t>,
+}
+
+impl<'t> Iterator<Option<(uint, uint)>> for SubCapturesPos<'t> {
+    fn next(&mut self) -> Option<Option<(uint, uint)>> {
+        if self.idx < self.caps.len() {
+            self.idx += 1;
+            Some(self.caps.pos(self.idx - 1))
+        } else {
+            None
+        }
+    }
+}
+
+/// An iterator that yields all non-overlapping capture groups matching a
+/// particular regular expression. The iterator stops when no more matches can
+/// be found.
+///
+/// `'r` is the lifetime of the compiled expression and `'t` is the lifetime
+/// of the matched string.
+pub struct FindCaptures<'r, 't> {
+    re: &'r Regex,
+    search: &'t str,
+    last_match: Option<uint>,
+    last_end: uint,
+}
+
+impl<'r, 't> Iterator<Captures<'t>> for FindCaptures<'r, 't> {
+    fn next(&mut self) -> Option<Captures<'t>> {
+        if self.last_end > self.search.len() {
+            return None
+        }
+
+        let caps = exec_slice(self.re, Submatches, self.search,
+                              self.last_end, self.search.len());
+        let (s, e) =
+            if !has_match(&caps) {
+                return None
+            } else {
+                (caps.get(0).unwrap(), caps.get(1).unwrap())
+            };
+
+        // Don't accept empty matches immediately following a match.
+        // i.e., no infinite loops please.
+        if e - s == 0 && Some(self.last_end) == self.last_match {
+            self.last_end += 1;
+            return self.next()
+        }
+        self.last_end = e;
+        self.last_match = Some(self.last_end);
+        Captures::new(self.re, self.search, caps)
+    }
+}
+
+/// An iterator over all non-overlapping matches for a particular string.
+///
+/// The iterator yields a tuple of integers corresponding to the start and end
+/// of the match. The indices are byte offsets. The iterator stops when no more
+/// matches can be found.
+///
+/// `'r` is the lifetime of the compiled expression and `'t` is the lifetime
+/// of the matched string.
+pub struct FindMatches<'r, 't> {
+    re: &'r Regex,
+    search: &'t str,
+    last_match: Option<uint>,
+    last_end: uint,
+}
+
+impl<'r, 't> Iterator<(uint, uint)> for FindMatches<'r, 't> {
+    fn next(&mut self) -> Option<(uint, uint)> {
+        if self.last_end > self.search.len() {
+            return None
+        }
+
+        let caps = exec_slice(self.re, Location, self.search,
+                              self.last_end, self.search.len());
+        let (s, e) =
+            if !has_match(&caps) {
+                return None
+            } else {
+                (caps.get(0).unwrap(), caps.get(1).unwrap())
+            };
+
+        // Don't accept empty matches immediately following a match.
+        // i.e., no infinite loops please.
+        if e - s == 0 && Some(self.last_end) == self.last_match {
+            self.last_end += 1;
+            return self.next()
+        }
+        self.last_end = e;
+        self.last_match = Some(self.last_end);
+        Some((s, e))
+    }
+}
+
+fn exec(re: &Regex, which: MatchKind, input: &str) -> CaptureLocs {
+    exec_slice(re, which, input, 0, input.len())
+}
+
+fn exec_slice(re: &Regex, which: MatchKind,
+              input: &str, s: uint, e: uint) -> CaptureLocs {
+    match re.p {
+        Dynamic(ref prog) => vm::run(which, prog, input, s, e),
+        Native(exec) => exec(which, input, s, e),
+    }
+}
+
+#[inline]
+fn has_match(caps: &CaptureLocs) -> bool {
+    caps.len() >= 2 && caps.get(0).is_some() && caps.get(1).is_some()
+}
diff --git a/src/libregex/test/bench.rs b/src/libregex/test/bench.rs
new file mode 100644 (file)
index 0000000..a5667ab
--- /dev/null
@@ -0,0 +1,179 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rand::{Rng, task_rng};
+use stdtest::Bencher;
+use std::str;
+use regex::{Regex, NoExpand};
+
+fn bench_assert_match(b: &mut Bencher, re: Regex, text: &str) {
+    b.iter(|| if !re.is_match(text) { fail!("no match") });
+}
+
+#[bench]
+fn no_exponential(b: &mut Bencher) {
+    let n = 100;
+    let re = Regex::new("a?".repeat(n) + "a".repeat(n)).unwrap();
+    let text = "a".repeat(n);
+    bench_assert_match(b, re, text);
+}
+
+#[bench]
+fn literal(b: &mut Bencher) {
+    let re = regex!("y");
+    let text = "x".repeat(50) + "y";
+    bench_assert_match(b, re, text);
+}
+
+#[bench]
+fn not_literal(b: &mut Bencher) {
+    let re = regex!(".y");
+    let text = "x".repeat(50) + "y";
+    bench_assert_match(b, re, text);
+}
+
+#[bench]
+fn match_class(b: &mut Bencher) {
+    let re = regex!("[abcdw]");
+    let text = "xxxx".repeat(20) + "w";
+    bench_assert_match(b, re, text);
+}
+
+#[bench]
+fn match_class_in_range(b: &mut Bencher) {
+    // 'b' is between 'a' and 'c', so the class range checking doesn't help.
+    let re = regex!("[ac]");
+    let text = "bbbb".repeat(20) + "c";
+    bench_assert_match(b, re, text);
+}
+
+#[bench]
+fn replace_all(b: &mut Bencher) {
+    let re = regex!("[cjrw]");
+    let text = "abcdefghijklmnopqrstuvwxyz";
+    // FIXME: This isn't using the $name expand stuff.
+    // It's possible RE2/Go is using it, but currently, the expand in this
+    // crate is actually compiling a regex, so it's incredibly slow.
+    b.iter(|| re.replace_all(text, NoExpand("")));
+}
+
+#[bench]
+fn anchored_literal_short_non_match(b: &mut Bencher) {
+    let re = regex!("^zbc(d|e)");
+    let text = "abcdefghijklmnopqrstuvwxyz";
+    b.iter(|| re.is_match(text));
+}
+
+#[bench]
+fn anchored_literal_long_non_match(b: &mut Bencher) {
+    let re = regex!("^zbc(d|e)");
+    let text = "abcdefghijklmnopqrstuvwxyz".repeat(15);
+    b.iter(|| re.is_match(text));
+}
+
+#[bench]
+fn anchored_literal_short_match(b: &mut Bencher) {
+    let re = regex!("^.bc(d|e)");
+    let text = "abcdefghijklmnopqrstuvwxyz";
+    b.iter(|| re.is_match(text));
+}
+
+#[bench]
+fn anchored_literal_long_match(b: &mut Bencher) {
+    let re = regex!("^.bc(d|e)");
+    let text = "abcdefghijklmnopqrstuvwxyz".repeat(15);
+    b.iter(|| re.is_match(text));
+}
+
+#[bench]
+fn one_pass_short_a(b: &mut Bencher) {
+    let re = regex!("^.bc(d|e)*$");
+    let text = "abcddddddeeeededd";
+    b.iter(|| re.is_match(text));
+}
+
+#[bench]
+fn one_pass_short_a_not(b: &mut Bencher) {
+    let re = regex!(".bc(d|e)*$");
+    let text = "abcddddddeeeededd";
+    b.iter(|| re.is_match(text));
+}
+
+#[bench]
+fn one_pass_short_b(b: &mut Bencher) {
+    let re = regex!("^.bc(?:d|e)*$");
+    let text = "abcddddddeeeededd";
+    b.iter(|| re.is_match(text));
+}
+
+#[bench]
+fn one_pass_short_b_not(b: &mut Bencher) {
+    let re = regex!(".bc(?:d|e)*$");
+    let text = "abcddddddeeeededd";
+    b.iter(|| re.is_match(text));
+}
+
+#[bench]
+fn one_pass_long_prefix(b: &mut Bencher) {
+    let re = regex!("^abcdefghijklmnopqrstuvwxyz.*$");
+    let text = "abcdefghijklmnopqrstuvwxyz";
+    b.iter(|| re.is_match(text));
+}
+
+#[bench]
+fn one_pass_long_prefix_not(b: &mut Bencher) {
+    let re = regex!("^.bcdefghijklmnopqrstuvwxyz.*$");
+    let text = "abcdefghijklmnopqrstuvwxyz";
+    b.iter(|| re.is_match(text));
+}
+
+macro_rules! throughput(
+    ($name:ident, $regex:expr, $size:expr) => (
+        #[bench]
+        fn $name(b: &mut Bencher) {
+            let text = gen_text($size);
+            b.bytes = $size;
+            b.iter(|| if $regex.is_match(text) { fail!("match") });
+        }
+    );
+)
+
+fn easy0() -> Regex { regex!("ABCDEFGHIJKLMNOPQRSTUVWXYZ$") }
+fn easy1() -> Regex { regex!("A[AB]B[BC]C[CD]D[DE]E[EF]F[FG]G[GH]H[HI]I[IJ]J$") }
+fn medium() -> Regex { regex!("[XYZ]ABCDEFGHIJKLMNOPQRSTUVWXYZ$") }
+fn hard() -> Regex { regex!("[ -~]*ABCDEFGHIJKLMNOPQRSTUVWXYZ$") }
+
+fn gen_text(n: uint) -> ~str {
+    let mut rng = task_rng();
+    let mut bytes = rng.gen_ascii_str(n).into_bytes();
+    for (i, b) in bytes.mut_iter().enumerate() {
+        if i % 20 == 0 {
+            *b = '\n' as u8
+        }
+    }
+    str::from_utf8(bytes).unwrap().to_owned()
+}
+
+throughput!(easy0_32, easy0(), 32)
+throughput!(easy0_1K, easy0(), 1<<10)
+throughput!(easy0_32K, easy0(), 32<<10)
+
+throughput!(easy1_32, easy1(), 32)
+throughput!(easy1_1K, easy1(), 1<<10)
+throughput!(easy1_32K, easy1(), 32<<10)
+
+throughput!(medium_32, medium(), 32)
+throughput!(medium_1K, medium(), 1<<10)
+throughput!(medium_32K,medium(), 32<<10)
+
+throughput!(hard_32, hard(), 32)
+throughput!(hard_1K, hard(), 1<<10)
+throughput!(hard_32K,hard(), 32<<10)
+
diff --git a/src/libregex/test/matches.rs b/src/libregex/test/matches.rs
new file mode 100644 (file)
index 0000000..fb93851
--- /dev/null
@@ -0,0 +1,373 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+
+// DO NOT EDIT. Automatically generated by 'src/etc/regex-match-tests'
+// on 2014-04-23 01:33:36.539280.
+
+// Tests from basic.dat
+mat!(match_basic_3, r"abracadabra$", r"abracadabracadabra", Some((7, 18)))
+mat!(match_basic_4, r"a...b", r"abababbb", Some((2, 7)))
+mat!(match_basic_5, r"XXXXXX", r"..XXXXXX", Some((2, 8)))
+mat!(match_basic_6, r"\)", r"()", Some((1, 2)))
+mat!(match_basic_7, r"a]", r"a]a", Some((0, 2)))
+mat!(match_basic_9, r"\}", r"}", Some((0, 1)))
+mat!(match_basic_10, r"\]", r"]", Some((0, 1)))
+mat!(match_basic_12, r"]", r"]", Some((0, 1)))
+mat!(match_basic_15, r"^a", r"ax", Some((0, 1)))
+mat!(match_basic_16, r"\^a", r"a^a", Some((1, 3)))
+mat!(match_basic_17, r"a\^", r"a^", Some((0, 2)))
+mat!(match_basic_18, r"a$", r"aa", Some((1, 2)))
+mat!(match_basic_19, r"a\$", r"a$", Some((0, 2)))
+mat!(match_basic_20, r"^$", r"", Some((0, 0)))
+mat!(match_basic_21, r"$^", r"", Some((0, 0)))
+mat!(match_basic_22, r"a($)", r"aa", Some((1, 2)), Some((2, 2)))
+mat!(match_basic_23, r"a*(^a)", r"aa", Some((0, 1)), Some((0, 1)))
+mat!(match_basic_24, r"(..)*(...)*", r"a", Some((0, 0)))
+mat!(match_basic_25, r"(..)*(...)*", r"abcd", Some((0, 4)), Some((2, 4)))
+mat!(match_basic_26, r"(ab|a)(bc|c)", r"abc", Some((0, 3)), Some((0, 2)), Some((2, 3)))
+mat!(match_basic_27, r"(ab)c|abc", r"abc", Some((0, 3)), Some((0, 2)))
+mat!(match_basic_28, r"a{0}b", r"ab", Some((1, 2)))
+mat!(match_basic_29, r"(a*)(b?)(b+)b{3}", r"aaabbbbbbb", Some((0, 10)), Some((0, 3)), Some((3, 4)), Some((4, 7)))
+mat!(match_basic_30, r"(a*)(b{0,1})(b{1,})b{3}", r"aaabbbbbbb", Some((0, 10)), Some((0, 3)), Some((3, 4)), Some((4, 7)))
+mat!(match_basic_32, r"((a|a)|a)", r"a", Some((0, 1)), Some((0, 1)), Some((0, 1)))
+mat!(match_basic_33, r"(a*)(a|aa)", r"aaaa", Some((0, 4)), Some((0, 3)), Some((3, 4)))
+mat!(match_basic_34, r"a*(a.|aa)", r"aaaa", Some((0, 4)), Some((2, 4)))
+mat!(match_basic_35, r"a(b)|c(d)|a(e)f", r"aef", Some((0, 3)), None, None, Some((1, 2)))
+mat!(match_basic_36, r"(a|b)?.*", r"b", Some((0, 1)), Some((0, 1)))
+mat!(match_basic_37, r"(a|b)c|a(b|c)", r"ac", Some((0, 2)), Some((0, 1)))
+mat!(match_basic_38, r"(a|b)c|a(b|c)", r"ab", Some((0, 2)), None, Some((1, 2)))
+mat!(match_basic_39, r"(a|b)*c|(a|ab)*c", r"abc", Some((0, 3)), Some((1, 2)))
+mat!(match_basic_40, r"(a|b)*c|(a|ab)*c", r"xc", Some((1, 2)))
+mat!(match_basic_41, r"(.a|.b).*|.*(.a|.b)", r"xa", Some((0, 2)), Some((0, 2)))
+mat!(match_basic_42, r"a?(ab|ba)ab", r"abab", Some((0, 4)), Some((0, 2)))
+mat!(match_basic_43, r"a?(ac{0}b|ba)ab", r"abab", Some((0, 4)), Some((0, 2)))
+mat!(match_basic_44, r"ab|abab", r"abbabab", Some((0, 2)))
+mat!(match_basic_45, r"aba|bab|bba", r"baaabbbaba", Some((5, 8)))
+mat!(match_basic_46, r"aba|bab", r"baaabbbaba", Some((6, 9)))
+mat!(match_basic_47, r"(aa|aaa)*|(a|aaaaa)", r"aa", Some((0, 2)), Some((0, 2)))
+mat!(match_basic_48, r"(a.|.a.)*|(a|.a...)", r"aa", Some((0, 2)), Some((0, 2)))
+mat!(match_basic_49, r"ab|a", r"xabc", Some((1, 3)))
+mat!(match_basic_50, r"ab|a", r"xxabc", Some((2, 4)))
+mat!(match_basic_51, r"(?i)(Ab|cD)*", r"aBcD", Some((0, 4)), Some((2, 4)))
+mat!(match_basic_52, r"[^-]", r"--a", Some((2, 3)))
+mat!(match_basic_53, r"[a-]*", r"--a", Some((0, 3)))
+mat!(match_basic_54, r"[a-m-]*", r"--amoma--", Some((0, 4)))
+mat!(match_basic_55, r":::1:::0:|:::1:1:0:", r":::0:::1:::1:::0:", Some((8, 17)))
+mat!(match_basic_56, r":::1:::0:|:::1:1:1:", r":::0:::1:::1:::0:", Some((8, 17)))
+mat!(match_basic_57, r"[[:upper:]]", r"A", Some((0, 1)))
+mat!(match_basic_58, r"[[:lower:]]+", r"`az{", Some((1, 3)))
+mat!(match_basic_59, r"[[:upper:]]+", r"@AZ[", Some((1, 3)))
+mat!(match_basic_65, r"
+", r"
+", Some((0, 1)))
+mat!(match_basic_66, r"
+", r"
+", Some((0, 1)))
+mat!(match_basic_67, r"[^a]", r"
+", Some((0, 1)))
+mat!(match_basic_68, r"
+a", r"
+a", Some((0, 2)))
+mat!(match_basic_69, r"(a)(b)(c)", r"abc", Some((0, 3)), Some((0, 1)), Some((1, 2)), Some((2, 3)))
+mat!(match_basic_70, r"xxx", r"xxx", Some((0, 3)))
+mat!(match_basic_71, r"(^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$)", r"feb 6,", Some((0, 6)))
+mat!(match_basic_72, r"(^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$)", r"2/7", Some((0, 3)))
+mat!(match_basic_73, r"(^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$)", r"feb 1,Feb 6", Some((5, 11)))
+mat!(match_basic_74, r"((((((((((((((((((((((((((((((x))))))))))))))))))))))))))))))", r"x", Some((0, 1)), Some((0, 1)), Some((0, 1)))
+mat!(match_basic_75, r"((((((((((((((((((((((((((((((x))))))))))))))))))))))))))))))*", r"xx", Some((0, 2)), Some((1, 2)), Some((1, 2)))
+mat!(match_basic_76, r"a?(ab|ba)*", r"ababababababababababababababababababababababababababababababababababababababababa", Some((0, 81)), Some((79, 81)))
+mat!(match_basic_77, r"abaa|abbaa|abbbaa|abbbbaa", r"ababbabbbabbbabbbbabbbbaa", Some((18, 25)))
+mat!(match_basic_78, r"abaa|abbaa|abbbaa|abbbbaa", r"ababbabbbabbbabbbbabaa", Some((18, 22)))
+mat!(match_basic_79, r"aaac|aabc|abac|abbc|baac|babc|bbac|bbbc", r"baaabbbabac", Some((7, 11)))
+mat!(match_basic_80, r".*", r"\ 1\7f", Some((0, 2)))
+mat!(match_basic_81, r"aaaa|bbbb|cccc|ddddd|eeeeee|fffffff|gggg|hhhh|iiiii|jjjjj|kkkkk|llll", r"XaaaXbbbXcccXdddXeeeXfffXgggXhhhXiiiXjjjXkkkXlllXcbaXaaaa", Some((53, 57)))
+mat!(match_basic_83, r"a*a*a*a*a*b", r"aaaaaaaaab", Some((0, 10)))
+mat!(match_basic_84, r"^", r"", Some((0, 0)))
+mat!(match_basic_85, r"$", r"", Some((0, 0)))
+mat!(match_basic_86, r"^$", r"", Some((0, 0)))
+mat!(match_basic_87, r"^a$", r"a", Some((0, 1)))
+mat!(match_basic_88, r"abc", r"abc", Some((0, 3)))
+mat!(match_basic_89, r"abc", r"xabcy", Some((1, 4)))
+mat!(match_basic_90, r"abc", r"ababc", Some((2, 5)))
+mat!(match_basic_91, r"ab*c", r"abc", Some((0, 3)))
+mat!(match_basic_92, r"ab*bc", r"abc", Some((0, 3)))
+mat!(match_basic_93, r"ab*bc", r"abbc", Some((0, 4)))
+mat!(match_basic_94, r"ab*bc", r"abbbbc", Some((0, 6)))
+mat!(match_basic_95, r"ab+bc", r"abbc", Some((0, 4)))
+mat!(match_basic_96, r"ab+bc", r"abbbbc", Some((0, 6)))
+mat!(match_basic_97, r"ab?bc", r"abbc", Some((0, 4)))
+mat!(match_basic_98, r"ab?bc", r"abc", Some((0, 3)))
+mat!(match_basic_99, r"ab?c", r"abc", Some((0, 3)))
+mat!(match_basic_100, r"^abc$", r"abc", Some((0, 3)))
+mat!(match_basic_101, r"^abc", r"abcc", Some((0, 3)))
+mat!(match_basic_102, r"abc$", r"aabc", Some((1, 4)))
+mat!(match_basic_103, r"^", r"abc", Some((0, 0)))
+mat!(match_basic_104, r"$", r"abc", Some((3, 3)))
+mat!(match_basic_105, r"a.c", r"abc", Some((0, 3)))
+mat!(match_basic_106, r"a.c", r"axc", Some((0, 3)))
+mat!(match_basic_107, r"a.*c", r"axyzc", Some((0, 5)))
+mat!(match_basic_108, r"a[bc]d", r"abd", Some((0, 3)))
+mat!(match_basic_109, r"a[b-d]e", r"ace", Some((0, 3)))
+mat!(match_basic_110, r"a[b-d]", r"aac", Some((1, 3)))
+mat!(match_basic_111, r"a[-b]", r"a-", Some((0, 2)))
+mat!(match_basic_112, r"a[b-]", r"a-", Some((0, 2)))
+mat!(match_basic_113, r"a]", r"a]", Some((0, 2)))
+mat!(match_basic_114, r"a[]]b", r"a]b", Some((0, 3)))
+mat!(match_basic_115, r"a[^bc]d", r"aed", Some((0, 3)))
+mat!(match_basic_116, r"a[^-b]c", r"adc", Some((0, 3)))
+mat!(match_basic_117, r"a[^]b]c", r"adc", Some((0, 3)))
+mat!(match_basic_118, r"ab|cd", r"abc", Some((0, 2)))
+mat!(match_basic_119, r"ab|cd", r"abcd", Some((0, 2)))
+mat!(match_basic_120, r"a\(b", r"a(b", Some((0, 3)))
+mat!(match_basic_121, r"a\(*b", r"ab", Some((0, 2)))
+mat!(match_basic_122, r"a\(*b", r"a((b", Some((0, 4)))
+mat!(match_basic_123, r"((a))", r"abc", Some((0, 1)), Some((0, 1)), Some((0, 1)))
+mat!(match_basic_124, r"(a)b(c)", r"abc", Some((0, 3)), Some((0, 1)), Some((2, 3)))
+mat!(match_basic_125, r"a+b+c", r"aabbabc", Some((4, 7)))
+mat!(match_basic_126, r"a*", r"aaa", Some((0, 3)))
+mat!(match_basic_128, r"(a*)*", r"-", Some((0, 0)), None)
+mat!(match_basic_129, r"(a*)+", r"-", Some((0, 0)), Some((0, 0)))
+mat!(match_basic_131, r"(a*|b)*", r"-", Some((0, 0)), None)
+mat!(match_basic_132, r"(a+|b)*", r"ab", Some((0, 2)), Some((1, 2)))
+mat!(match_basic_133, r"(a+|b)+", r"ab", Some((0, 2)), Some((1, 2)))
+mat!(match_basic_134, r"(a+|b)?", r"ab", Some((0, 1)), Some((0, 1)))
+mat!(match_basic_135, r"[^ab]*", r"cde", Some((0, 3)))
+mat!(match_basic_137, r"(^)*", r"-", Some((0, 0)), None)
+mat!(match_basic_138, r"a*", r"", Some((0, 0)))
+mat!(match_basic_139, r"([abc])*d", r"abbbcd", Some((0, 6)), Some((4, 5)))
+mat!(match_basic_140, r"([abc])*bcd", r"abcd", Some((0, 4)), Some((0, 1)))
+mat!(match_basic_141, r"a|b|c|d|e", r"e", Some((0, 1)))
+mat!(match_basic_142, r"(a|b|c|d|e)f", r"ef", Some((0, 2)), Some((0, 1)))
+mat!(match_basic_144, r"((a*|b))*", r"-", Some((0, 0)), None, None)
+mat!(match_basic_145, r"abcd*efg", r"abcdefg", Some((0, 7)))
+mat!(match_basic_146, r"ab*", r"xabyabbbz", Some((1, 3)))
+mat!(match_basic_147, r"ab*", r"xayabbbz", Some((1, 2)))
+mat!(match_basic_148, r"(ab|cd)e", r"abcde", Some((2, 5)), Some((2, 4)))
+mat!(match_basic_149, r"[abhgefdc]ij", r"hij", Some((0, 3)))
+mat!(match_basic_150, r"(a|b)c*d", r"abcd", Some((1, 4)), Some((1, 2)))
+mat!(match_basic_151, r"(ab|ab*)bc", r"abc", Some((0, 3)), Some((0, 1)))
+mat!(match_basic_152, r"a([bc]*)c*", r"abc", Some((0, 3)), Some((1, 3)))
+mat!(match_basic_153, r"a([bc]*)(c*d)", r"abcd", Some((0, 4)), Some((1, 3)), Some((3, 4)))
+mat!(match_basic_154, r"a([bc]+)(c*d)", r"abcd", Some((0, 4)), Some((1, 3)), Some((3, 4)))
+mat!(match_basic_155, r"a([bc]*)(c+d)", r"abcd", Some((0, 4)), Some((1, 2)), Some((2, 4)))
+mat!(match_basic_156, r"a[bcd]*dcdcde", r"adcdcde", Some((0, 7)))
+mat!(match_basic_157, r"(ab|a)b*c", r"abc", Some((0, 3)), Some((0, 2)))
+mat!(match_basic_158, r"((a)(b)c)(d)", r"abcd", Some((0, 4)), Some((0, 3)), Some((0, 1)), Some((1, 2)), Some((3, 4)))
+mat!(match_basic_159, r"[A-Za-z_][A-Za-z0-9_]*", r"alpha", Some((0, 5)))
+mat!(match_basic_160, r"^a(bc+|b[eh])g|.h$", r"abh", Some((1, 3)))
+mat!(match_basic_161, r"(bc+d$|ef*g.|h?i(j|k))", r"effgz", Some((0, 5)), Some((0, 5)))
+mat!(match_basic_162, r"(bc+d$|ef*g.|h?i(j|k))", r"ij", Some((0, 2)), Some((0, 2)), Some((1, 2)))
+mat!(match_basic_163, r"(bc+d$|ef*g.|h?i(j|k))", r"reffgz", Some((1, 6)), Some((1, 6)))
+mat!(match_basic_164, r"(((((((((a)))))))))", r"a", Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1)))
+mat!(match_basic_165, r"multiple words", r"multiple words yeah", Some((0, 14)))
+mat!(match_basic_166, r"(.*)c(.*)", r"abcde", Some((0, 5)), Some((0, 2)), Some((3, 5)))
+mat!(match_basic_167, r"abcd", r"abcd", Some((0, 4)))
+mat!(match_basic_168, r"a(bc)d", r"abcd", Some((0, 4)), Some((1, 3)))
+mat!(match_basic_169, r"a[\ 1-\ 3]?c", r"a\ 2c", Some((0, 3)))
+mat!(match_basic_170, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Qaddafi", Some((0, 15)), None, Some((10, 12)))
+mat!(match_basic_171, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Mo'ammar Gadhafi", Some((0, 16)), None, Some((11, 13)))
+mat!(match_basic_172, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Kaddafi", Some((0, 15)), None, Some((10, 12)))
+mat!(match_basic_173, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Qadhafi", Some((0, 15)), None, Some((10, 12)))
+mat!(match_basic_174, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Gadafi", Some((0, 14)), None, Some((10, 11)))
+mat!(match_basic_175, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Mu'ammar Qadafi", Some((0, 15)), None, Some((11, 12)))
+mat!(match_basic_176, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Moamar Gaddafi", Some((0, 14)), None, Some((9, 11)))
+mat!(match_basic_177, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Mu'ammar Qadhdhafi", Some((0, 18)), None, Some((13, 15)))
+mat!(match_basic_178, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Khaddafi", Some((0, 16)), None, Some((11, 13)))
+mat!(match_basic_179, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Ghaddafy", Some((0, 16)), None, Some((11, 13)))
+mat!(match_basic_180, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Ghadafi", Some((0, 15)), None, Some((11, 12)))
+mat!(match_basic_181, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Ghaddafi", Some((0, 16)), None, Some((11, 13)))
+mat!(match_basic_182, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muamar Kaddafi", Some((0, 14)), None, Some((9, 11)))
+mat!(match_basic_183, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Quathafi", Some((0, 16)), None, Some((11, 13)))
+mat!(match_basic_184, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Gheddafi", Some((0, 16)), None, Some((11, 13)))
+mat!(match_basic_185, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Moammar Khadafy", Some((0, 15)), None, Some((11, 12)))
+mat!(match_basic_186, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Moammar Qudhafi", Some((0, 15)), None, Some((10, 12)))
+mat!(match_basic_187, r"a+(b|c)*d+", r"aabcdd", Some((0, 6)), Some((3, 4)))
+mat!(match_basic_188, r"^.+$", r"vivi", Some((0, 4)))
+mat!(match_basic_189, r"^(.+)$", r"vivi", Some((0, 4)), Some((0, 4)))
+mat!(match_basic_190, r"^([^!.]+).att.com!(.+)$", r"gryphon.att.com!eby", Some((0, 19)), Some((0, 7)), Some((16, 19)))
+mat!(match_basic_191, r"^([^!]+!)?([^!]+)$", r"bas", Some((0, 3)), None, Some((0, 3)))
+mat!(match_basic_192, r"^([^!]+!)?([^!]+)$", r"bar!bas", Some((0, 7)), Some((0, 4)), Some((4, 7)))
+mat!(match_basic_193, r"^([^!]+!)?([^!]+)$", r"foo!bas", Some((0, 7)), Some((0, 4)), Some((4, 7)))
+mat!(match_basic_194, r"^.+!([^!]+!)([^!]+)$", r"foo!bar!bas", Some((0, 11)), Some((4, 8)), Some((8, 11)))
+mat!(match_basic_195, r"((foo)|(bar))!bas", r"bar!bas", Some((0, 7)), Some((0, 3)), None, Some((0, 3)))
+mat!(match_basic_196, r"((foo)|(bar))!bas", r"foo!bar!bas", Some((4, 11)), Some((4, 7)), None, Some((4, 7)))
+mat!(match_basic_197, r"((foo)|(bar))!bas", r"foo!bas", Some((0, 7)), Some((0, 3)), Some((0, 3)))
+mat!(match_basic_198, r"((foo)|bar)!bas", r"bar!bas", Some((0, 7)), Some((0, 3)))
+mat!(match_basic_199, r"((foo)|bar)!bas", r"foo!bar!bas", Some((4, 11)), Some((4, 7)))
+mat!(match_basic_200, r"((foo)|bar)!bas", r"foo!bas", Some((0, 7)), Some((0, 3)), Some((0, 3)))
+mat!(match_basic_201, r"(foo|(bar))!bas", r"bar!bas", Some((0, 7)), Some((0, 3)), Some((0, 3)))
+mat!(match_basic_202, r"(foo|(bar))!bas", r"foo!bar!bas", Some((4, 11)), Some((4, 7)), Some((4, 7)))
+mat!(match_basic_203, r"(foo|(bar))!bas", r"foo!bas", Some((0, 7)), Some((0, 3)))
+mat!(match_basic_204, r"(foo|bar)!bas", r"bar!bas", Some((0, 7)), Some((0, 3)))
+mat!(match_basic_205, r"(foo|bar)!bas", r"foo!bar!bas", Some((4, 11)), Some((4, 7)))
+mat!(match_basic_206, r"(foo|bar)!bas", r"foo!bas", Some((0, 7)), Some((0, 3)))
+mat!(match_basic_207, r"^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$", r"foo!bar!bas", Some((0, 11)), Some((0, 11)), None, None, Some((4, 8)), Some((8, 11)))
+mat!(match_basic_208, r"^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$", r"bas", Some((0, 3)), None, Some((0, 3)))
+mat!(match_basic_209, r"^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$", r"bar!bas", Some((0, 7)), Some((0, 4)), Some((4, 7)))
+mat!(match_basic_210, r"^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$", r"foo!bar!bas", Some((0, 11)), None, None, Some((4, 8)), Some((8, 11)))
+mat!(match_basic_211, r"^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$", r"foo!bas", Some((0, 7)), Some((0, 4)), Some((4, 7)))
+mat!(match_basic_212, r"^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$", r"bas", Some((0, 3)), Some((0, 3)), None, Some((0, 3)))
+mat!(match_basic_213, r"^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$", r"bar!bas", Some((0, 7)), Some((0, 7)), Some((0, 4)), Some((4, 7)))
+mat!(match_basic_214, r"^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$", r"foo!bar!bas", Some((0, 11)), Some((0, 11)), None, None, Some((4, 8)), Some((8, 11)))
+mat!(match_basic_215, r"^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$", r"foo!bas", Some((0, 7)), Some((0, 7)), Some((0, 4)), Some((4, 7)))
+mat!(match_basic_216, r".*(/XXX).*", r"/XXX", Some((0, 4)), Some((0, 4)))
+mat!(match_basic_217, r".*(\\XXX).*", r"\XXX", Some((0, 4)), Some((0, 4)))
+mat!(match_basic_218, r"\\XXX", r"\XXX", Some((0, 4)))
+mat!(match_basic_219, r".*(/000).*", r"/000", Some((0, 4)), Some((0, 4)))
+mat!(match_basic_220, r".*(\\000).*", r"\000", Some((0, 4)), Some((0, 4)))
+mat!(match_basic_221, r"\\000", r"\000", Some((0, 4)))
+
+// Tests from nullsubexpr.dat
+mat!(match_nullsubexpr_3, r"(a*)*", r"a", Some((0, 1)), Some((0, 1)))
+mat!(match_nullsubexpr_5, r"(a*)*", r"x", Some((0, 0)), None)
+mat!(match_nullsubexpr_6, r"(a*)*", r"aaaaaa", Some((0, 6)), Some((0, 6)))
+mat!(match_nullsubexpr_7, r"(a*)*", r"aaaaaax", Some((0, 6)), Some((0, 6)))
+mat!(match_nullsubexpr_8, r"(a*)+", r"a", Some((0, 1)), Some((0, 1)))
+mat!(match_nullsubexpr_9, r"(a*)+", r"x", Some((0, 0)), Some((0, 0)))
+mat!(match_nullsubexpr_10, r"(a*)+", r"aaaaaa", Some((0, 6)), Some((0, 6)))
+mat!(match_nullsubexpr_11, r"(a*)+", r"aaaaaax", Some((0, 6)), Some((0, 6)))
+mat!(match_nullsubexpr_12, r"(a+)*", r"a", Some((0, 1)), Some((0, 1)))
+mat!(match_nullsubexpr_13, r"(a+)*", r"x", Some((0, 0)))
+mat!(match_nullsubexpr_14, r"(a+)*", r"aaaaaa", Some((0, 6)), Some((0, 6)))
+mat!(match_nullsubexpr_15, r"(a+)*", r"aaaaaax", Some((0, 6)), Some((0, 6)))
+mat!(match_nullsubexpr_16, r"(a+)+", r"a", Some((0, 1)), Some((0, 1)))
+mat!(match_nullsubexpr_17, r"(a+)+", r"x", None)
+mat!(match_nullsubexpr_18, r"(a+)+", r"aaaaaa", Some((0, 6)), Some((0, 6)))
+mat!(match_nullsubexpr_19, r"(a+)+", r"aaaaaax", Some((0, 6)), Some((0, 6)))
+mat!(match_nullsubexpr_21, r"([a]*)*", r"a", Some((0, 1)), Some((0, 1)))
+mat!(match_nullsubexpr_23, r"([a]*)*", r"x", Some((0, 0)), None)
+mat!(match_nullsubexpr_24, r"([a]*)*", r"aaaaaa", Some((0, 6)), Some((0, 6)))
+mat!(match_nullsubexpr_25, r"([a]*)*", r"aaaaaax", Some((0, 6)), Some((0, 6)))
+mat!(match_nullsubexpr_26, r"([a]*)+", r"a", Some((0, 1)), Some((0, 1)))
+mat!(match_nullsubexpr_27, r"([a]*)+", r"x", Some((0, 0)), Some((0, 0)))
+mat!(match_nullsubexpr_28, r"([a]*)+", r"aaaaaa", Some((0, 6)), Some((0, 6)))
+mat!(match_nullsubexpr_29, r"([a]*)+", r"aaaaaax", Some((0, 6)), Some((0, 6)))
+mat!(match_nullsubexpr_30, r"([^b]*)*", r"a", Some((0, 1)), Some((0, 1)))
+mat!(match_nullsubexpr_32, r"([^b]*)*", r"b", Some((0, 0)), None)
+mat!(match_nullsubexpr_33, r"([^b]*)*", r"aaaaaa", Some((0, 6)), Some((0, 6)))
+mat!(match_nullsubexpr_34, r"([^b]*)*", r"aaaaaab", Some((0, 6)), Some((0, 6)))
+mat!(match_nullsubexpr_35, r"([ab]*)*", r"a", Some((0, 1)), Some((0, 1)))
+mat!(match_nullsubexpr_36, r"([ab]*)*", r"aaaaaa", Some((0, 6)), Some((0, 6)))
+mat!(match_nullsubexpr_37, r"([ab]*)*", r"ababab", Some((0, 6)), Some((0, 6)))
+mat!(match_nullsubexpr_38, r"([ab]*)*", r"bababa", Some((0, 6)), Some((0, 6)))
+mat!(match_nullsubexpr_39, r"([ab]*)*", r"b", Some((0, 1)), Some((0, 1)))
+mat!(match_nullsubexpr_40, r"([ab]*)*", r"bbbbbb", Some((0, 6)), Some((0, 6)))
+mat!(match_nullsubexpr_41, r"([ab]*)*", r"aaaabcde", Some((0, 5)), Some((0, 5)))
+mat!(match_nullsubexpr_42, r"([^a]*)*", r"b", Some((0, 1)), Some((0, 1)))
+mat!(match_nullsubexpr_43, r"([^a]*)*", r"bbbbbb", Some((0, 6)), Some((0, 6)))
+mat!(match_nullsubexpr_45, r"([^a]*)*", r"aaaaaa", Some((0, 0)), None)
+mat!(match_nullsubexpr_46, r"([^ab]*)*", r"ccccxx", Some((0, 6)), Some((0, 6)))
+mat!(match_nullsubexpr_48, r"([^ab]*)*", r"ababab", Some((0, 0)), None)
+mat!(match_nullsubexpr_50, r"((z)+|a)*", r"zabcde", Some((0, 2)), Some((1, 2)))
+mat!(match_nullsubexpr_69, r"(a*)*(x)", r"x", Some((0, 1)), None, Some((0, 1)))
+mat!(match_nullsubexpr_70, r"(a*)*(x)", r"ax", Some((0, 2)), Some((0, 1)), Some((1, 2)))
+mat!(match_nullsubexpr_71, r"(a*)*(x)", r"axa", Some((0, 2)), Some((0, 1)), Some((1, 2)))
+mat!(match_nullsubexpr_73, r"(a*)+(x)", r"x", Some((0, 1)), Some((0, 0)), Some((0, 1)))
+mat!(match_nullsubexpr_74, r"(a*)+(x)", r"ax", Some((0, 2)), Some((0, 1)), Some((1, 2)))
+mat!(match_nullsubexpr_75, r"(a*)+(x)", r"axa", Some((0, 2)), Some((0, 1)), Some((1, 2)))
+mat!(match_nullsubexpr_77, r"(a*){2}(x)", r"x", Some((0, 1)), Some((0, 0)), Some((0, 1)))
+mat!(match_nullsubexpr_78, r"(a*){2}(x)", r"ax", Some((0, 2)), Some((1, 1)), Some((1, 2)))
+mat!(match_nullsubexpr_79, r"(a*){2}(x)", r"axa", Some((0, 2)), Some((1, 1)), Some((1, 2)))
+
+// Tests from repetition.dat
+mat!(match_repetition_10, r"((..)|(.))", r"", None)
+mat!(match_repetition_11, r"((..)|(.))((..)|(.))", r"", None)
+mat!(match_repetition_12, r"((..)|(.))((..)|(.))((..)|(.))", r"", None)
+mat!(match_repetition_14, r"((..)|(.)){1}", r"", None)
+mat!(match_repetition_15, r"((..)|(.)){2}", r"", None)
+mat!(match_repetition_16, r"((..)|(.)){3}", r"", None)
+mat!(match_repetition_18, r"((..)|(.))*", r"", Some((0, 0)))
+mat!(match_repetition_20, r"((..)|(.))", r"a", Some((0, 1)), Some((0, 1)), None, Some((0, 1)))
+mat!(match_repetition_21, r"((..)|(.))((..)|(.))", r"a", None)
+mat!(match_repetition_22, r"((..)|(.))((..)|(.))((..)|(.))", r"a", None)
+mat!(match_repetition_24, r"((..)|(.)){1}", r"a", Some((0, 1)), Some((0, 1)), None, Some((0, 1)))
+mat!(match_repetition_25, r"((..)|(.)){2}", r"a", None)
+mat!(match_repetition_26, r"((..)|(.)){3}", r"a", None)
+mat!(match_repetition_28, r"((..)|(.))*", r"a", Some((0, 1)), Some((0, 1)), None, Some((0, 1)))
+mat!(match_repetition_30, r"((..)|(.))", r"aa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None)
+mat!(match_repetition_31, r"((..)|(.))((..)|(.))", r"aa", Some((0, 2)), Some((0, 1)), None, Some((0, 1)), Some((1, 2)), None, Some((1, 2)))
+mat!(match_repetition_32, r"((..)|(.))((..)|(.))((..)|(.))", r"aa", None)
+mat!(match_repetition_34, r"((..)|(.)){1}", r"aa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None)
+mat!(match_repetition_35, r"((..)|(.)){2}", r"aa", Some((0, 2)), Some((1, 2)), None, Some((1, 2)))
+mat!(match_repetition_36, r"((..)|(.)){3}", r"aa", None)
+mat!(match_repetition_38, r"((..)|(.))*", r"aa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None)
+mat!(match_repetition_40, r"((..)|(.))", r"aaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None)
+mat!(match_repetition_41, r"((..)|(.))((..)|(.))", r"aaa", Some((0, 3)), Some((0, 2)), Some((0, 2)), None, Some((2, 3)), None, Some((2, 3)))
+mat!(match_repetition_42, r"((..)|(.))((..)|(.))((..)|(.))", r"aaa", Some((0, 3)), Some((0, 1)), None, Some((0, 1)), Some((1, 2)), None, Some((1, 2)), Some((2, 3)), None, Some((2, 3)))
+mat!(match_repetition_44, r"((..)|(.)){1}", r"aaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None)
+mat!(match_repetition_46, r"((..)|(.)){2}", r"aaa", Some((0, 3)), Some((2, 3)), Some((0, 2)), Some((2, 3)))
+mat!(match_repetition_47, r"((..)|(.)){3}", r"aaa", Some((0, 3)), Some((2, 3)), None, Some((2, 3)))
+mat!(match_repetition_50, r"((..)|(.))*", r"aaa", Some((0, 3)), Some((2, 3)), Some((0, 2)), Some((2, 3)))
+mat!(match_repetition_52, r"((..)|(.))", r"aaaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None)
+mat!(match_repetition_53, r"((..)|(.))((..)|(.))", r"aaaa", Some((0, 4)), Some((0, 2)), Some((0, 2)), None, Some((2, 4)), Some((2, 4)), None)
+mat!(match_repetition_54, r"((..)|(.))((..)|(.))((..)|(.))", r"aaaa", Some((0, 4)), Some((0, 2)), Some((0, 2)), None, Some((2, 3)), None, Some((2, 3)), Some((3, 4)), None, Some((3, 4)))
+mat!(match_repetition_56, r"((..)|(.)){1}", r"aaaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None)
+mat!(match_repetition_57, r"((..)|(.)){2}", r"aaaa", Some((0, 4)), Some((2, 4)), Some((2, 4)), None)
+mat!(match_repetition_59, r"((..)|(.)){3}", r"aaaa", Some((0, 4)), Some((3, 4)), Some((0, 2)), Some((3, 4)))
+mat!(match_repetition_61, r"((..)|(.))*", r"aaaa", Some((0, 4)), Some((2, 4)), Some((2, 4)), None)
+mat!(match_repetition_63, r"((..)|(.))", r"aaaaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None)
+mat!(match_repetition_64, r"((..)|(.))((..)|(.))", r"aaaaa", Some((0, 4)), Some((0, 2)), Some((0, 2)), None, Some((2, 4)), Some((2, 4)), None)
+mat!(match_repetition_65, r"((..)|(.))((..)|(.))((..)|(.))", r"aaaaa", Some((0, 5)), Some((0, 2)), Some((0, 2)), None, Some((2, 4)), Some((2, 4)), None, Some((4, 5)), None, Some((4, 5)))
+mat!(match_repetition_67, r"((..)|(.)){1}", r"aaaaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None)
+mat!(match_repetition_68, r"((..)|(.)){2}", r"aaaaa", Some((0, 4)), Some((2, 4)), Some((2, 4)), None)
+mat!(match_repetition_70, r"((..)|(.)){3}", r"aaaaa", Some((0, 5)), Some((4, 5)), Some((2, 4)), Some((4, 5)))
+mat!(match_repetition_73, r"((..)|(.))*", r"aaaaa", Some((0, 5)), Some((4, 5)), Some((2, 4)), Some((4, 5)))
+mat!(match_repetition_75, r"((..)|(.))", r"aaaaaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None)
+mat!(match_repetition_76, r"((..)|(.))((..)|(.))", r"aaaaaa", Some((0, 4)), Some((0, 2)), Some((0, 2)), None, Some((2, 4)), Some((2, 4)), None)
+mat!(match_repetition_77, r"((..)|(.))((..)|(.))((..)|(.))", r"aaaaaa", Some((0, 6)), Some((0, 2)), Some((0, 2)), None, Some((2, 4)), Some((2, 4)), None, Some((4, 6)), Some((4, 6)), None)
+mat!(match_repetition_79, r"((..)|(.)){1}", r"aaaaaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None)
+mat!(match_repetition_80, r"((..)|(.)){2}", r"aaaaaa", Some((0, 4)), Some((2, 4)), Some((2, 4)), None)
+mat!(match_repetition_81, r"((..)|(.)){3}", r"aaaaaa", Some((0, 6)), Some((4, 6)), Some((4, 6)), None)
+mat!(match_repetition_83, r"((..)|(.))*", r"aaaaaa", Some((0, 6)), Some((4, 6)), Some((4, 6)), None)
+mat!(match_repetition_90, r"X(.?){0,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8)))
+mat!(match_repetition_91, r"X(.?){1,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8)))
+mat!(match_repetition_92, r"X(.?){2,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8)))
+mat!(match_repetition_93, r"X(.?){3,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8)))
+mat!(match_repetition_94, r"X(.?){4,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8)))
+mat!(match_repetition_95, r"X(.?){5,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8)))
+mat!(match_repetition_96, r"X(.?){6,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8)))
+mat!(match_repetition_97, r"X(.?){7,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8)))
+mat!(match_repetition_98, r"X(.?){8,}Y", r"X1234567Y", Some((0, 9)), Some((8, 8)))
+mat!(match_repetition_100, r"X(.?){0,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8)))
+mat!(match_repetition_102, r"X(.?){1,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8)))
+mat!(match_repetition_104, r"X(.?){2,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8)))
+mat!(match_repetition_106, r"X(.?){3,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8)))
+mat!(match_repetition_108, r"X(.?){4,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8)))
+mat!(match_repetition_110, r"X(.?){5,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8)))
+mat!(match_repetition_112, r"X(.?){6,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8)))
+mat!(match_repetition_114, r"X(.?){7,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8)))
+mat!(match_repetition_115, r"X(.?){8,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8)))
+mat!(match_repetition_126, r"(a|ab|c|bcd){0,}(d*)", r"ababcd", Some((0, 1)), Some((0, 1)), Some((1, 1)))
+mat!(match_repetition_127, r"(a|ab|c|bcd){1,}(d*)", r"ababcd", Some((0, 1)), Some((0, 1)), Some((1, 1)))
+mat!(match_repetition_128, r"(a|ab|c|bcd){2,}(d*)", r"ababcd", Some((0, 6)), Some((3, 6)), Some((6, 6)))
+mat!(match_repetition_129, r"(a|ab|c|bcd){3,}(d*)", r"ababcd", Some((0, 6)), Some((3, 6)), Some((6, 6)))
+mat!(match_repetition_130, r"(a|ab|c|bcd){4,}(d*)", r"ababcd", None)
+mat!(match_repetition_131, r"(a|ab|c|bcd){0,10}(d*)", r"ababcd", Some((0, 1)), Some((0, 1)), Some((1, 1)))
+mat!(match_repetition_132, r"(a|ab|c|bcd){1,10}(d*)", r"ababcd", Some((0, 1)), Some((0, 1)), Some((1, 1)))
+mat!(match_repetition_133, r"(a|ab|c|bcd){2,10}(d*)", r"ababcd", Some((0, 6)), Some((3, 6)), Some((6, 6)))
+mat!(match_repetition_134, r"(a|ab|c|bcd){3,10}(d*)", r"ababcd", Some((0, 6)), Some((3, 6)), Some((6, 6)))
+mat!(match_repetition_135, r"(a|ab|c|bcd){4,10}(d*)", r"ababcd", None)
+mat!(match_repetition_136, r"(a|ab|c|bcd)*(d*)", r"ababcd", Some((0, 1)), Some((0, 1)), Some((1, 1)))
+mat!(match_repetition_137, r"(a|ab|c|bcd)+(d*)", r"ababcd", Some((0, 1)), Some((0, 1)), Some((1, 1)))
+mat!(match_repetition_143, r"(ab|a|c|bcd){0,}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6)))
+mat!(match_repetition_145, r"(ab|a|c|bcd){1,}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6)))
+mat!(match_repetition_147, r"(ab|a|c|bcd){2,}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6)))
+mat!(match_repetition_149, r"(ab|a|c|bcd){3,}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6)))
+mat!(match_repetition_150, r"(ab|a|c|bcd){4,}(d*)", r"ababcd", None)
+mat!(match_repetition_152, r"(ab|a|c|bcd){0,10}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6)))
+mat!(match_repetition_154, r"(ab|a|c|bcd){1,10}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6)))
+mat!(match_repetition_156, r"(ab|a|c|bcd){2,10}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6)))
+mat!(match_repetition_158, r"(ab|a|c|bcd){3,10}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6)))
+mat!(match_repetition_159, r"(ab|a|c|bcd){4,10}(d*)", r"ababcd", None)
+mat!(match_repetition_161, r"(ab|a|c|bcd)*(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6)))
+mat!(match_repetition_163, r"(ab|a|c|bcd)+(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6)))
+
diff --git a/src/libregex/test/mod.rs b/src/libregex/test/mod.rs
new file mode 100644 (file)
index 0000000..9386e17
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[cfg(not(stage1))]
+#[phase(syntax)]
+extern crate regex_macros;
+
+// Dirty hack: During stage1, test dynamic regexs. For stage2, we test
+// native regexs.
+#[cfg(stage1)]
+macro_rules! regex(
+    ($re:expr) => (
+        match ::regex::Regex::new($re) {
+            Ok(re) => re,
+            Err(err) => fail!("{}", err),
+        }
+    );
+)
+
+mod bench;
+mod tests;
+
diff --git a/src/libregex/test/tests.rs b/src/libregex/test/tests.rs
new file mode 100644 (file)
index 0000000..ce8996c
--- /dev/null
@@ -0,0 +1,199 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+
+use regex::{Regex, NoExpand};
+
+#[test]
+fn splitn() {
+    let re = regex!(r"\d+");
+    let text = "cauchy123plato456tyler789binx";
+    let subs: Vec<&str> = re.splitn(text, 2).collect();
+    assert_eq!(subs, vec!("cauchy", "plato456tyler789binx"));
+}
+
+#[test]
+fn split() {
+    let re = regex!(r"\d+");
+    let text = "cauchy123plato456tyler789binx";
+    let subs: Vec<&str> = re.split(text).collect();
+    assert_eq!(subs, vec!("cauchy", "plato", "tyler", "binx"));
+}
+
+macro_rules! replace(
+    ($name:ident, $which:ident, $re:expr,
+     $search:expr, $replace:expr, $result:expr) => (
+        #[test]
+        fn $name() {
+            let re = regex!($re);
+            assert_eq!(re.$which($search, $replace), StrBuf::from_str($result));
+        }
+    );
+)
+
+replace!(rep_first, replace, r"\d", "age: 26", "Z", "age: Z6")
+replace!(rep_plus, replace, r"\d+", "age: 26", "Z", "age: Z")
+replace!(rep_all, replace_all, r"\d", "age: 26", "Z", "age: ZZ")
+replace!(rep_groups, replace, r"(\S+)\s+(\S+)", "w1 w2", "$2 $1", "w2 w1")
+replace!(rep_double_dollar, replace,
+         r"(\S+)\s+(\S+)", "w1 w2", "$2 $$1", "w2 $1")
+replace!(rep_no_expand, replace,
+         r"(\S+)\s+(\S+)", "w1 w2", NoExpand("$2 $1"), "$2 $1")
+replace!(rep_named, replace_all,
+         r"(?P<first>\S+)\s+(?P<last>\S+)(?P<space>\s*)",
+         "w1 w2 w3 w4", "$last $first$space", "w2 w1 w4 w3")
+replace!(rep_trim, replace_all, "^[ \t]+|[ \t]+$", " \t  trim me\t   \t",
+         "", "trim me")
+
+macro_rules! noparse(
+    ($name:ident, $re:expr) => (
+        #[test]
+        fn $name() {
+            let re = $re;
+            match Regex::new(re) {
+                Err(_) => {},
+                Ok(_) => fail!("Regex '{}' should cause a parse error.", re),
+            }
+        }
+    );
+)
+
+noparse!(fail_double_repeat, "a**")
+noparse!(fail_no_repeat_arg, "*")
+noparse!(fail_no_repeat_arg_begin, "^*")
+noparse!(fail_incomplete_escape, "\\")
+noparse!(fail_class_incomplete, "[A-")
+noparse!(fail_class_not_closed, "[A")
+noparse!(fail_class_no_begin, r"[\A]")
+noparse!(fail_class_no_end, r"[\z]")
+noparse!(fail_class_no_boundary, r"[\b]")
+noparse!(fail_open_paren, "(")
+noparse!(fail_close_paren, ")")
+noparse!(fail_invalid_range, "[a-Z]")
+noparse!(fail_empty_capture_name, "(?P<>a)")
+noparse!(fail_empty_capture_exp, "(?P<name>)")
+noparse!(fail_bad_capture_name, "(?P<na-me>)")
+noparse!(fail_bad_flag, "(?a)a")
+noparse!(fail_empty_alt_before, "|a")
+noparse!(fail_empty_alt_after, "a|")
+noparse!(fail_counted_big_exact, "a{1001}")
+noparse!(fail_counted_big_min, "a{1001,}")
+noparse!(fail_counted_no_close, "a{1001")
+noparse!(fail_unfinished_cap, "(?")
+noparse!(fail_unfinished_escape, "\\")
+noparse!(fail_octal_digit, r"\8")
+noparse!(fail_hex_digit, r"\xG0")
+noparse!(fail_hex_short, r"\xF")
+noparse!(fail_hex_long_digits, r"\x{fffg}")
+noparse!(fail_flag_bad, "(?a)")
+noparse!(fail_flag_empty, "(?)")
+noparse!(fail_double_neg, "(?-i-i)")
+noparse!(fail_neg_empty, "(?i-)")
+noparse!(fail_empty_group, "()")
+noparse!(fail_dupe_named, "(?P<a>.)(?P<a>.)")
+
+macro_rules! mat(
+    ($name:ident, $re:expr, $text:expr, $($loc:tt)+) => (
+        #[test]
+        fn $name() {
+            let text = $text;
+            let expected: Vec<Option<(uint, uint)>> = vec!($($loc)+);
+            let r = regex!($re);
+            let got = match r.captures(text) {
+                Some(c) => c.iter_pos().collect::<Vec<Option<(uint, uint)>>>(),
+                None => vec!(None),
+            };
+            // The test set sometimes leave out capture groups, so truncate
+            // actual capture groups to match test set.
+            let (sexpect, mut sgot) = (expected.as_slice(), got.as_slice());
+            if sgot.len() > sexpect.len() {
+                sgot = sgot.slice(0, sexpect.len())
+            }
+            if sexpect != sgot {
+                fail!("For RE '{}' against '{}', expected '{}' but got '{}'",
+                      $re, text, sexpect, sgot);
+            }
+        }
+    );
+)
+
+// Some crazy expressions from regular-expressions.info.
+mat!(match_ranges,
+     r"\b(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b",
+     "num: 255", Some((5, 8)))
+mat!(match_ranges_not,
+     r"\b(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b",
+     "num: 256", None)
+mat!(match_float1, r"[-+]?[0-9]*\.?[0-9]+", "0.1", Some((0, 3)))
+mat!(match_float2, r"[-+]?[0-9]*\.?[0-9]+", "0.1.2", Some((0, 3)))
+mat!(match_float3, r"[-+]?[0-9]*\.?[0-9]+", "a1.2", Some((1, 4)))
+mat!(match_float4, r"^[-+]?[0-9]*\.?[0-9]+$", "1.a", None)
+mat!(match_email, r"(?i)\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b",
+     "mine is jam.slam@gmail.com ", Some((8, 26)))
+mat!(match_email_not, r"(?i)\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b",
+     "mine is jam.slam@gmail ", None)
+mat!(match_email_big, r"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?",
+     "mine is jam.slam@gmail.com ", Some((8, 26)))
+mat!(match_date1,
+     r"^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$",
+     "1900-01-01", Some((0, 10)))
+mat!(match_date2,
+     r"^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$",
+     "1900-00-01", None)
+mat!(match_date3,
+     r"^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$",
+     "1900-13-01", None)
+
+// Exercise the flags.
+mat!(match_flag_case, "(?i)abc", "ABC", Some((0, 3)))
+mat!(match_flag_weird_case, "(?i)a(?-i)bc", "Abc", Some((0, 3)))
+mat!(match_flag_weird_case_not, "(?i)a(?-i)bc", "ABC", None)
+mat!(match_flag_case_dotnl, "(?is)a.", "A\n", Some((0, 2)))
+mat!(match_flag_case_dotnl_toggle, "(?is)a.(?-is)a.", "A\nab", Some((0, 4)))
+mat!(match_flag_case_dotnl_toggle_not, "(?is)a.(?-is)a.", "A\na\n", None)
+mat!(match_flag_case_dotnl_toggle_ok, "(?is)a.(?-is:a.)?", "A\na\n", Some((0, 2)))
+mat!(match_flag_multi, "(?m)(?:^\\d+$\n?)+", "123\n456\n789", Some((0, 11)))
+mat!(match_flag_ungreedy, "(?U)a+", "aa", Some((0, 1)))
+mat!(match_flag_ungreedy_greedy, "(?U)a+?", "aa", Some((0, 2)))
+mat!(match_flag_ungreedy_noop, "(?U)(?-U)a+", "aa", Some((0, 2)))
+
+// Some Unicode tests.
+mat!(uni_literal, r"Ⅰ", "Ⅰ", Some((0, 3)))
+mat!(uni_one, r"\pN", "Ⅰ", Some((0, 3)))
+mat!(uni_mixed, r"\pN+", "Ⅰ1Ⅱ2", Some((0, 8)))
+mat!(uni_not, r"\PN+", "abⅠ", Some((0, 2)))
+mat!(uni_not_class, r"[\PN]+", "abⅠ", Some((0, 2)))
+mat!(uni_not_class_neg, r"[^\PN]+", "abⅠ", Some((2, 5)))
+mat!(uni_case, r"(?i)Δ", "δ", Some((0, 2)))
+mat!(uni_case_not, r"Δ", "δ", None)
+mat!(uni_case_upper, r"\p{Lu}+", "ΛΘΓΔα", Some((0, 8)))
+mat!(uni_case_upper_nocase_flag, r"(?i)\p{Lu}+", "ΛΘΓΔα", Some((0, 10)))
+mat!(uni_case_upper_nocase, r"\p{L}+", "ΛΘΓΔα", Some((0, 10)))
+mat!(uni_case_lower, r"\p{Ll}+", "ΛΘΓΔα", Some((8, 10)))
+
+// Test the Unicode friendliness of Perl character classes.
+mat!(uni_perl_w, r"\w+", "dδd", Some((0, 4)))
+mat!(uni_perl_w_not, r"\w+", "Ⅱ", None)
+mat!(uni_perl_w_neg, r"\W+", "Ⅱ", Some((0, 3)))
+mat!(uni_perl_d, r"\d+", "1२३9", Some((0, 8)))
+mat!(uni_perl_d_not, r"\d+", "Ⅱ", None)
+mat!(uni_perl_d_neg, r"\D+", "Ⅱ", Some((0, 3)))
+mat!(uni_perl_s, r"\s+", " ", Some((0, 3)))
+mat!(uni_perl_s_not, r"\s+", "☃", None)
+mat!(uni_perl_s_neg, r"\S+", "☃", Some((0, 3)))
+
+// And do the same for word boundaries.
+mat!(uni_boundary_none, r"\d\b", "6δ", None)
+mat!(uni_boundary_ogham, r"\d\b", "6 ", Some((0, 1)))
+
+// A whole mess of tests from Glenn Fowler's regex test suite.
+// Generated by the 'src/etc/regex-match-tests' program.
+mod matches;
diff --git a/src/libregex/testdata/LICENSE b/src/libregex/testdata/LICENSE
new file mode 100644 (file)
index 0000000..f47dbf4
--- /dev/null
@@ -0,0 +1,19 @@
+The following license covers testregex.c and all associated test data.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of THIS SOFTWARE FILE (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, and/or sell copies of the
+Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following disclaimer:
+
+THIS SOFTWARE IS PROVIDED BY AT&T ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL AT&T BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/libregex/testdata/README b/src/libregex/testdata/README
new file mode 100644 (file)
index 0000000..33b0ba1
--- /dev/null
@@ -0,0 +1,17 @@
+Test data was taken from the Go distribution, which was in turn taken from the 
+testregex test suite:
+
+  http://www2.research.att.com/~astopen/testregex/testregex.html
+
+The LICENSE in this directory corresponds to the LICENSE that the data was
+released under.
+
+The tests themselves were modified for RE2/Go. A couple were modified further 
+by me (Andrew Gallant) (only in repetition.dat) so that RE2/Go would pass them. 
+(Yes, it seems like RE2/Go includes failing test cases.) This may or may not 
+have been a bad idea, but I think being consistent with an established Regex 
+library is worth something.
+
+Note that these files are read by 'src/etc/regexp-match-tests' and turned into 
+Rust tests found in 'src/libregexp/tests/matches.rs'.
+
diff --git a/src/libregex/testdata/basic.dat b/src/libregex/testdata/basic.dat
new file mode 100644 (file)
index 0000000..e55efae
--- /dev/null
@@ -0,0 +1,221 @@
+NOTE   all standard compliant implementations should pass these : 2002-05-31
+
+BE     abracadabra$    abracadabracadabra      (7,18)
+BE     a...b           abababbb                (2,7)
+BE     XXXXXX          ..XXXXXX                (2,8)
+E      \)              ()      (1,2)
+BE     a]              a]a     (0,2)
+B      }               }       (0,1)
+E      \}              }       (0,1)
+BE     \]              ]       (0,1)
+B      ]               ]       (0,1)
+E      ]               ]       (0,1)
+B      {               {       (0,1)
+B      }               }       (0,1)
+BE     ^a              ax      (0,1)
+BE     \^a             a^a     (1,3)
+BE     a\^             a^      (0,2)
+BE     a$              aa      (1,2)
+BE     a\$             a$      (0,2)
+BE     ^$              NULL    (0,0)
+E      $^              NULL    (0,0)
+E      a($)            aa      (1,2)(2,2)
+E      a*(^a)          aa      (0,1)(0,1)
+E      (..)*(...)*             a       (0,0)
+E      (..)*(...)*             abcd    (0,4)(2,4)
+E      (ab|a)(bc|c)            abc     (0,3)(0,2)(2,3)
+E      (ab)c|abc               abc     (0,3)(0,2)
+E      a{0}b           ab                      (1,2)
+E      (a*)(b?)(b+)b{3}        aaabbbbbbb      (0,10)(0,3)(3,4)(4,7)
+E      (a*)(b{0,1})(b{1,})b{3} aaabbbbbbb      (0,10)(0,3)(3,4)(4,7)
+E      a{9876543210}   NULL    BADBR
+E      ((a|a)|a)                       a       (0,1)(0,1)(0,1)
+E      (a*)(a|aa)                      aaaa    (0,4)(0,3)(3,4)
+E      a*(a.|aa)                       aaaa    (0,4)(2,4)
+E      a(b)|c(d)|a(e)f                 aef     (0,3)(?,?)(?,?)(1,2)
+E      (a|b)?.*                        b       (0,1)(0,1)
+E      (a|b)c|a(b|c)                   ac      (0,2)(0,1)
+E      (a|b)c|a(b|c)                   ab      (0,2)(?,?)(1,2)
+E      (a|b)*c|(a|ab)*c                abc     (0,3)(1,2)
+E      (a|b)*c|(a|ab)*c                xc      (1,2)
+E      (.a|.b).*|.*(.a|.b)             xa      (0,2)(0,2)
+E      a?(ab|ba)ab                     abab    (0,4)(0,2)
+E      a?(ac{0}b|ba)ab                 abab    (0,4)(0,2)
+E      ab|abab                         abbabab (0,2)
+E      aba|bab|bba                     baaabbbaba      (5,8)
+E      aba|bab                         baaabbbaba      (6,9)
+E      (aa|aaa)*|(a|aaaaa)             aa      (0,2)(0,2)
+E      (a.|.a.)*|(a|.a...)             aa      (0,2)(0,2)
+E      ab|a                            xabc    (1,3)
+E      ab|a                            xxabc   (2,4)
+Ei     (Ab|cD)*                        aBcD    (0,4)(2,4)
+BE     [^-]                    --a             (2,3)
+BE     [a-]*                   --a             (0,3)
+BE     [a-m-]*                 --amoma--       (0,4)
+E      :::1:::0:|:::1:1:0:     :::0:::1:::1:::0:       (8,17)
+E      :::1:::0:|:::1:1:1:     :::0:::1:::1:::0:       (8,17)
+{E     [[:upper:]]             A               (0,1)   [[<element>]] not supported
+E      [[:lower:]]+            `az{            (1,3)
+E      [[:upper:]]+            @AZ[            (1,3)
+# No collation in Go
+#BE    [[-]]                   [[-]]           (2,4)
+#BE    [[.NIL.]]       NULL    ECOLLATE
+#BE    [[=aleph=]]     NULL    ECOLLATE
+}
+BE$    \n              \n      (0,1)
+BEn$   \n              \n      (0,1)
+BE$    [^a]            \n      (0,1)
+BE$    \na             \na     (0,2)
+E      (a)(b)(c)       abc     (0,3)(0,1)(1,2)(2,3)
+BE     xxx             xxx     (0,3)
+E1     (^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$)      feb 6,  (0,6)
+E1     (^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$)      2/7     (0,3)
+E1     (^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$)      feb 1,Feb 6     (5,11)
+E3     ((((((((((((((((((((((((((((((x))))))))))))))))))))))))))))))   x       (0,1)(0,1)(0,1)
+E3     ((((((((((((((((((((((((((((((x))))))))))))))))))))))))))))))*  xx      (0,2)(1,2)(1,2)
+E      a?(ab|ba)*      ababababababababababababababababababababababababababababababababababababababababa       (0,81)(79,81)
+E      abaa|abbaa|abbbaa|abbbbaa       ababbabbbabbbabbbbabbbbaa       (18,25)
+E      abaa|abbaa|abbbaa|abbbbaa       ababbabbbabbbabbbbabaa  (18,22)
+E      aaac|aabc|abac|abbc|baac|babc|bbac|bbbc baaabbbabac     (7,11)
+BE$    .*                      \x01\x7f        (0,2)
+E      aaaa|bbbb|cccc|ddddd|eeeeee|fffffff|gggg|hhhh|iiiii|jjjjj|kkkkk|llll            XaaaXbbbXcccXdddXeeeXfffXgggXhhhXiiiXjjjXkkkXlllXcbaXaaaa       (53,57)
+L      aaaa\nbbbb\ncccc\nddddd\neeeeee\nfffffff\ngggg\nhhhh\niiiii\njjjjj\nkkkkk\nllll         XaaaXbbbXcccXdddXeeeXfffXgggXhhhXiiiXjjjXkkkXlllXcbaXaaaa       NOMATCH
+E      a*a*a*a*a*b             aaaaaaaaab      (0,10)
+BE     ^                       NULL            (0,0)
+BE     $                       NULL            (0,0)
+BE     ^$                      NULL            (0,0)
+BE     ^a$                     a               (0,1)
+BE     abc                     abc             (0,3)
+BE     abc                     xabcy           (1,4)
+BE     abc                     ababc           (2,5)
+BE     ab*c                    abc             (0,3)
+BE     ab*bc                   abc             (0,3)
+BE     ab*bc                   abbc            (0,4)
+BE     ab*bc                   abbbbc          (0,6)
+E      ab+bc                   abbc            (0,4)
+E      ab+bc                   abbbbc          (0,6)
+E      ab?bc                   abbc            (0,4)
+E      ab?bc                   abc             (0,3)
+E      ab?c                    abc             (0,3)
+BE     ^abc$                   abc             (0,3)
+BE     ^abc                    abcc            (0,3)
+BE     abc$                    aabc            (1,4)
+BE     ^                       abc             (0,0)
+BE     $                       abc             (3,3)
+BE     a.c                     abc             (0,3)
+BE     a.c                     axc             (0,3)
+BE     a.*c                    axyzc           (0,5)
+BE     a[bc]d                  abd             (0,3)
+BE     a[b-d]e                 ace             (0,3)
+BE     a[b-d]                  aac             (1,3)
+BE     a[-b]                   a-              (0,2)
+BE     a[b-]                   a-              (0,2)
+BE     a]                      a]              (0,2)
+BE     a[]]b                   a]b             (0,3)
+BE     a[^bc]d                 aed             (0,3)
+BE     a[^-b]c                 adc             (0,3)
+BE     a[^]b]c                 adc             (0,3)
+E      ab|cd                   abc             (0,2)
+E      ab|cd                   abcd            (0,2)
+E      a\(b                    a(b             (0,3)
+E      a\(*b                   ab              (0,2)
+E      a\(*b                   a((b            (0,4)
+E      ((a))                   abc             (0,1)(0,1)(0,1)
+E      (a)b(c)                 abc             (0,3)(0,1)(2,3)
+E      a+b+c                   aabbabc         (4,7)
+E      a*                      aaa             (0,3)
+#E     (a*)*                   -               (0,0)(0,0)
+E      (a*)*                   -               (0,0)(?,?)      RE2/Go
+E      (a*)+                   -               (0,0)(0,0)
+#E     (a*|b)*                 -               (0,0)(0,0)
+E      (a*|b)*                 -               (0,0)(?,?)      RE2/Go
+E      (a+|b)*                 ab              (0,2)(1,2)
+E      (a+|b)+                 ab              (0,2)(1,2)
+E      (a+|b)?                 ab              (0,1)(0,1)
+BE     [^ab]*                  cde             (0,3)
+#E     (^)*                    -               (0,0)(0,0)
+E      (^)*                    -               (0,0)(?,?)      RE2/Go
+BE     a*                      NULL            (0,0)
+E      ([abc])*d               abbbcd          (0,6)(4,5)
+E      ([abc])*bcd             abcd            (0,4)(0,1)
+E      a|b|c|d|e               e               (0,1)
+E      (a|b|c|d|e)f            ef              (0,2)(0,1)
+#E     ((a*|b))*               -               (0,0)(0,0)(0,0)
+E      ((a*|b))*               -               (0,0)(?,?)(?,?) RE2/Go
+BE     abcd*efg                abcdefg         (0,7)
+BE     ab*                     xabyabbbz       (1,3)
+BE     ab*                     xayabbbz        (1,2)
+E      (ab|cd)e                abcde           (2,5)(2,4)
+BE     [abhgefdc]ij            hij             (0,3)
+E      (a|b)c*d                abcd            (1,4)(1,2)
+E      (ab|ab*)bc              abc             (0,3)(0,1)
+E      a([bc]*)c*              abc             (0,3)(1,3)
+E      a([bc]*)(c*d)           abcd            (0,4)(1,3)(3,4)
+E      a([bc]+)(c*d)           abcd            (0,4)(1,3)(3,4)
+E      a([bc]*)(c+d)           abcd            (0,4)(1,2)(2,4)
+E      a[bcd]*dcdcde           adcdcde         (0,7)
+E      (ab|a)b*c               abc             (0,3)(0,2)
+E      ((a)(b)c)(d)            abcd            (0,4)(0,3)(0,1)(1,2)(3,4)
+BE     [A-Za-z_][A-Za-z0-9_]*  alpha           (0,5)
+E      ^a(bc+|b[eh])g|.h$      abh             (1,3)
+E      (bc+d$|ef*g.|h?i(j|k))  effgz           (0,5)(0,5)
+E      (bc+d$|ef*g.|h?i(j|k))  ij              (0,2)(0,2)(1,2)
+E      (bc+d$|ef*g.|h?i(j|k))  reffgz          (1,6)(1,6)
+E      (((((((((a)))))))))     a               (0,1)(0,1)(0,1)(0,1)(0,1)(0,1)(0,1)(0,1)(0,1)(0,1)
+BE     multiple words          multiple words yeah     (0,14)
+E      (.*)c(.*)               abcde           (0,5)(0,2)(3,5)
+BE     abcd                    abcd            (0,4)
+E      a(bc)d                  abcd            (0,4)(1,3)
+E      a[\ 1-\ 3]?c                a\ 2c             (0,3)
+E      M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]       Muammar Qaddafi (0,15)(?,?)(10,12)
+E      M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]       Mo'ammar Gadhafi        (0,16)(?,?)(11,13)
+E      M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]       Muammar Kaddafi (0,15)(?,?)(10,12)
+E      M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]       Muammar Qadhafi (0,15)(?,?)(10,12)
+E      M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]       Muammar Gadafi  (0,14)(?,?)(10,11)
+E      M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]       Mu'ammar Qadafi (0,15)(?,?)(11,12)
+E      M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]       Moamar Gaddafi  (0,14)(?,?)(9,11)
+E      M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]       Mu'ammar Qadhdhafi      (0,18)(?,?)(13,15)
+E      M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]       Muammar Khaddafi        (0,16)(?,?)(11,13)
+E      M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]       Muammar Ghaddafy        (0,16)(?,?)(11,13)
+E      M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]       Muammar Ghadafi (0,15)(?,?)(11,12)
+E      M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]       Muammar Ghaddafi        (0,16)(?,?)(11,13)
+E      M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]       Muamar Kaddafi  (0,14)(?,?)(9,11)
+E      M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]       Muammar Quathafi        (0,16)(?,?)(11,13)
+E      M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]       Muammar Gheddafi        (0,16)(?,?)(11,13)
+E      M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]       Moammar Khadafy (0,15)(?,?)(11,12)
+E      M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]       Moammar Qudhafi (0,15)(?,?)(10,12)
+E      a+(b|c)*d+              aabcdd                  (0,6)(3,4)
+E      ^.+$                    vivi                    (0,4)
+E      ^(.+)$                  vivi                    (0,4)(0,4)
+E      ^([^!.]+).att.com!(.+)$ gryphon.att.com!eby     (0,19)(0,7)(16,19)
+E      ^([^!]+!)?([^!]+)$      bas                     (0,3)(?,?)(0,3)
+E      ^([^!]+!)?([^!]+)$      bar!bas                 (0,7)(0,4)(4,7)
+E      ^([^!]+!)?([^!]+)$      foo!bas                 (0,7)(0,4)(4,7)
+E      ^.+!([^!]+!)([^!]+)$    foo!bar!bas             (0,11)(4,8)(8,11)
+E      ((foo)|(bar))!bas       bar!bas                 (0,7)(0,3)(?,?)(0,3)
+E      ((foo)|(bar))!bas       foo!bar!bas             (4,11)(4,7)(?,?)(4,7)
+E      ((foo)|(bar))!bas       foo!bas                 (0,7)(0,3)(0,3)
+E      ((foo)|bar)!bas         bar!bas                 (0,7)(0,3)
+E      ((foo)|bar)!bas         foo!bar!bas             (4,11)(4,7)
+E      ((foo)|bar)!bas         foo!bas                 (0,7)(0,3)(0,3)
+E      (foo|(bar))!bas         bar!bas                 (0,7)(0,3)(0,3)
+E      (foo|(bar))!bas         foo!bar!bas             (4,11)(4,7)(4,7)
+E      (foo|(bar))!bas         foo!bas                 (0,7)(0,3)
+E      (foo|bar)!bas           bar!bas                 (0,7)(0,3)
+E      (foo|bar)!bas           foo!bar!bas             (4,11)(4,7)
+E      (foo|bar)!bas           foo!bas                 (0,7)(0,3)
+E      ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ foo!bar!bas     (0,11)(0,11)(?,?)(?,?)(4,8)(8,11)
+E      ^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$ bas             (0,3)(?,?)(0,3)
+E      ^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$ bar!bas         (0,7)(0,4)(4,7)
+E      ^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$ foo!bar!bas     (0,11)(?,?)(?,?)(4,8)(8,11)
+E      ^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$ foo!bas         (0,7)(0,4)(4,7)
+E      ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ bas             (0,3)(0,3)(?,?)(0,3)
+E      ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ bar!bas         (0,7)(0,7)(0,4)(4,7)
+E      ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ foo!bar!bas     (0,11)(0,11)(?,?)(?,?)(4,8)(8,11)
+E      ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ foo!bas         (0,7)(0,7)(0,4)(4,7)
+E      .*(/XXX).*                      /XXX                    (0,4)(0,4)
+E      .*(\\XXX).*                     \XXX                    (0,4)(0,4)
+E      \\XXX                           \XXX                    (0,4)
+E      .*(/000).*                      /000                    (0,4)(0,4)
+E      .*(\\000).*                     \000                    (0,4)(0,4)
+E      \\000                           \000                    (0,4)
diff --git a/src/libregex/testdata/nullsubexpr.dat b/src/libregex/testdata/nullsubexpr.dat
new file mode 100644 (file)
index 0000000..2e18fbb
--- /dev/null
@@ -0,0 +1,79 @@
+NOTE   null subexpression matches : 2002-06-06
+
+E      (a*)*           a               (0,1)(0,1)
+#E     SAME            x               (0,0)(0,0)
+E      SAME            x               (0,0)(?,?)      RE2/Go
+E      SAME            aaaaaa          (0,6)(0,6)
+E      SAME            aaaaaax         (0,6)(0,6)
+E      (a*)+           a               (0,1)(0,1)
+E      SAME            x               (0,0)(0,0)
+E      SAME            aaaaaa          (0,6)(0,6)
+E      SAME            aaaaaax         (0,6)(0,6)
+E      (a+)*           a               (0,1)(0,1)
+E      SAME            x               (0,0)
+E      SAME            aaaaaa          (0,6)(0,6)
+E      SAME            aaaaaax         (0,6)(0,6)
+E      (a+)+           a               (0,1)(0,1)
+E      SAME            x               NOMATCH
+E      SAME            aaaaaa          (0,6)(0,6)
+E      SAME            aaaaaax         (0,6)(0,6)
+
+E      ([a]*)*         a               (0,1)(0,1)
+#E     SAME            x               (0,0)(0,0)
+E      SAME            x               (0,0)(?,?)      RE2/Go
+E      SAME            aaaaaa          (0,6)(0,6)
+E      SAME            aaaaaax         (0,6)(0,6)
+E      ([a]*)+         a               (0,1)(0,1)
+E      SAME            x               (0,0)(0,0)
+E      SAME            aaaaaa          (0,6)(0,6)
+E      SAME            aaaaaax         (0,6)(0,6)
+E      ([^b]*)*        a               (0,1)(0,1)
+#E     SAME            b               (0,0)(0,0)
+E      SAME            b               (0,0)(?,?)      RE2/Go
+E      SAME            aaaaaa          (0,6)(0,6)
+E      SAME            aaaaaab         (0,6)(0,6)
+E      ([ab]*)*        a               (0,1)(0,1)
+E      SAME            aaaaaa          (0,6)(0,6)
+E      SAME            ababab          (0,6)(0,6)
+E      SAME            bababa          (0,6)(0,6)
+E      SAME            b               (0,1)(0,1)
+E      SAME            bbbbbb          (0,6)(0,6)
+E      SAME            aaaabcde        (0,5)(0,5)
+E      ([^a]*)*        b               (0,1)(0,1)
+E      SAME            bbbbbb          (0,6)(0,6)
+#E     SAME            aaaaaa          (0,0)(0,0)
+E      SAME            aaaaaa          (0,0)(?,?)      RE2/Go
+E      ([^ab]*)*       ccccxx          (0,6)(0,6)
+#E     SAME            ababab          (0,0)(0,0)
+E      SAME            ababab          (0,0)(?,?)      RE2/Go
+
+E      ((z)+|a)*       zabcde          (0,2)(1,2)
+
+#{E    a+?             aaaaaa          (0,1)   no *? +? mimimal match ops
+#E     (a)             aaa             (0,1)(0,1)
+#E     (a*?)           aaa             (0,0)(0,0)
+#E     (a)*?           aaa             (0,0)
+#E     (a*?)*?         aaa             (0,0)
+#}
+
+B      \(a*\)*\(x\)            x       (0,1)(0,0)(0,1)
+B      \(a*\)*\(x\)            ax      (0,2)(0,1)(1,2)
+B      \(a*\)*\(x\)            axa     (0,2)(0,1)(1,2)
+B      \(a*\)*\(x\)\(\1\)      x       (0,1)(0,0)(0,1)(1,1)
+B      \(a*\)*\(x\)\(\1\)      ax      (0,2)(1,1)(1,2)(2,2)
+B      \(a*\)*\(x\)\(\1\)      axa     (0,3)(0,1)(1,2)(2,3)
+B      \(a*\)*\(x\)\(\1\)\(x\) axax    (0,4)(0,1)(1,2)(2,3)(3,4)
+B      \(a*\)*\(x\)\(\1\)\(x\) axxa    (0,3)(1,1)(1,2)(2,2)(2,3)
+
+#E     (a*)*(x)                x       (0,1)(0,0)(0,1)
+E      (a*)*(x)                x       (0,1)(?,?)(0,1) RE2/Go
+E      (a*)*(x)                ax      (0,2)(0,1)(1,2)
+E      (a*)*(x)                axa     (0,2)(0,1)(1,2)
+
+E      (a*)+(x)                x       (0,1)(0,0)(0,1)
+E      (a*)+(x)                ax      (0,2)(0,1)(1,2)
+E      (a*)+(x)                axa     (0,2)(0,1)(1,2)
+
+E      (a*){2}(x)              x       (0,1)(0,0)(0,1)
+E      (a*){2}(x)              ax      (0,2)(1,1)(1,2)
+E      (a*){2}(x)              axa     (0,2)(1,1)(1,2)
diff --git a/src/libregex/testdata/repetition.dat b/src/libregex/testdata/repetition.dat
new file mode 100644 (file)
index 0000000..3bb2121
--- /dev/null
@@ -0,0 +1,163 @@
+NOTE   implicit vs. explicit repetitions : 2009-02-02
+
+# Glenn Fowler <gsf@research.att.com>
+# conforming matches (column 4) must match one of the following BREs
+#      NOMATCH
+#      (0,.)\((\(.\),\(.\))(?,?)(\2,\3)\)*
+#      (0,.)\((\(.\),\(.\))(\2,\3)(?,?)\)*
+# i.e., each 3-tuple has two identical elements and one (?,?)
+
+E      ((..)|(.))                              NULL            NOMATCH
+E      ((..)|(.))((..)|(.))                    NULL            NOMATCH
+E      ((..)|(.))((..)|(.))((..)|(.))          NULL            NOMATCH
+
+E      ((..)|(.)){1}                           NULL            NOMATCH
+E      ((..)|(.)){2}                           NULL            NOMATCH
+E      ((..)|(.)){3}                           NULL            NOMATCH
+
+E      ((..)|(.))*                             NULL            (0,0)
+
+E      ((..)|(.))                              a               (0,1)(0,1)(?,?)(0,1)
+E      ((..)|(.))((..)|(.))                    a               NOMATCH
+E      ((..)|(.))((..)|(.))((..)|(.))          a               NOMATCH
+
+E      ((..)|(.)){1}                           a               (0,1)(0,1)(?,?)(0,1)
+E      ((..)|(.)){2}                           a               NOMATCH
+E      ((..)|(.)){3}                           a               NOMATCH
+
+E      ((..)|(.))*                             a               (0,1)(0,1)(?,?)(0,1)
+
+E      ((..)|(.))                              aa              (0,2)(0,2)(0,2)(?,?)
+E      ((..)|(.))((..)|(.))                    aa              (0,2)(0,1)(?,?)(0,1)(1,2)(?,?)(1,2)
+E      ((..)|(.))((..)|(.))((..)|(.))          aa              NOMATCH
+
+E      ((..)|(.)){1}                           aa              (0,2)(0,2)(0,2)(?,?)
+E      ((..)|(.)){2}                           aa              (0,2)(1,2)(?,?)(1,2)
+E      ((..)|(.)){3}                           aa              NOMATCH
+
+E      ((..)|(.))*                             aa              (0,2)(0,2)(0,2)(?,?)
+
+E      ((..)|(.))                              aaa             (0,2)(0,2)(0,2)(?,?)
+E      ((..)|(.))((..)|(.))                    aaa             (0,3)(0,2)(0,2)(?,?)(2,3)(?,?)(2,3)
+E      ((..)|(.))((..)|(.))((..)|(.))          aaa             (0,3)(0,1)(?,?)(0,1)(1,2)(?,?)(1,2)(2,3)(?,?)(2,3)
+
+E      ((..)|(.)){1}                           aaa             (0,2)(0,2)(0,2)(?,?)
+#E     ((..)|(.)){2}                           aaa             (0,3)(2,3)(?,?)(2,3)
+E      ((..)|(.)){2}                           aaa             (0,3)(2,3)(0,2)(2,3)    RE2/Go
+E      ((..)|(.)){3}                           aaa             (0,3)(2,3)(?,?)(2,3)
+
+#E     ((..)|(.))*                             aaa             (0,3)(2,3)(?,?)(2,3)
+E      ((..)|(.))*                             aaa             (0,3)(2,3)(0,2)(2,3)    RE2/Go
+
+E      ((..)|(.))                              aaaa            (0,2)(0,2)(0,2)(?,?)
+E      ((..)|(.))((..)|(.))                    aaaa            (0,4)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)
+E      ((..)|(.))((..)|(.))((..)|(.))          aaaa            (0,4)(0,2)(0,2)(?,?)(2,3)(?,?)(2,3)(3,4)(?,?)(3,4)
+
+E      ((..)|(.)){1}                           aaaa            (0,2)(0,2)(0,2)(?,?)
+E      ((..)|(.)){2}                           aaaa            (0,4)(2,4)(2,4)(?,?)
+#E     ((..)|(.)){3}                           aaaa            (0,4)(3,4)(?,?)(3,4)
+E      ((..)|(.)){3}                           aaaa            (0,4)(3,4)(0,2)(3,4)    RE2/Go
+
+E      ((..)|(.))*                             aaaa            (0,4)(2,4)(2,4)(?,?)
+
+E      ((..)|(.))                              aaaaa           (0,2)(0,2)(0,2)(?,?)
+E      ((..)|(.))((..)|(.))                    aaaaa           (0,4)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)
+E      ((..)|(.))((..)|(.))((..)|(.))          aaaaa           (0,5)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)(4,5)(?,?)(4,5)
+
+E      ((..)|(.)){1}                           aaaaa           (0,2)(0,2)(0,2)(?,?)
+E      ((..)|(.)){2}                           aaaaa           (0,4)(2,4)(2,4)(?,?)
+#E     ((..)|(.)){3}                           aaaaa           (0,5)(4,5)(?,?)(4,5)
+E      ((..)|(.)){3}                           aaaaa           (0,5)(4,5)(2,4)(4,5)    RE2/Go
+
+#E     ((..)|(.))*                             aaaaa           (0,5)(4,5)(?,?)(4,5)
+E      ((..)|(.))*                             aaaaa           (0,5)(4,5)(2,4)(4,5)    RE2/Go
+
+E      ((..)|(.))                              aaaaaa          (0,2)(0,2)(0,2)(?,?)
+E      ((..)|(.))((..)|(.))                    aaaaaa          (0,4)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)
+E      ((..)|(.))((..)|(.))((..)|(.))          aaaaaa          (0,6)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)(4,6)(4,6)(?,?)
+
+E      ((..)|(.)){1}                           aaaaaa          (0,2)(0,2)(0,2)(?,?)
+E      ((..)|(.)){2}                           aaaaaa          (0,4)(2,4)(2,4)(?,?)
+E      ((..)|(.)){3}                           aaaaaa          (0,6)(4,6)(4,6)(?,?)
+
+E      ((..)|(.))*                             aaaaaa          (0,6)(4,6)(4,6)(?,?)
+
+NOTE   additional repetition tests graciously provided by Chris Kuklewicz www.haskell.org 2009-02-02
+
+# These test a bug in OS X / FreeBSD / NetBSD, and libtree. 
+# Linux/GLIBC gets the {8,} and {8,8} wrong.
+
+:HA#100:E      X(.?){0,}Y      X1234567Y       (0,9)(7,8)
+:HA#101:E      X(.?){1,}Y      X1234567Y       (0,9)(7,8)
+:HA#102:E      X(.?){2,}Y      X1234567Y       (0,9)(7,8)
+:HA#103:E      X(.?){3,}Y      X1234567Y       (0,9)(7,8)
+:HA#104:E      X(.?){4,}Y      X1234567Y       (0,9)(7,8)
+:HA#105:E      X(.?){5,}Y      X1234567Y       (0,9)(7,8)
+:HA#106:E      X(.?){6,}Y      X1234567Y       (0,9)(7,8)
+:HA#107:E      X(.?){7,}Y      X1234567Y       (0,9)(7,8)
+:HA#108:E      X(.?){8,}Y      X1234567Y       (0,9)(8,8)
+#:HA#110:E     X(.?){0,8}Y     X1234567Y       (0,9)(7,8)
+:HA#110:E      X(.?){0,8}Y     X1234567Y       (0,9)(8,8)      RE2/Go
+#:HA#111:E     X(.?){1,8}Y     X1234567Y       (0,9)(7,8)
+:HA#111:E      X(.?){1,8}Y     X1234567Y       (0,9)(8,8)      RE2/Go
+#:HA#112:E     X(.?){2,8}Y     X1234567Y       (0,9)(7,8)
+:HA#112:E      X(.?){2,8}Y     X1234567Y       (0,9)(8,8)      RE2/Go
+#:HA#113:E     X(.?){3,8}Y     X1234567Y       (0,9)(7,8)
+:HA#113:E      X(.?){3,8}Y     X1234567Y       (0,9)(8,8)      RE2/Go
+#:HA#114:E     X(.?){4,8}Y     X1234567Y       (0,9)(7,8)
+:HA#114:E      X(.?){4,8}Y     X1234567Y       (0,9)(8,8)      RE2/Go
+#:HA#115:E     X(.?){5,8}Y     X1234567Y       (0,9)(7,8)
+:HA#115:E      X(.?){5,8}Y     X1234567Y       (0,9)(8,8)      RE2/Go
+#:HA#116:E     X(.?){6,8}Y     X1234567Y       (0,9)(7,8)
+:HA#116:E      X(.?){6,8}Y     X1234567Y       (0,9)(8,8)      RE2/Go
+#:HA#117:E     X(.?){7,8}Y     X1234567Y       (0,9)(7,8)
+:HA#117:E      X(.?){7,8}Y     X1234567Y       (0,9)(8,8)      RE2/Go
+:HA#118:E      X(.?){8,8}Y     X1234567Y       (0,9)(8,8)
+
+# These test a fixed bug in my regex-tdfa that did not keep the expanded
+# form properly grouped, so right association did the wrong thing with
+# these ambiguous patterns (crafted just to test my code when I became
+# suspicious of my implementation).  The first subexpression should use
+# "ab" then "a" then "bcd".
+
+# OS X / FreeBSD / NetBSD badly fail many of these, with impossible
+# results like (0,6)(4,5)(6,6).
+
+:HA#260:E      (a|ab|c|bcd){0,}(d*)    ababcd  (0,1)(0,1)(1,1)
+:HA#261:E      (a|ab|c|bcd){1,}(d*)    ababcd  (0,1)(0,1)(1,1)
+:HA#262:E      (a|ab|c|bcd){2,}(d*)    ababcd  (0,6)(3,6)(6,6)
+:HA#263:E      (a|ab|c|bcd){3,}(d*)    ababcd  (0,6)(3,6)(6,6)
+:HA#264:E      (a|ab|c|bcd){4,}(d*)    ababcd  NOMATCH
+:HA#265:E      (a|ab|c|bcd){0,10}(d*)  ababcd  (0,1)(0,1)(1,1)
+:HA#266:E      (a|ab|c|bcd){1,10}(d*)  ababcd  (0,1)(0,1)(1,1)
+:HA#267:E      (a|ab|c|bcd){2,10}(d*)  ababcd  (0,6)(3,6)(6,6)
+:HA#268:E      (a|ab|c|bcd){3,10}(d*)  ababcd  (0,6)(3,6)(6,6)
+:HA#269:E      (a|ab|c|bcd){4,10}(d*)  ababcd  NOMATCH
+:HA#270:E      (a|ab|c|bcd)*(d*)       ababcd  (0,1)(0,1)(1,1)
+:HA#271:E      (a|ab|c|bcd)+(d*)       ababcd  (0,1)(0,1)(1,1)
+
+# The above worked on Linux/GLIBC but the following often fail.
+# They also trip up OS X / FreeBSD / NetBSD:
+
+#:HA#280:E     (ab|a|c|bcd){0,}(d*)    ababcd  (0,6)(3,6)(6,6)
+:HA#280:E      (ab|a|c|bcd){0,}(d*)    ababcd  (0,6)(4,5)(5,6) RE2/Go
+#:HA#281:E     (ab|a|c|bcd){1,}(d*)    ababcd  (0,6)(3,6)(6,6)
+:HA#281:E      (ab|a|c|bcd){1,}(d*)    ababcd  (0,6)(4,5)(5,6) RE2/Go
+#:HA#282:E     (ab|a|c|bcd){2,}(d*)    ababcd  (0,6)(3,6)(6,6)
+:HA#282:E      (ab|a|c|bcd){2,}(d*)    ababcd  (0,6)(4,5)(5,6) RE2/Go
+#:HA#283:E     (ab|a|c|bcd){3,}(d*)    ababcd  (0,6)(3,6)(6,6)
+:HA#283:E      (ab|a|c|bcd){3,}(d*)    ababcd  (0,6)(4,5)(5,6) RE2/Go
+:HA#284:E      (ab|a|c|bcd){4,}(d*)    ababcd  NOMATCH
+#:HA#285:E     (ab|a|c|bcd){0,10}(d*)  ababcd  (0,6)(3,6)(6,6)
+:HA#285:E      (ab|a|c|bcd){0,10}(d*)  ababcd  (0,6)(4,5)(5,6) RE2/Go
+#:HA#286:E     (ab|a|c|bcd){1,10}(d*)  ababcd  (0,6)(3,6)(6,6)
+:HA#286:E      (ab|a|c|bcd){1,10}(d*)  ababcd  (0,6)(4,5)(5,6) RE2/Go
+#:HA#287:E     (ab|a|c|bcd){2,10}(d*)  ababcd  (0,6)(3,6)(6,6)
+:HA#287:E      (ab|a|c|bcd){2,10}(d*)  ababcd  (0,6)(4,5)(5,6) RE2/Go
+#:HA#288:E     (ab|a|c|bcd){3,10}(d*)  ababcd  (0,6)(3,6)(6,6)
+:HA#288:E      (ab|a|c|bcd){3,10}(d*)  ababcd  (0,6)(4,5)(5,6) RE2/Go
+:HA#289:E      (ab|a|c|bcd){4,10}(d*)  ababcd  NOMATCH
+#:HA#290:E     (ab|a|c|bcd)*(d*)       ababcd  (0,6)(3,6)(6,6)
+:HA#290:E      (ab|a|c|bcd)*(d*)       ababcd  (0,6)(4,5)(5,6) RE2/Go
+#:HA#291:E     (ab|a|c|bcd)+(d*)       ababcd  (0,6)(3,6)(6,6)
+:HA#291:E      (ab|a|c|bcd)+(d*)       ababcd  (0,6)(4,5)(5,6) RE2/Go
diff --git a/src/libregex/unicode.rs b/src/libregex/unicode.rs
new file mode 100644 (file)
index 0000000..c263827
--- /dev/null
@@ -0,0 +1,5537 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// DO NOT EDIT. Automatically generated by 'src/etc/regex-unicode-tables'
+// on 2014-04-23 00:13:04.445491.
+
+use parse::{Class, NamedClasses};
+
+pub static UNICODE_CLASSES: NamedClasses = &[
+
+("Arabic", &[
+    ('\U00000600', '\U00000604'),
+    ('\U00000606', '\U0000060b'),
+    ('\U0000060d', '\U0000061a'),
+    ('\U0000061c', '\U0000061c'),
+    ('\U0000061e', '\U0000061e'),
+    ('\U00000620', '\U0000063f'),
+    ('\U00000641', '\U0000064a'),
+    ('\U00000656', '\U0000065f'),
+    ('\U0000066a', '\U0000066f'),
+    ('\U00000671', '\U000006dc'),
+    ('\U000006de', '\U000006ff'),
+    ('\U00000750', '\U0000077f'),
+    ('\U000008a0', '\U000008a0'),
+    ('\U000008a2', '\U000008ac'),
+    ('\U000008e4', '\U000008fe'),
+    ('\U0000fb50', '\U0000fbc1'),
+    ('\U0000fbd3', '\U0000fd3d'),
+    ('\U0000fd50', '\U0000fd8f'),
+    ('\U0000fd92', '\U0000fdc7'),
+    ('\U0000fdf0', '\U0000fdfc'),
+    ('\U0000fe70', '\U0000fe74'),
+    ('\U0000fe76', '\U0000fefc'),
+    ('\U00010e60', '\U00010e7e'),
+    ('\U0001ee00', '\U0001ee03'),
+    ('\U0001ee05', '\U0001ee1f'),
+    ('\U0001ee21', '\U0001ee22'),
+    ('\U0001ee24', '\U0001ee24'),
+    ('\U0001ee27', '\U0001ee27'),
+    ('\U0001ee29', '\U0001ee32'),
+    ('\U0001ee34', '\U0001ee37'),
+    ('\U0001ee39', '\U0001ee39'),
+    ('\U0001ee3b', '\U0001ee3b'),
+    ('\U0001ee42', '\U0001ee42'),
+    ('\U0001ee47', '\U0001ee47'),
+    ('\U0001ee49', '\U0001ee49'),
+    ('\U0001ee4b', '\U0001ee4b'),
+    ('\U0001ee4d', '\U0001ee4f'),
+    ('\U0001ee51', '\U0001ee52'),
+    ('\U0001ee54', '\U0001ee54'),
+    ('\U0001ee57', '\U0001ee57'),
+    ('\U0001ee59', '\U0001ee59'),
+    ('\U0001ee5b', '\U0001ee5b'),
+    ('\U0001ee5d', '\U0001ee5d'),
+    ('\U0001ee5f', '\U0001ee5f'),
+    ('\U0001ee61', '\U0001ee62'),
+    ('\U0001ee64', '\U0001ee64'),
+    ('\U0001ee67', '\U0001ee6a'),
+    ('\U0001ee6c', '\U0001ee72'),
+    ('\U0001ee74', '\U0001ee77'),
+    ('\U0001ee79', '\U0001ee7c'),
+    ('\U0001ee7e', '\U0001ee7e'),
+    ('\U0001ee80', '\U0001ee89'),
+    ('\U0001ee8b', '\U0001ee9b'),
+    ('\U0001eea1', '\U0001eea3'),
+    ('\U0001eea5', '\U0001eea9'),
+    ('\U0001eeab', '\U0001eebb'),
+    ('\U0001eef0', '\U0001eef1')
+    ]),
+("Armenian", &[
+    ('\U00000531', '\U00000556'),
+    ('\U00000559', '\U0000055f'),
+    ('\U00000561', '\U00000587'),
+    ('\U0000058a', '\U0000058a'),
+    ('\U0000058f', '\U0000058f'),
+    ('\U0000fb13', '\U0000fb17')
+    ]),
+("Avestan", &[
+    ('\U00010b00', '\U00010b35'),
+    ('\U00010b39', '\U00010b3f')
+    ]),
+("Balinese", &[
+    ('\U00001b00', '\U00001b4b'),
+    ('\U00001b50', '\U00001b7c')
+    ]),
+("Bamum", &[
+    ('\U0000a6a0', '\U0000a6f7'),
+    ('\U00016800', '\U00016a38')
+    ]),
+("Batak", &[
+    ('\U00001bc0', '\U00001bf3'),
+    ('\U00001bfc', '\U00001bff')
+    ]),
+("Bengali", &[
+    ('\U00000981', '\U00000983'),
+    ('\U00000985', '\U0000098c'),
+    ('\U0000098f', '\U00000990'),
+    ('\U00000993', '\U000009a8'),
+    ('\U000009aa', '\U000009b0'),
+    ('\U000009b2', '\U000009b2'),
+    ('\U000009b6', '\U000009b9'),
+    ('\U000009bc', '\U000009c4'),
+    ('\U000009c7', '\U000009c8'),
+    ('\U000009cb', '\U000009ce'),
+    ('\U000009d7', '\U000009d7'),
+    ('\U000009dc', '\U000009dd'),
+    ('\U000009df', '\U000009e3'),
+    ('\U000009e6', '\U000009fb')
+    ]),
+("Bopomofo", &[
+    ('\U000002ea', '\U000002eb'),
+    ('\U00003105', '\U0000312d'),
+    ('\U000031a0', '\U000031ba')
+    ]),
+("Brahmi", &[
+    ('\U00011000', '\U0001104d'),
+    ('\U00011052', '\U0001106f')
+    ]),
+("Braille", &[
+    ('\U00002800', '\U000028ff')
+    ]),
+("Buginese", &[
+    ('\U00001a00', '\U00001a1b'),
+    ('\U00001a1e', '\U00001a1f')
+    ]),
+("Buhid", &[
+    ('\U00001740', '\U00001753')
+    ]),
+("C", &[
+    ('\U00000000', '\U0000001f'),
+    ('\U0000007f', '\U0000009f'),
+    ('\U000000ad', '\U000000ad'),
+    ('\U00000600', '\U00000604'),
+    ('\U0000061c', '\U0000061c'),
+    ('\U000006dd', '\U000006dd'),
+    ('\U0000070f', '\U0000070f'),
+    ('\U0000180e', '\U0000180e'),
+    ('\U0000200b', '\U0000200f'),
+    ('\U0000202a', '\U0000202e'),
+    ('\U00002060', '\U00002064'),
+    ('\U00002066', '\U0000206f'),
+    ('\U0000e000', '\U0000e000'),
+    ('\U0000f8ff', '\U0000f8ff'),
+    ('\U0000feff', '\U0000feff'),
+    ('\U0000fff9', '\U0000fffb'),
+    ('\U000110bd', '\U000110bd'),
+    ('\U0001d173', '\U0001d17a'),
+    ('\U000e0001', '\U000e0001'),
+    ('\U000e0020', '\U000e007f'),
+    ('\U000f0000', '\U000f0000'),
+    ('\U000ffffd', '\U000ffffd'),
+    ('\U00100000', '\U00100000'),
+    ('\U0010fffd', '\U0010fffd')
+    ]),
+("Canadian_Aboriginal", &[
+    ('\U00001400', '\U0000167f'),
+    ('\U000018b0', '\U000018f5')
+    ]),
+("Carian", &[
+    ('\U000102a0', '\U000102d0')
+    ]),
+("Cc", &[
+    ('\U00000000', '\U0000001f'),
+    ('\U0000007f', '\U0000009f')
+    ]),
+("Cf", &[
+    ('\U000000ad', '\U000000ad'),
+    ('\U00000600', '\U00000604'),
+    ('\U0000061c', '\U0000061c'),
+    ('\U000006dd', '\U000006dd'),
+    ('\U0000070f', '\U0000070f'),
+    ('\U0000180e', '\U0000180e'),
+    ('\U0000200b', '\U0000200f'),
+    ('\U0000202a', '\U0000202e'),
+    ('\U00002060', '\U00002064'),
+    ('\U00002066', '\U0000206f'),
+    ('\U0000feff', '\U0000feff'),
+    ('\U0000fff9', '\U0000fffb'),
+    ('\U000110bd', '\U000110bd'),
+    ('\U0001d173', '\U0001d17a'),
+    ('\U000e0001', '\U000e0001'),
+    ('\U000e0020', '\U000e007f')
+    ]),
+("Chakma", &[
+    ('\U00011100', '\U00011134'),
+    ('\U00011136', '\U00011143')
+    ]),
+("Cham", &[
+    ('\U0000aa00', '\U0000aa36'),
+    ('\U0000aa40', '\U0000aa4d'),
+    ('\U0000aa50', '\U0000aa59'),
+    ('\U0000aa5c', '\U0000aa5f')
+    ]),
+("Cherokee", &[
+    ('\U000013a0', '\U000013f4')
+    ]),
+("Co", &[
+    ('\U0000e000', '\U0000e000'),
+    ('\U0000f8ff', '\U0000f8ff'),
+    ('\U000f0000', '\U000f0000'),
+    ('\U000ffffd', '\U000ffffd'),
+    ('\U00100000', '\U00100000'),
+    ('\U0010fffd', '\U0010fffd')
+    ]),
+("Common", &[
+    ('\U00000000', '\U00000040'),
+    ('\U0000005b', '\U00000060'),
+    ('\U0000007b', '\U000000a9'),
+    ('\U000000ab', '\U000000b9'),
+    ('\U000000bb', '\U000000bf'),
+    ('\U000000d7', '\U000000d7'),
+    ('\U000000f7', '\U000000f7'),
+    ('\U000002b9', '\U000002df'),
+    ('\U000002e5', '\U000002e9'),
+    ('\U000002ec', '\U000002ff'),
+    ('\U00000374', '\U00000374'),
+    ('\U0000037e', '\U0000037e'),
+    ('\U00000385', '\U00000385'),
+    ('\U00000387', '\U00000387'),
+    ('\U00000589', '\U00000589'),
+    ('\U0000060c', '\U0000060c'),
+    ('\U0000061b', '\U0000061b'),
+    ('\U0000061f', '\U0000061f'),
+    ('\U00000640', '\U00000640'),
+    ('\U00000660', '\U00000669'),
+    ('\U000006dd', '\U000006dd'),
+    ('\U00000964', '\U00000965'),
+    ('\U00000e3f', '\U00000e3f'),
+    ('\U00000fd5', '\U00000fd8'),
+    ('\U000010fb', '\U000010fb'),
+    ('\U000016eb', '\U000016ed'),
+    ('\U00001735', '\U00001736'),
+    ('\U00001802', '\U00001803'),
+    ('\U00001805', '\U00001805'),
+    ('\U00001cd3', '\U00001cd3'),
+    ('\U00001ce1', '\U00001ce1'),
+    ('\U00001ce9', '\U00001cec'),
+    ('\U00001cee', '\U00001cf3'),
+    ('\U00001cf5', '\U00001cf6'),
+    ('\U00002000', '\U0000200b'),
+    ('\U0000200e', '\U00002064'),
+    ('\U00002066', '\U00002070'),
+    ('\U00002074', '\U0000207e'),
+    ('\U00002080', '\U0000208e'),
+    ('\U000020a0', '\U000020ba'),
+    ('\U00002100', '\U00002125'),
+    ('\U00002127', '\U00002129'),
+    ('\U0000212c', '\U00002131'),
+    ('\U00002133', '\U0000214d'),
+    ('\U0000214f', '\U0000215f'),
+    ('\U00002189', '\U00002189'),
+    ('\U00002190', '\U000023f3'),
+    ('\U00002400', '\U00002426'),
+    ('\U00002440', '\U0000244a'),
+    ('\U00002460', '\U000026ff'),
+    ('\U00002701', '\U000027ff'),
+    ('\U00002900', '\U00002b4c'),
+    ('\U00002b50', '\U00002b59'),
+    ('\U00002e00', '\U00002e3b'),
+    ('\U00002ff0', '\U00002ffb'),
+    ('\U00003000', '\U00003004'),
+    ('\U00003006', '\U00003006'),
+    ('\U00003008', '\U00003020'),
+    ('\U00003030', '\U00003037'),
+    ('\U0000303c', '\U0000303f'),
+    ('\U0000309b', '\U0000309c'),
+    ('\U000030a0', '\U000030a0'),
+    ('\U000030fb', '\U000030fc'),
+    ('\U00003190', '\U0000319f'),
+    ('\U000031c0', '\U000031e3'),
+    ('\U00003220', '\U0000325f'),
+    ('\U0000327f', '\U000032cf'),
+    ('\U00003358', '\U000033ff'),
+    ('\U00004dc0', '\U00004dff'),
+    ('\U0000a700', '\U0000a721'),
+    ('\U0000a788', '\U0000a78a'),
+    ('\U0000a830', '\U0000a839'),
+    ('\U0000a9cf', '\U0000a9cf'),
+    ('\U0000fd3e', '\U0000fd3f'),
+    ('\U0000fdfd', '\U0000fdfd'),
+    ('\U0000fe10', '\U0000fe19'),
+    ('\U0000fe30', '\U0000fe52'),
+    ('\U0000fe54', '\U0000fe66'),
+    ('\U0000fe68', '\U0000fe6b'),
+    ('\U0000feff', '\U0000feff'),
+    ('\U0000ff01', '\U0000ff20'),
+    ('\U0000ff3b', '\U0000ff40'),
+    ('\U0000ff5b', '\U0000ff65'),
+    ('\U0000ff70', '\U0000ff70'),
+    ('\U0000ff9e', '\U0000ff9f'),
+    ('\U0000ffe0', '\U0000ffe6'),
+    ('\U0000ffe8', '\U0000ffee'),
+    ('\U0000fff9', '\U0000fffd'),
+    ('\U00010100', '\U00010102'),
+    ('\U00010107', '\U00010133'),
+    ('\U00010137', '\U0001013f'),
+    ('\U00010190', '\U0001019b'),
+    ('\U000101d0', '\U000101fc'),
+    ('\U0001d000', '\U0001d0f5'),
+    ('\U0001d100', '\U0001d126'),
+    ('\U0001d129', '\U0001d166'),
+    ('\U0001d16a', '\U0001d17a'),
+    ('\U0001d183', '\U0001d184'),
+    ('\U0001d18c', '\U0001d1a9'),
+    ('\U0001d1ae', '\U0001d1dd'),
+    ('\U0001d300', '\U0001d356'),
+    ('\U0001d360', '\U0001d371'),
+    ('\U0001d400', '\U0001d454'),
+    ('\U0001d456', '\U0001d49c'),
+    ('\U0001d49e', '\U0001d49f'),
+    ('\U0001d4a2', '\U0001d4a2'),
+    ('\U0001d4a5', '\U0001d4a6'),
+    ('\U0001d4a9', '\U0001d4ac'),
+    ('\U0001d4ae', '\U0001d4b9'),
+    ('\U0001d4bb', '\U0001d4bb'),
+    ('\U0001d4bd', '\U0001d4c3'),
+    ('\U0001d4c5', '\U0001d505'),
+    ('\U0001d507', '\U0001d50a'),
+    ('\U0001d50d', '\U0001d514'),
+    ('\U0001d516', '\U0001d51c'),
+    ('\U0001d51e', '\U0001d539'),
+    ('\U0001d53b', '\U0001d53e'),
+    ('\U0001d540', '\U0001d544'),
+    ('\U0001d546', '\U0001d546'),
+    ('\U0001d54a', '\U0001d550'),
+    ('\U0001d552', '\U0001d6a5'),
+    ('\U0001d6a8', '\U0001d7cb'),
+    ('\U0001d7ce', '\U0001d7ff'),
+    ('\U0001f000', '\U0001f02b'),
+    ('\U0001f030', '\U0001f093'),
+    ('\U0001f0a0', '\U0001f0ae'),
+    ('\U0001f0b1', '\U0001f0be'),
+    ('\U0001f0c1', '\U0001f0cf'),
+    ('\U0001f0d1', '\U0001f0df'),
+    ('\U0001f100', '\U0001f10a'),
+    ('\U0001f110', '\U0001f12e'),
+    ('\U0001f130', '\U0001f16b'),
+    ('\U0001f170', '\U0001f19a'),
+    ('\U0001f1e6', '\U0001f1ff'),
+    ('\U0001f201', '\U0001f202'),
+    ('\U0001f210', '\U0001f23a'),
+    ('\U0001f240', '\U0001f248'),
+    ('\U0001f250', '\U0001f251'),
+    ('\U0001f300', '\U0001f320'),
+    ('\U0001f330', '\U0001f335'),
+    ('\U0001f337', '\U0001f37c'),
+    ('\U0001f380', '\U0001f393'),
+    ('\U0001f3a0', '\U0001f3c4'),
+    ('\U0001f3c6', '\U0001f3ca'),
+    ('\U0001f3e0', '\U0001f3f0'),
+    ('\U0001f400', '\U0001f43e'),
+    ('\U0001f440', '\U0001f440'),
+    ('\U0001f442', '\U0001f4f7'),
+    ('\U0001f4f9', '\U0001f4fc'),
+    ('\U0001f500', '\U0001f53d'),
+    ('\U0001f540', '\U0001f543'),
+    ('\U0001f550', '\U0001f567'),
+    ('\U0001f5fb', '\U0001f640'),
+    ('\U0001f645', '\U0001f64f'),
+    ('\U0001f680', '\U0001f6c5'),
+    ('\U0001f700', '\U0001f773'),
+    ('\U000e0001', '\U000e0001'),
+    ('\U000e0020', '\U000e007f')
+    ]),
+("Coptic", &[
+    ('\U000003e2', '\U000003ef'),
+    ('\U00002c80', '\U00002cf3'),
+    ('\U00002cf9', '\U00002cff')
+    ]),
+("Cuneiform", &[
+    ('\U00012000', '\U0001236e'),
+    ('\U00012400', '\U00012462'),
+    ('\U00012470', '\U00012473')
+    ]),
+("Cypriot", &[
+    ('\U00010800', '\U00010805'),
+    ('\U00010808', '\U00010808'),
+    ('\U0001080a', '\U00010835'),
+    ('\U00010837', '\U00010838'),
+    ('\U0001083c', '\U0001083c'),
+    ('\U0001083f', '\U0001083f')
+    ]),
+("Cyrillic", &[
+    ('\U00000400', '\U00000484'),
+    ('\U00000487', '\U00000527'),
+    ('\U00001d2b', '\U00001d2b'),
+    ('\U00001d78', '\U00001d78'),
+    ('\U00002de0', '\U00002dff'),
+    ('\U0000a640', '\U0000a697'),
+    ('\U0000a69f', '\U0000a69f')
+    ]),
+("Deseret", &[
+    ('\U00010400', '\U0001044f')
+    ]),
+("Devanagari", &[
+    ('\U00000900', '\U00000950'),
+    ('\U00000953', '\U00000963'),
+    ('\U00000966', '\U00000977'),
+    ('\U00000979', '\U0000097f'),
+    ('\U0000a8e0', '\U0000a8fb')
+    ]),
+("Egyptian_Hieroglyphs", &[
+    ('\U00013000', '\U0001342e')
+    ]),
+("Ethiopic", &[
+    ('\U00001200', '\U00001248'),
+    ('\U0000124a', '\U0000124d'),
+    ('\U00001250', '\U00001256'),
+    ('\U00001258', '\U00001258'),
+    ('\U0000125a', '\U0000125d'),
+    ('\U00001260', '\U00001288'),
+    ('\U0000128a', '\U0000128d'),
+    ('\U00001290', '\U000012b0'),
+    ('\U000012b2', '\U000012b5'),
+    ('\U000012b8', '\U000012be'),
+    ('\U000012c0', '\U000012c0'),
+    ('\U000012c2', '\U000012c5'),
+    ('\U000012c8', '\U000012d6'),
+    ('\U000012d8', '\U00001310'),
+    ('\U00001312', '\U00001315'),
+    ('\U00001318', '\U0000135a'),
+    ('\U0000135d', '\U0000137c'),
+    ('\U00001380', '\U00001399'),
+    ('\U00002d80', '\U00002d96'),
+    ('\U00002da0', '\U00002da6'),
+    ('\U00002da8', '\U00002dae'),
+    ('\U00002db0', '\U00002db6'),
+    ('\U00002db8', '\U00002dbe'),
+    ('\U00002dc0', '\U00002dc6'),
+    ('\U00002dc8', '\U00002dce'),
+    ('\U00002dd0', '\U00002dd6'),
+    ('\U00002dd8', '\U00002dde'),
+    ('\U0000ab01', '\U0000ab06'),
+    ('\U0000ab09', '\U0000ab0e'),
+    ('\U0000ab11', '\U0000ab16'),
+    ('\U0000ab20', '\U0000ab26'),
+    ('\U0000ab28', '\U0000ab2e')
+    ]),
+("Georgian", &[
+    ('\U000010a0', '\U000010c5'),
+    ('\U000010c7', '\U000010c7'),
+    ('\U000010cd', '\U000010cd'),
+    ('\U000010d0', '\U000010fa'),
+    ('\U000010fc', '\U000010ff'),
+    ('\U00002d00', '\U00002d25'),
+    ('\U00002d27', '\U00002d27'),
+    ('\U00002d2d', '\U00002d2d')
+    ]),
+("Glagolitic", &[
+    ('\U00002c00', '\U00002c2e'),
+    ('\U00002c30', '\U00002c5e')
+    ]),
+("Gothic", &[
+    ('\U00010330', '\U0001034a')
+    ]),
+("Greek", &[
+    ('\U00000370', '\U00000373'),
+    ('\U00000375', '\U00000377'),
+    ('\U0000037a', '\U0000037d'),
+    ('\U00000384', '\U00000384'),
+    ('\U00000386', '\U00000386'),
+    ('\U00000388', '\U0000038a'),
+    ('\U0000038c', '\U0000038c'),
+    ('\U0000038e', '\U000003a1'),
+    ('\U000003a3', '\U000003e1'),
+    ('\U000003f0', '\U000003ff'),
+    ('\U00001d26', '\U00001d2a'),
+    ('\U00001d5d', '\U00001d61'),
+    ('\U00001d66', '\U00001d6a'),
+    ('\U00001dbf', '\U00001dbf'),
+    ('\U00001f00', '\U00001f15'),
+    ('\U00001f18', '\U00001f1d'),
+    ('\U00001f20', '\U00001f45'),
+    ('\U00001f48', '\U00001f4d'),
+    ('\U00001f50', '\U00001f57'),
+    ('\U00001f59', '\U00001f59'),
+    ('\U00001f5b', '\U00001f5b'),
+    ('\U00001f5d', '\U00001f5d'),
+    ('\U00001f5f', '\U00001f7d'),
+    ('\U00001f80', '\U00001fb4'),
+    ('\U00001fb6', '\U00001fc4'),
+    ('\U00001fc6', '\U00001fd3'),
+    ('\U00001fd6', '\U00001fdb'),
+    ('\U00001fdd', '\U00001fef'),
+    ('\U00001ff2', '\U00001ff4'),
+    ('\U00001ff6', '\U00001ffe'),
+    ('\U00002126', '\U00002126'),
+    ('\U00010140', '\U0001018a'),
+    ('\U0001d200', '\U0001d245')
+    ]),
+("Gujarati", &[
+    ('\U00000a81', '\U00000a83'),
+    ('\U00000a85', '\U00000a8d'),
+    ('\U00000a8f', '\U00000a91'),
+    ('\U00000a93', '\U00000aa8'),
+    ('\U00000aaa', '\U00000ab0'),
+    ('\U00000ab2', '\U00000ab3'),
+    ('\U00000ab5', '\U00000ab9'),
+    ('\U00000abc', '\U00000ac5'),
+    ('\U00000ac7', '\U00000ac9'),
+    ('\U00000acb', '\U00000acd'),
+    ('\U00000ad0', '\U00000ad0'),
+    ('\U00000ae0', '\U00000ae3'),
+    ('\U00000ae6', '\U00000af1')
+    ]),
+("Gurmukhi", &[
+    ('\U00000a01', '\U00000a03'),
+    ('\U00000a05', '\U00000a0a'),
+    ('\U00000a0f', '\U00000a10'),
+    ('\U00000a13', '\U00000a28'),
+    ('\U00000a2a', '\U00000a30'),
+    ('\U00000a32', '\U00000a33'),
+    ('\U00000a35', '\U00000a36'),
+    ('\U00000a38', '\U00000a39'),
+    ('\U00000a3c', '\U00000a3c'),
+    ('\U00000a3e', '\U00000a42'),
+    ('\U00000a47', '\U00000a48'),
+    ('\U00000a4b', '\U00000a4d'),
+    ('\U00000a51', '\U00000a51'),
+    ('\U00000a59', '\U00000a5c'),
+    ('\U00000a5e', '\U00000a5e'),
+    ('\U00000a66', '\U00000a75')
+    ]),
+("Han", &[
+    ('\U00002e80', '\U00002e99'),
+    ('\U00002e9b', '\U00002ef3'),
+    ('\U00002f00', '\U00002fd5'),
+    ('\U00003005', '\U00003005'),
+    ('\U00003007', '\U00003007'),
+    ('\U00003021', '\U00003029'),
+    ('\U00003038', '\U0000303b'),
+    ('\U00003400', '\U00004db5'),
+    ('\U00004e00', '\U00009fcc'),
+    ('\U0000f900', '\U0000fa6d'),
+    ('\U0000fa70', '\U0000fad9'),
+    ('\U00020000', '\U0002a6d6'),
+    ('\U0002a700', '\U0002b734'),
+    ('\U0002b740', '\U0002b81d'),
+    ('\U0002f800', '\U0002fa1d')
+    ]),
+("Hangul", &[
+    ('\U00001100', '\U000011ff'),
+    ('\U0000302e', '\U0000302f'),
+    ('\U00003131', '\U0000318e'),
+    ('\U00003200', '\U0000321e'),
+    ('\U00003260', '\U0000327e'),
+    ('\U0000a960', '\U0000a97c'),
+    ('\U0000ac00', '\U0000d7a3'),
+    ('\U0000d7b0', '\U0000d7c6'),
+    ('\U0000d7cb', '\U0000d7fb'),
+    ('\U0000ffa0', '\U0000ffbe'),
+    ('\U0000ffc2', '\U0000ffc7'),
+    ('\U0000ffca', '\U0000ffcf'),
+    ('\U0000ffd2', '\U0000ffd7'),
+    ('\U0000ffda', '\U0000ffdc')
+    ]),
+("Hanunoo", &[
+    ('\U00001720', '\U00001734')
+    ]),
+("Hebrew", &[
+    ('\U00000591', '\U000005c7'),
+    ('\U000005d0', '\U000005ea'),
+    ('\U000005f0', '\U000005f4'),
+    ('\U0000fb1d', '\U0000fb36'),
+    ('\U0000fb38', '\U0000fb3c'),
+    ('\U0000fb3e', '\U0000fb3e'),
+    ('\U0000fb40', '\U0000fb41'),
+    ('\U0000fb43', '\U0000fb44'),
+    ('\U0000fb46', '\U0000fb4f')
+    ]),
+("Hiragana", &[
+    ('\U00003041', '\U00003096'),
+    ('\U0000309d', '\U0000309f'),
+    ('\U0001b001', '\U0001b001'),
+    ('\U0001f200', '\U0001f200')
+    ]),
+("Imperial_Aramaic", &[
+    ('\U00010840', '\U00010855'),
+    ('\U00010857', '\U0001085f')
+    ]),
+("Inherited", &[
+    ('\U00000300', '\U0000036f'),
+    ('\U00000485', '\U00000486'),
+    ('\U0000064b', '\U00000655'),
+    ('\U00000670', '\U00000670'),
+    ('\U00000951', '\U00000952'),
+    ('\U00001cd0', '\U00001cd2'),
+    ('\U00001cd4', '\U00001ce0'),
+    ('\U00001ce2', '\U00001ce8'),
+    ('\U00001ced', '\U00001ced'),
+    ('\U00001cf4', '\U00001cf4'),
+    ('\U00001dc0', '\U00001de6'),
+    ('\U00001dfc', '\U00001dff'),
+    ('\U0000200c', '\U0000200d'),
+    ('\U000020d0', '\U000020f0'),
+    ('\U0000302a', '\U0000302d'),
+    ('\U00003099', '\U0000309a'),
+    ('\U0000fe00', '\U0000fe0f'),
+    ('\U0000fe20', '\U0000fe26'),
+    ('\U000101fd', '\U000101fd'),
+    ('\U0001d167', '\U0001d169'),
+    ('\U0001d17b', '\U0001d182'),
+    ('\U0001d185', '\U0001d18b'),
+    ('\U0001d1aa', '\U0001d1ad'),
+    ('\U000e0100', '\U000e01ef')
+    ]),
+("Inscriptional_Pahlavi", &[
+    ('\U00010b60', '\U00010b72'),
+    ('\U00010b78', '\U00010b7f')
+    ]),
+("Inscriptional_Parthian", &[
+    ('\U00010b40', '\U00010b55'),
+    ('\U00010b58', '\U00010b5f')
+    ]),
+("Javanese", &[
+    ('\U0000a980', '\U0000a9cd'),
+    ('\U0000a9d0', '\U0000a9d9'),
+    ('\U0000a9de', '\U0000a9df')
+    ]),
+("Kaithi", &[
+    ('\U00011080', '\U000110c1')
+    ]),
+("Kannada", &[
+    ('\U00000c82', '\U00000c83'),
+    ('\U00000c85', '\U00000c8c'),
+    ('\U00000c8e', '\U00000c90'),
+    ('\U00000c92', '\U00000ca8'),
+    ('\U00000caa', '\U00000cb3'),
+    ('\U00000cb5', '\U00000cb9'),
+    ('\U00000cbc', '\U00000cc4'),
+    ('\U00000cc6', '\U00000cc8'),
+    ('\U00000cca', '\U00000ccd'),
+    ('\U00000cd5', '\U00000cd6'),
+    ('\U00000cde', '\U00000cde'),
+    ('\U00000ce0', '\U00000ce3'),
+    ('\U00000ce6', '\U00000cef'),
+    ('\U00000cf1', '\U00000cf2')
+    ]),
+("Katakana", &[
+    ('\U000030a1', '\U000030fa'),
+    ('\U000030fd', '\U000030ff'),
+    ('\U000031f0', '\U000031ff'),
+    ('\U000032d0', '\U000032fe'),
+    ('\U00003300', '\U00003357'),
+    ('\U0000ff66', '\U0000ff6f'),
+    ('\U0000ff71', '\U0000ff9d'),
+    ('\U0001b000', '\U0001b000')
+    ]),
+("Kayah_Li", &[
+    ('\U0000a900', '\U0000a92f')
+    ]),
+("Kharoshthi", &[
+    ('\U00010a00', '\U00010a03'),
+    ('\U00010a05', '\U00010a06'),
+    ('\U00010a0c', '\U00010a13'),
+    ('\U00010a15', '\U00010a17'),
+    ('\U00010a19', '\U00010a33'),
+    ('\U00010a38', '\U00010a3a'),
+    ('\U00010a3f', '\U00010a47'),
+    ('\U00010a50', '\U00010a58')
+    ]),
+("Khmer", &[
+    ('\U00001780', '\U000017dd'),
+    ('\U000017e0', '\U000017e9'),
+    ('\U000017f0', '\U000017f9'),
+    ('\U000019e0', '\U000019ff')
+    ]),
+("L", &[
+    ('\U00000041', '\U0000005a'),
+    ('\U00000061', '\U0000007a'),
+    ('\U000000aa', '\U000000aa'),
+    ('\U000000b5', '\U000000b5'),
+    ('\U000000ba', '\U000000ba'),
+    ('\U000000c0', '\U000000d6'),
+    ('\U000000d8', '\U000000f6'),
+    ('\U000000f8', '\U000002c1'),
+    ('\U000002c6', '\U000002d1'),
+    ('\U000002e0', '\U000002e4'),
+    ('\U000002ec', '\U000002ec'),
+    ('\U000002ee', '\U000002ee'),
+    ('\U00000370', '\U00000374'),
+    ('\U00000376', '\U00000377'),
+    ('\U0000037a', '\U0000037d'),
+    ('\U00000386', '\U00000386'),
+    ('\U00000388', '\U0000038a'),
+    ('\U0000038c', '\U0000038c'),
+    ('\U0000038e', '\U000003a1'),
+    ('\U000003a3', '\U000003f5'),
+    ('\U000003f7', '\U00000481'),
+    ('\U0000048a', '\U00000527'),
+    ('\U00000531', '\U00000556'),
+    ('\U00000559', '\U00000559'),
+    ('\U00000561', '\U00000587'),
+    ('\U000005d0', '\U000005ea'),
+    ('\U000005f0', '\U000005f2'),
+    ('\U00000620', '\U0000064a'),
+    ('\U0000066e', '\U0000066f'),
+    ('\U00000671', '\U000006d3'),
+    ('\U000006d5', '\U000006d5'),
+    ('\U000006e5', '\U000006e6'),
+    ('\U000006ee', '\U000006ef'),
+    ('\U000006fa', '\U000006fc'),
+    ('\U000006ff', '\U000006ff'),
+    ('\U00000710', '\U00000710'),
+    ('\U00000712', '\U0000072f'),
+    ('\U0000074d', '\U000007a5'),
+    ('\U000007b1', '\U000007b1'),
+    ('\U000007ca', '\U000007ea'),
+    ('\U000007f4', '\U000007f5'),
+    ('\U000007fa', '\U000007fa'),
+    ('\U00000800', '\U00000815'),
+    ('\U0000081a', '\U0000081a'),
+    ('\U00000824', '\U00000824'),
+    ('\U00000828', '\U00000828'),
+    ('\U00000840', '\U00000858'),
+    ('\U000008a0', '\U000008a0'),
+    ('\U000008a2', '\U000008ac'),
+    ('\U00000904', '\U00000939'),
+    ('\U0000093d', '\U0000093d'),
+    ('\U00000950', '\U00000950'),
+    ('\U00000958', '\U00000961'),
+    ('\U00000971', '\U00000977'),
+    ('\U00000979', '\U0000097f'),
+    ('\U00000985', '\U0000098c'),
+    ('\U0000098f', '\U00000990'),
+    ('\U00000993', '\U000009a8'),
+    ('\U000009aa', '\U000009b0'),
+    ('\U000009b2', '\U000009b2'),
+    ('\U000009b6', '\U000009b9'),
+    ('\U000009bd', '\U000009bd'),
+    ('\U000009ce', '\U000009ce'),
+    ('\U000009dc', '\U000009dd'),
+    ('\U000009df', '\U000009e1'),
+    ('\U000009f0', '\U000009f1'),
+    ('\U00000a05', '\U00000a0a'),
+    ('\U00000a0f', '\U00000a10'),
+    ('\U00000a13', '\U00000a28'),
+    ('\U00000a2a', '\U00000a30'),
+    ('\U00000a32', '\U00000a33'),
+    ('\U00000a35', '\U00000a36'),
+    ('\U00000a38', '\U00000a39'),
+    ('\U00000a59', '\U00000a5c'),
+    ('\U00000a5e', '\U00000a5e'),
+    ('\U00000a72', '\U00000a74'),
+    ('\U00000a85', '\U00000a8d'),
+    ('\U00000a8f', '\U00000a91'),
+    ('\U00000a93', '\U00000aa8'),
+    ('\U00000aaa', '\U00000ab0'),
+    ('\U00000ab2', '\U00000ab3'),
+    ('\U00000ab5', '\U00000ab9'),
+    ('\U00000abd', '\U00000abd'),
+    ('\U00000ad0', '\U00000ad0'),
+    ('\U00000ae0', '\U00000ae1'),
+    ('\U00000b05', '\U00000b0c'),
+    ('\U00000b0f', '\U00000b10'),
+    ('\U00000b13', '\U00000b28'),
+    ('\U00000b2a', '\U00000b30'),
+    ('\U00000b32', '\U00000b33'),
+    ('\U00000b35', '\U00000b39'),
+    ('\U00000b3d', '\U00000b3d'),
+    ('\U00000b5c', '\U00000b5d'),
+    ('\U00000b5f', '\U00000b61'),
+    ('\U00000b71', '\U00000b71'),
+    ('\U00000b83', '\U00000b83'),
+    ('\U00000b85', '\U00000b8a'),
+    ('\U00000b8e', '\U00000b90'),
+    ('\U00000b92', '\U00000b95'),
+    ('\U00000b99', '\U00000b9a'),
+    ('\U00000b9c', '\U00000b9c'),
+    ('\U00000b9e', '\U00000b9f'),
+    ('\U00000ba3', '\U00000ba4'),
+    ('\U00000ba8', '\U00000baa'),
+    ('\U00000bae', '\U00000bb9'),
+    ('\U00000bd0', '\U00000bd0'),
+    ('\U00000c05', '\U00000c0c'),
+    ('\U00000c0e', '\U00000c10'),
+    ('\U00000c12', '\U00000c28'),
+    ('\U00000c2a', '\U00000c33'),
+    ('\U00000c35', '\U00000c39'),
+    ('\U00000c3d', '\U00000c3d'),
+    ('\U00000c58', '\U00000c59'),
+    ('\U00000c60', '\U00000c61'),
+    ('\U00000c85', '\U00000c8c'),
+    ('\U00000c8e', '\U00000c90'),
+    ('\U00000c92', '\U00000ca8'),
+    ('\U00000caa', '\U00000cb3'),
+    ('\U00000cb5', '\U00000cb9'),
+    ('\U00000cbd', '\U00000cbd'),
+    ('\U00000cde', '\U00000cde'),
+    ('\U00000ce0', '\U00000ce1'),
+    ('\U00000cf1', '\U00000cf2'),
+    ('\U00000d05', '\U00000d0c'),
+    ('\U00000d0e', '\U00000d10'),
+    ('\U00000d12', '\U00000d3a'),
+    ('\U00000d3d', '\U00000d3d'),
+    ('\U00000d4e', '\U00000d4e'),
+    ('\U00000d60', '\U00000d61'),
+    ('\U00000d7a', '\U00000d7f'),
+    ('\U00000d85', '\U00000d96'),
+    ('\U00000d9a', '\U00000db1'),
+    ('\U00000db3', '\U00000dbb'),
+    ('\U00000dbd', '\U00000dbd'),
+    ('\U00000dc0', '\U00000dc6'),
+    ('\U00000e01', '\U00000e30'),
+    ('\U00000e32', '\U00000e33'),
+    ('\U00000e40', '\U00000e46'),
+    ('\U00000e81', '\U00000e82'),
+    ('\U00000e84', '\U00000e84'),
+    ('\U00000e87', '\U00000e88'),
+    ('\U00000e8a', '\U00000e8a'),
+    ('\U00000e8d', '\U00000e8d'),
+    ('\U00000e94', '\U00000e97'),
+    ('\U00000e99', '\U00000e9f'),
+    ('\U00000ea1', '\U00000ea3'),
+    ('\U00000ea5', '\U00000ea5'),
+    ('\U00000ea7', '\U00000ea7'),
+    ('\U00000eaa', '\U00000eab'),
+    ('\U00000ead', '\U00000eb0'),
+    ('\U00000eb2', '\U00000eb3'),
+    ('\U00000ebd', '\U00000ebd'),
+    ('\U00000ec0', '\U00000ec4'),
+    ('\U00000ec6', '\U00000ec6'),
+    ('\U00000edc', '\U00000edf'),
+    ('\U00000f00', '\U00000f00'),
+    ('\U00000f40', '\U00000f47'),
+    ('\U00000f49', '\U00000f6c'),
+    ('\U00000f88', '\U00000f8c'),
+    ('\U00001000', '\U0000102a'),
+    ('\U0000103f', '\U0000103f'),
+    ('\U00001050', '\U00001055'),
+    ('\U0000105a', '\U0000105d'),
+    ('\U00001061', '\U00001061'),
+    ('\U00001065', '\U00001066'),
+    ('\U0000106e', '\U00001070'),
+    ('\U00001075', '\U00001081'),
+    ('\U0000108e', '\U0000108e'),
+    ('\U000010a0', '\U000010c5'),
+    ('\U000010c7', '\U000010c7'),
+    ('\U000010cd', '\U000010cd'),
+    ('\U000010d0', '\U000010fa'),
+    ('\U000010fc', '\U00001248'),
+    ('\U0000124a', '\U0000124d'),
+    ('\U00001250', '\U00001256'),
+    ('\U00001258', '\U00001258'),
+    ('\U0000125a', '\U0000125d'),
+    ('\U00001260', '\U00001288'),
+    ('\U0000128a', '\U0000128d'),
+    ('\U00001290', '\U000012b0'),
+    ('\U000012b2', '\U000012b5'),
+    ('\U000012b8', '\U000012be'),
+    ('\U000012c0', '\U000012c0'),
+    ('\U000012c2', '\U000012c5'),
+    ('\U000012c8', '\U000012d6'),
+    ('\U000012d8', '\U00001310'),
+    ('\U00001312', '\U00001315'),
+    ('\U00001318', '\U0000135a'),
+    ('\U00001380', '\U0000138f'),
+    ('\U000013a0', '\U000013f4'),
+    ('\U00001401', '\U0000166c'),
+    ('\U0000166f', '\U0000167f'),
+    ('\U00001681', '\U0000169a'),
+    ('\U000016a0', '\U000016ea'),
+    ('\U00001700', '\U0000170c'),
+    ('\U0000170e', '\U00001711'),
+    ('\U00001720', '\U00001731'),
+    ('\U00001740', '\U00001751'),
+    ('\U00001760', '\U0000176c'),
+    ('\U0000176e', '\U00001770'),
+    ('\U00001780', '\U000017b3'),
+    ('\U000017d7', '\U000017d7'),
+    ('\U000017dc', '\U000017dc'),
+    ('\U00001820', '\U00001877'),
+    ('\U00001880', '\U000018a8'),
+    ('\U000018aa', '\U000018aa'),
+    ('\U000018b0', '\U000018f5'),
+    ('\U00001900', '\U0000191c'),
+    ('\U00001950', '\U0000196d'),
+    ('\U00001970', '\U00001974'),
+    ('\U00001980', '\U000019ab'),
+    ('\U000019c1', '\U000019c7'),
+    ('\U00001a00', '\U00001a16'),
+    ('\U00001a20', '\U00001a54'),
+    ('\U00001aa7', '\U00001aa7'),
+    ('\U00001b05', '\U00001b33'),
+    ('\U00001b45', '\U00001b4b'),
+    ('\U00001b83', '\U00001ba0'),
+    ('\U00001bae', '\U00001baf'),
+    ('\U00001bba', '\U00001be5'),
+    ('\U00001c00', '\U00001c23'),
+    ('\U00001c4d', '\U00001c4f'),
+    ('\U00001c5a', '\U00001c7d'),
+    ('\U00001ce9', '\U00001cec'),
+    ('\U00001cee', '\U00001cf1'),
+    ('\U00001cf5', '\U00001cf6'),
+    ('\U00001d00', '\U00001dbf'),
+    ('\U00001e00', '\U00001f15'),
+    ('\U00001f18', '\U00001f1d'),
+    ('\U00001f20', '\U00001f45'),
+    ('\U00001f48', '\U00001f4d'),
+    ('\U00001f50', '\U00001f57'),
+    ('\U00001f59', '\U00001f59'),
+    ('\U00001f5b', '\U00001f5b'),
+    ('\U00001f5d', '\U00001f5d'),
+    ('\U00001f5f', '\U00001f7d'),
+    ('\U00001f80', '\U00001fb4'),
+    ('\U00001fb6', '\U00001fbc'),
+    ('\U00001fbe', '\U00001fbe'),
+    ('\U00001fc2', '\U00001fc4'),
+    ('\U00001fc6', '\U00001fcc'),
+    ('\U00001fd0', '\U00001fd3'),
+    ('\U00001fd6', '\U00001fdb'),
+    ('\U00001fe0', '\U00001fec'),
+    ('\U00001ff2', '\U00001ff4'),
+    ('\U00001ff6', '\U00001ffc'),
+    ('\U00002071', '\U00002071'),
+    ('\U0000207f', '\U0000207f'),
+    ('\U00002090', '\U0000209c'),
+    ('\U00002102', '\U00002102'),
+    ('\U00002107', '\U00002107'),
+    ('\U0000210a', '\U00002113'),
+    ('\U00002115', '\U00002115'),
+    ('\U00002119', '\U0000211d'),
+    ('\U00002124', '\U00002124'),
+    ('\U00002126', '\U00002126'),
+    ('\U00002128', '\U00002128'),
+    ('\U0000212a', '\U0000212d'),
+    ('\U0000212f', '\U00002139'),
+    ('\U0000213c', '\U0000213f'),
+    ('\U00002145', '\U00002149'),
+    ('\U0000214e', '\U0000214e'),
+    ('\U00002183', '\U00002184'),
+    ('\U00002c00', '\U00002c2e'),
+    ('\U00002c30', '\U00002c5e'),
+    ('\U00002c60', '\U00002ce4'),
+    ('\U00002ceb', '\U00002cee'),
+    ('\U00002cf2', '\U00002cf3'),
+    ('\U00002d00', '\U00002d25'),
+    ('\U00002d27', '\U00002d27'),
+    ('\U00002d2d', '\U00002d2d'),
+    ('\U00002d30', '\U00002d67'),
+    ('\U00002d6f', '\U00002d6f'),
+    ('\U00002d80', '\U00002d96'),
+    ('\U00002da0', '\U00002da6'),
+    ('\U00002da8', '\U00002dae'),
+    ('\U00002db0', '\U00002db6'),
+    ('\U00002db8', '\U00002dbe'),
+    ('\U00002dc0', '\U00002dc6'),
+    ('\U00002dc8', '\U00002dce'),
+    ('\U00002dd0', '\U00002dd6'),
+    ('\U00002dd8', '\U00002dde'),
+    ('\U00002e2f', '\U00002e2f'),
+    ('\U00003005', '\U00003006'),
+    ('\U00003031', '\U00003035'),
+    ('\U0000303b', '\U0000303c'),
+    ('\U00003041', '\U00003096'),
+    ('\U0000309d', '\U0000309f'),
+    ('\U000030a1', '\U000030fa'),
+    ('\U000030fc', '\U000030ff'),
+    ('\U00003105', '\U0000312d'),
+    ('\U00003131', '\U0000318e'),
+    ('\U000031a0', '\U000031ba'),
+    ('\U000031f0', '\U000031ff'),
+    ('\U00003400', '\U00003400'),
+    ('\U00004db5', '\U00004db5'),
+    ('\U00004e00', '\U00004e00'),
+    ('\U00009fcc', '\U00009fcc'),
+    ('\U0000a000', '\U0000a48c'),
+    ('\U0000a4d0', '\U0000a4fd'),
+    ('\U0000a500', '\U0000a60c'),
+    ('\U0000a610', '\U0000a61f'),
+    ('\U0000a62a', '\U0000a62b'),
+    ('\U0000a640', '\U0000a66e'),
+    ('\U0000a67f', '\U0000a697'),
+    ('\U0000a6a0', '\U0000a6e5'),
+    ('\U0000a717', '\U0000a71f'),
+    ('\U0000a722', '\U0000a788'),
+    ('\U0000a78b', '\U0000a78e'),
+    ('\U0000a790', '\U0000a793'),
+    ('\U0000a7a0', '\U0000a7aa'),
+    ('\U0000a7f8', '\U0000a801'),
+    ('\U0000a803', '\U0000a805'),
+    ('\U0000a807', '\U0000a80a'),
+    ('\U0000a80c', '\U0000a822'),
+    ('\U0000a840', '\U0000a873'),
+    ('\U0000a882', '\U0000a8b3'),
+    ('\U0000a8f2', '\U0000a8f7'),
+    ('\U0000a8fb', '\U0000a8fb'),
+    ('\U0000a90a', '\U0000a925'),
+    ('\U0000a930', '\U0000a946'),
+    ('\U0000a960', '\U0000a97c'),
+    ('\U0000a984', '\U0000a9b2'),
+    ('\U0000a9cf', '\U0000a9cf'),
+    ('\U0000aa00', '\U0000aa28'),
+    ('\U0000aa40', '\U0000aa42'),
+    ('\U0000aa44', '\U0000aa4b'),
+    ('\U0000aa60', '\U0000aa76'),
+    ('\U0000aa7a', '\U0000aa7a'),
+    ('\U0000aa80', '\U0000aaaf'),
+    ('\U0000aab1', '\U0000aab1'),
+    ('\U0000aab5', '\U0000aab6'),
+    ('\U0000aab9', '\U0000aabd'),
+    ('\U0000aac0', '\U0000aac0'),
+    ('\U0000aac2', '\U0000aac2'),
+    ('\U0000aadb', '\U0000aadd'),
+    ('\U0000aae0', '\U0000aaea'),
+    ('\U0000aaf2', '\U0000aaf4'),
+    ('\U0000ab01', '\U0000ab06'),
+    ('\U0000ab09', '\U0000ab0e'),
+    ('\U0000ab11', '\U0000ab16'),
+    ('\U0000ab20', '\U0000ab26'),
+    ('\U0000ab28', '\U0000ab2e'),
+    ('\U0000abc0', '\U0000abe2'),
+    ('\U0000ac00', '\U0000ac00'),
+    ('\U0000d7a3', '\U0000d7a3'),
+    ('\U0000d7b0', '\U0000d7c6'),
+    ('\U0000d7cb', '\U0000d7fb'),
+    ('\U0000f900', '\U0000fa6d'),
+    ('\U0000fa70', '\U0000fad9'),
+    ('\U0000fb00', '\U0000fb06'),
+    ('\U0000fb13', '\U0000fb17'),
+    ('\U0000fb1d', '\U0000fb1d'),
+    ('\U0000fb1f', '\U0000fb28'),
+    ('\U0000fb2a', '\U0000fb36'),
+    ('\U0000fb38', '\U0000fb3c'),
+    ('\U0000fb3e', '\U0000fb3e'),
+    ('\U0000fb40', '\U0000fb41'),
+    ('\U0000fb43', '\U0000fb44'),
+    ('\U0000fb46', '\U0000fbb1'),
+    ('\U0000fbd3', '\U0000fd3d'),
+    ('\U0000fd50', '\U0000fd8f'),
+    ('\U0000fd92', '\U0000fdc7'),
+    ('\U0000fdf0', '\U0000fdfb'),
+    ('\U0000fe70', '\U0000fe74'),
+    ('\U0000fe76', '\U0000fefc'),
+    ('\U0000ff21', '\U0000ff3a'),
+    ('\U0000ff41', '\U0000ff5a'),
+    ('\U0000ff66', '\U0000ffbe'),
+    ('\U0000ffc2', '\U0000ffc7'),
+    ('\U0000ffca', '\U0000ffcf'),
+    ('\U0000ffd2', '\U0000ffd7'),
+    ('\U0000ffda', '\U0000ffdc'),
+    ('\U00010000', '\U0001000b'),
+    ('\U0001000d', '\U00010026'),
+    ('\U00010028', '\U0001003a'),
+    ('\U0001003c', '\U0001003d'),
+    ('\U0001003f', '\U0001004d'),
+    ('\U00010050', '\U0001005d'),
+    ('\U00010080', '\U000100fa'),
+    ('\U00010280', '\U0001029c'),
+    ('\U000102a0', '\U000102d0'),
+    ('\U00010300', '\U0001031e'),
+    ('\U00010330', '\U00010340'),
+    ('\U00010342', '\U00010349'),
+    ('\U00010380', '\U0001039d'),
+    ('\U000103a0', '\U000103c3'),
+    ('\U000103c8', '\U000103cf'),
+    ('\U00010400', '\U0001049d'),
+    ('\U00010800', '\U00010805'),
+    ('\U00010808', '\U00010808'),
+    ('\U0001080a', '\U00010835'),
+    ('\U00010837', '\U00010838'),
+    ('\U0001083c', '\U0001083c'),
+    ('\U0001083f', '\U00010855'),
+    ('\U00010900', '\U00010915'),
+    ('\U00010920', '\U00010939'),
+    ('\U00010980', '\U000109b7'),
+    ('\U000109be', '\U000109bf'),
+    ('\U00010a00', '\U00010a00'),
+    ('\U00010a10', '\U00010a13'),
+    ('\U00010a15', '\U00010a17'),
+    ('\U00010a19', '\U00010a33'),
+    ('\U00010a60', '\U00010a7c'),
+    ('\U00010b00', '\U00010b35'),
+    ('\U00010b40', '\U00010b55'),
+    ('\U00010b60', '\U00010b72'),
+    ('\U00010c00', '\U00010c48'),
+    ('\U00011003', '\U00011037'),
+    ('\U00011083', '\U000110af'),
+    ('\U000110d0', '\U000110e8'),
+    ('\U00011103', '\U00011126'),
+    ('\U00011183', '\U000111b2'),
+    ('\U000111c1', '\U000111c4'),
+    ('\U00011680', '\U000116aa'),
+    ('\U00012000', '\U0001236e'),
+    ('\U00013000', '\U0001342e'),
+    ('\U00016800', '\U00016a38'),
+    ('\U00016f00', '\U00016f44'),
+    ('\U00016f50', '\U00016f50'),
+    ('\U00016f93', '\U00016f9f'),
+    ('\U0001b000', '\U0001b001'),
+    ('\U0001d400', '\U0001d454'),
+    ('\U0001d456', '\U0001d49c'),
+    ('\U0001d49e', '\U0001d49f'),
+    ('\U0001d4a2', '\U0001d4a2'),
+    ('\U0001d4a5', '\U0001d4a6'),
+    ('\U0001d4a9', '\U0001d4ac'),
+    ('\U0001d4ae', '\U0001d4b9'),
+    ('\U0001d4bb', '\U0001d4bb'),
+    ('\U0001d4bd', '\U0001d4c3'),
+    ('\U0001d4c5', '\U0001d505'),
+    ('\U0001d507', '\U0001d50a'),
+    ('\U0001d50d', '\U0001d514'),
+    ('\U0001d516', '\U0001d51c'),
+    ('\U0001d51e', '\U0001d539'),
+    ('\U0001d53b', '\U0001d53e'),
+    ('\U0001d540', '\U0001d544'),
+    ('\U0001d546', '\U0001d546'),
+    ('\U0001d54a', '\U0001d550'),
+    ('\U0001d552', '\U0001d6a5'),
+    ('\U0001d6a8', '\U0001d6c0'),
+    ('\U0001d6c2', '\U0001d6da'),
+    ('\U0001d6dc', '\U0001d6fa'),
+    ('\U0001d6fc', '\U0001d714'),
+    ('\U0001d716', '\U0001d734'),
+    ('\U0001d736', '\U0001d74e'),
+    ('\U0001d750', '\U0001d76e'),
+    ('\U0001d770', '\U0001d788'),
+    ('\U0001d78a', '\U0001d7a8'),
+    ('\U0001d7aa', '\U0001d7c2'),
+    ('\U0001d7c4', '\U0001d7cb'),
+    ('\U0001ee00', '\U0001ee03'),
+    ('\U0001ee05', '\U0001ee1f'),
+    ('\U0001ee21', '\U0001ee22'),
+    ('\U0001ee24', '\U0001ee24'),
+    ('\U0001ee27', '\U0001ee27'),
+    ('\U0001ee29', '\U0001ee32'),
+    ('\U0001ee34', '\U0001ee37'),
+    ('\U0001ee39', '\U0001ee39'),
+    ('\U0001ee3b', '\U0001ee3b'),
+    ('\U0001ee42', '\U0001ee42'),
+    ('\U0001ee47', '\U0001ee47'),
+    ('\U0001ee49', '\U0001ee49'),
+    ('\U0001ee4b', '\U0001ee4b'),
+    ('\U0001ee4d', '\U0001ee4f'),
+    ('\U0001ee51', '\U0001ee52'),
+    ('\U0001ee54', '\U0001ee54'),
+    ('\U0001ee57', '\U0001ee57'),
+    ('\U0001ee59', '\U0001ee59'),
+    ('\U0001ee5b', '\U0001ee5b'),
+    ('\U0001ee5d', '\U0001ee5d'),
+    ('\U0001ee5f', '\U0001ee5f'),
+    ('\U0001ee61', '\U0001ee62'),
+    ('\U0001ee64', '\U0001ee64'),
+    ('\U0001ee67', '\U0001ee6a'),
+    ('\U0001ee6c', '\U0001ee72'),
+    ('\U0001ee74', '\U0001ee77'),
+    ('\U0001ee79', '\U0001ee7c'),
+    ('\U0001ee7e', '\U0001ee7e'),
+    ('\U0001ee80', '\U0001ee89'),
+    ('\U0001ee8b', '\U0001ee9b'),
+    ('\U0001eea1', '\U0001eea3'),
+    ('\U0001eea5', '\U0001eea9'),
+    ('\U0001eeab', '\U0001eebb'),
+    ('\U00020000', '\U00020000'),
+    ('\U0002a6d6', '\U0002a6d6'),
+    ('\U0002a700', '\U0002a700'),
+    ('\U0002b734', '\U0002b734'),
+    ('\U0002b740', '\U0002b740'),
+    ('\U0002b81d', '\U0002b81d'),
+    ('\U0002f800', '\U0002fa1d')
+    ]),
+("LC", &[
+    ('\U00000041', '\U0000005a'),
+    ('\U00000061', '\U0000007a'),
+    ('\U000000b5', '\U000000b5'),
+    ('\U000000c0', '\U000000d6'),
+    ('\U000000d8', '\U000000f6'),
+    ('\U000000f8', '\U000001ba'),
+    ('\U000001bc', '\U000001bf'),
+    ('\U000001c4', '\U00000293'),
+    ('\U00000295', '\U000002af'),
+    ('\U00000370', '\U00000373'),
+    ('\U00000376', '\U00000377'),
+    ('\U0000037b', '\U0000037d'),
+    ('\U00000386', '\U00000386'),
+    ('\U00000388', '\U0000038a'),
+    ('\U0000038c', '\U0000038c'),
+    ('\U0000038e', '\U000003a1'),
+    ('\U000003a3', '\U000003f5'),
+    ('\U000003f7', '\U00000481'),
+    ('\U0000048a', '\U00000527'),
+    ('\U00000531', '\U00000556'),
+    ('\U00000561', '\U00000587'),
+    ('\U000010a0', '\U000010c5'),
+    ('\U000010c7', '\U000010c7'),
+    ('\U000010cd', '\U000010cd'),
+    ('\U00001d00', '\U00001d2b'),
+    ('\U00001d6b', '\U00001d77'),
+    ('\U00001d79', '\U00001d9a'),
+    ('\U00001e00', '\U00001f15'),
+    ('\U00001f18', '\U00001f1d'),
+    ('\U00001f20', '\U00001f45'),
+    ('\U00001f48', '\U00001f4d'),
+    ('\U00001f50', '\U00001f57'),
+    ('\U00001f59', '\U00001f59'),
+    ('\U00001f5b', '\U00001f5b'),
+    ('\U00001f5d', '\U00001f5d'),
+    ('\U00001f5f', '\U00001f7d'),
+    ('\U00001f80', '\U00001fb4'),
+    ('\U00001fb6', '\U00001fbc'),
+    ('\U00001fbe', '\U00001fbe'),
+    ('\U00001fc2', '\U00001fc4'),
+    ('\U00001fc6', '\U00001fcc'),
+    ('\U00001fd0', '\U00001fd3'),
+    ('\U00001fd6', '\U00001fdb'),
+    ('\U00001fe0', '\U00001fec'),
+    ('\U00001ff2', '\U00001ff4'),
+    ('\U00001ff6', '\U00001ffc'),
+    ('\U00002102', '\U00002102'),
+    ('\U00002107', '\U00002107'),
+    ('\U0000210a', '\U00002113'),
+    ('\U00002115', '\U00002115'),
+    ('\U00002119', '\U0000211d'),
+    ('\U00002124', '\U00002124'),
+    ('\U00002126', '\U00002126'),
+    ('\U00002128', '\U00002128'),
+    ('\U0000212a', '\U0000212d'),
+    ('\U0000212f', '\U00002134'),
+    ('\U00002139', '\U00002139'),
+    ('\U0000213c', '\U0000213f'),
+    ('\U00002145', '\U00002149'),
+    ('\U0000214e', '\U0000214e'),
+    ('\U00002183', '\U00002184'),
+    ('\U00002c00', '\U00002c2e'),
+    ('\U00002c30', '\U00002c5e'),
+    ('\U00002c60', '\U00002c7b'),
+    ('\U00002c7e', '\U00002ce4'),
+    ('\U00002ceb', '\U00002cee'),
+    ('\U00002cf2', '\U00002cf3'),
+    ('\U00002d00', '\U00002d25'),
+    ('\U00002d27', '\U00002d27'),
+    ('\U00002d2d', '\U00002d2d'),
+    ('\U0000a640', '\U0000a66d'),
+    ('\U0000a680', '\U0000a697'),
+    ('\U0000a722', '\U0000a76f'),
+    ('\U0000a771', '\U0000a787'),
+    ('\U0000a78b', '\U0000a78e'),
+    ('\U0000a790', '\U0000a793'),
+    ('\U0000a7a0', '\U0000a7aa'),
+    ('\U0000a7fa', '\U0000a7fa'),
+    ('\U0000fb00', '\U0000fb06'),
+    ('\U0000fb13', '\U0000fb17'),
+    ('\U0000ff21', '\U0000ff3a'),
+    ('\U0000ff41', '\U0000ff5a'),
+    ('\U00010400', '\U0001044f'),
+    ('\U0001d400', '\U0001d454'),
+    ('\U0001d456', '\U0001d49c'),
+    ('\U0001d49e', '\U0001d49f'),
+    ('\U0001d4a2', '\U0001d4a2'),
+    ('\U0001d4a5', '\U0001d4a6'),
+    ('\U0001d4a9', '\U0001d4ac'),
+    ('\U0001d4ae', '\U0001d4b9'),
+    ('\U0001d4bb', '\U0001d4bb'),
+    ('\U0001d4bd', '\U0001d4c3'),
+    ('\U0001d4c5', '\U0001d505'),
+    ('\U0001d507', '\U0001d50a'),
+    ('\U0001d50d', '\U0001d514'),
+    ('\U0001d516', '\U0001d51c'),
+    ('\U0001d51e', '\U0001d539'),
+    ('\U0001d53b', '\U0001d53e'),
+    ('\U0001d540', '\U0001d544'),
+    ('\U0001d546', '\U0001d546'),
+    ('\U0001d54a', '\U0001d550'),
+    ('\U0001d552', '\U0001d6a5'),
+    ('\U0001d6a8', '\U0001d6c0'),
+    ('\U0001d6c2', '\U0001d6da'),
+    ('\U0001d6dc', '\U0001d6fa'),
+    ('\U0001d6fc', '\U0001d714'),
+    ('\U0001d716', '\U0001d734'),
+    ('\U0001d736', '\U0001d74e'),
+    ('\U0001d750', '\U0001d76e'),
+    ('\U0001d770', '\U0001d788'),
+    ('\U0001d78a', '\U0001d7a8'),
+    ('\U0001d7aa', '\U0001d7c2'),
+    ('\U0001d7c4', '\U0001d7cb')
+    ]),
+("Lao", &[
+    ('\U00000e81', '\U00000e82'),
+    ('\U00000e84', '\U00000e84'),
+    ('\U00000e87', '\U00000e88'),
+    ('\U00000e8a', '\U00000e8a'),
+    ('\U00000e8d', '\U00000e8d'),
+    ('\U00000e94', '\U00000e97'),
+    ('\U00000e99', '\U00000e9f'),
+    ('\U00000ea1', '\U00000ea3'),
+    ('\U00000ea5', '\U00000ea5'),
+    ('\U00000ea7', '\U00000ea7'),
+    ('\U00000eaa', '\U00000eab'),
+    ('\U00000ead', '\U00000eb9'),
+    ('\U00000ebb', '\U00000ebd'),
+    ('\U00000ec0', '\U00000ec4'),
+    ('\U00000ec6', '\U00000ec6'),
+    ('\U00000ec8', '\U00000ecd'),
+    ('\U00000ed0', '\U00000ed9'),
+    ('\U00000edc', '\U00000edf')
+    ]),
+("Latin", &[
+    ('\U00000041', '\U0000005a'),
+    ('\U00000061', '\U0000007a'),
+    ('\U000000aa', '\U000000aa'),
+    ('\U000000ba', '\U000000ba'),
+    ('\U000000c0', '\U000000d6'),
+    ('\U000000d8', '\U000000f6'),
+    ('\U000000f8', '\U000002b8'),
+    ('\U000002e0', '\U000002e4'),
+    ('\U00001d00', '\U00001d25'),
+    ('\U00001d2c', '\U00001d5c'),
+    ('\U00001d62', '\U00001d65'),
+    ('\U00001d6b', '\U00001d77'),
+    ('\U00001d79', '\U00001dbe'),
+    ('\U00001e00', '\U00001eff'),
+    ('\U00002071', '\U00002071'),
+    ('\U0000207f', '\U0000207f'),
+    ('\U00002090', '\U0000209c'),
+    ('\U0000212a', '\U0000212b'),
+    ('\U00002132', '\U00002132'),
+    ('\U0000214e', '\U0000214e'),
+    ('\U00002160', '\U00002188'),
+    ('\U00002c60', '\U00002c7f'),
+    ('\U0000a722', '\U0000a787'),
+    ('\U0000a78b', '\U0000a78e'),
+    ('\U0000a790', '\U0000a793'),
+    ('\U0000a7a0', '\U0000a7aa'),
+    ('\U0000a7f8', '\U0000a7ff'),
+    ('\U0000fb00', '\U0000fb06'),
+    ('\U0000ff21', '\U0000ff3a'),
+    ('\U0000ff41', '\U0000ff5a')
+    ]),
+("Lepcha", &[
+    ('\U00001c00', '\U00001c37'),
+    ('\U00001c3b', '\U00001c49'),
+    ('\U00001c4d', '\U00001c4f')
+    ]),
+("Limbu", &[
+    ('\U00001900', '\U0000191c'),
+    ('\U00001920', '\U0000192b'),
+    ('\U00001930', '\U0000193b'),
+    ('\U00001940', '\U00001940'),
+    ('\U00001944', '\U0000194f')
+    ]),
+("Linear_B", &[
+    ('\U00010000', '\U0001000b'),
+    ('\U0001000d', '\U00010026'),
+    ('\U00010028', '\U0001003a'),
+    ('\U0001003c', '\U0001003d'),
+    ('\U0001003f', '\U0001004d'),
+    ('\U00010050', '\U0001005d'),
+    ('\U00010080', '\U000100fa')
+    ]),
+("Lisu", &[
+    ('\U0000a4d0', '\U0000a4ff')
+    ]),
+("Ll", &[
+    ('\U00000061', '\U0000007a'),
+    ('\U000000b5', '\U000000b5'),
+    ('\U000000df', '\U000000f6'),
+    ('\U000000f8', '\U000000ff'),
+    ('\U00000101', '\U00000101'),
+    ('\U00000103', '\U00000103'),
+    ('\U00000105', '\U00000105'),
+    ('\U00000107', '\U00000107'),
+    ('\U00000109', '\U00000109'),
+    ('\U0000010b', '\U0000010b'),
+    ('\U0000010d', '\U0000010d'),
+    ('\U0000010f', '\U0000010f'),
+    ('\U00000111', '\U00000111'),
+    ('\U00000113', '\U00000113'),
+    ('\U00000115', '\U00000115'),
+    ('\U00000117', '\U00000117'),
+    ('\U00000119', '\U00000119'),
+    ('\U0000011b', '\U0000011b'),
+    ('\U0000011d', '\U0000011d'),
+    ('\U0000011f', '\U0000011f'),
+    ('\U00000121', '\U00000121'),
+    ('\U00000123', '\U00000123'),
+    ('\U00000125', '\U00000125'),
+    ('\U00000127', '\U00000127'),
+    ('\U00000129', '\U00000129'),
+    ('\U0000012b', '\U0000012b'),
+    ('\U0000012d', '\U0000012d'),
+    ('\U0000012f', '\U0000012f'),
+    ('\U00000131', '\U00000131'),
+    ('\U00000133', '\U00000133'),
+    ('\U00000135', '\U00000135'),
+    ('\U00000137', '\U00000138'),
+    ('\U0000013a', '\U0000013a'),
+    ('\U0000013c', '\U0000013c'),
+    ('\U0000013e', '\U0000013e'),
+    ('\U00000140', '\U00000140'),
+    ('\U00000142', '\U00000142'),
+    ('\U00000144', '\U00000144'),
+    ('\U00000146', '\U00000146'),
+    ('\U00000148', '\U00000149'),
+    ('\U0000014b', '\U0000014b'),
+    ('\U0000014d', '\U0000014d'),
+    ('\U0000014f', '\U0000014f'),
+    ('\U00000151', '\U00000151'),
+    ('\U00000153', '\U00000153'),
+    ('\U00000155', '\U00000155'),
+    ('\U00000157', '\U00000157'),
+    ('\U00000159', '\U00000159'),
+    ('\U0000015b', '\U0000015b'),
+    ('\U0000015d', '\U0000015d'),
+    ('\U0000015f', '\U0000015f'),
+    ('\U00000161', '\U00000161'),
+    ('\U00000163', '\U00000163'),
+    ('\U00000165', '\U00000165'),
+    ('\U00000167', '\U00000167'),
+    ('\U00000169', '\U00000169'),
+    ('\U0000016b', '\U0000016b'),
+    ('\U0000016d', '\U0000016d'),
+    ('\U0000016f', '\U0000016f'),
+    ('\U00000171', '\U00000171'),
+    ('\U00000173', '\U00000173'),
+    ('\U00000175', '\U00000175'),
+    ('\U00000177', '\U00000177'),
+    ('\U0000017a', '\U0000017a'),
+    ('\U0000017c', '\U0000017c'),
+    ('\U0000017e', '\U00000180'),
+    ('\U00000183', '\U00000183'),
+    ('\U00000185', '\U00000185'),
+    ('\U00000188', '\U00000188'),
+    ('\U0000018c', '\U0000018d'),
+    ('\U00000192', '\U00000192'),
+    ('\U00000195', '\U00000195'),
+    ('\U00000199', '\U0000019b'),
+    ('\U0000019e', '\U0000019e'),
+    ('\U000001a1', '\U000001a1'),
+    ('\U000001a3', '\U000001a3'),
+    ('\U000001a5', '\U000001a5'),
+    ('\U000001a8', '\U000001a8'),
+    ('\U000001aa', '\U000001ab'),
+    ('\U000001ad', '\U000001ad'),
+    ('\U000001b0', '\U000001b0'),
+    ('\U000001b4', '\U000001b4'),
+    ('\U000001b6', '\U000001b6'),
+    ('\U000001b9', '\U000001ba'),
+    ('\U000001bd', '\U000001bf'),
+    ('\U000001c6', '\U000001c6'),
+    ('\U000001c9', '\U000001c9'),
+    ('\U000001cc', '\U000001cc'),
+    ('\U000001ce', '\U000001ce'),
+    ('\U000001d0', '\U000001d0'),
+    ('\U000001d2', '\U000001d2'),
+    ('\U000001d4', '\U000001d4'),
+    ('\U000001d6', '\U000001d6'),
+    ('\U000001d8', '\U000001d8'),
+    ('\U000001da', '\U000001da'),
+    ('\U000001dc', '\U000001dd'),
+    ('\U000001df', '\U000001df'),
+    ('\U000001e1', '\U000001e1'),
+    ('\U000001e3', '\U000001e3'),
+    ('\U000001e5', '\U000001e5'),
+    ('\U000001e7', '\U000001e7'),
+    ('\U000001e9', '\U000001e9'),
+    ('\U000001eb', '\U000001eb'),
+    ('\U000001ed', '\U000001ed'),
+    ('\U000001ef', '\U000001f0'),
+    ('\U000001f3', '\U000001f3'),
+    ('\U000001f5', '\U000001f5'),
+    ('\U000001f9', '\U000001f9'),
+    ('\U000001fb', '\U000001fb'),
+    ('\U000001fd', '\U000001fd'),
+    ('\U000001ff', '\U000001ff'),
+    ('\U00000201', '\U00000201'),
+    ('\U00000203', '\U00000203'),
+    ('\U00000205', '\U00000205'),
+    ('\U00000207', '\U00000207'),
+    ('\U00000209', '\U00000209'),
+    ('\U0000020b', '\U0000020b'),
+    ('\U0000020d', '\U0000020d'),
+    ('\U0000020f', '\U0000020f'),
+    ('\U00000211', '\U00000211'),
+    ('\U00000213', '\U00000213'),
+    ('\U00000215', '\U00000215'),
+    ('\U00000217', '\U00000217'),
+    ('\U00000219', '\U00000219'),
+    ('\U0000021b', '\U0000021b'),
+    ('\U0000021d', '\U0000021d'),
+    ('\U0000021f', '\U0000021f'),
+    ('\U00000221', '\U00000221'),
+    ('\U00000223', '\U00000223'),
+    ('\U00000225', '\U00000225'),
+    ('\U00000227', '\U00000227'),
+    ('\U00000229', '\U00000229'),
+    ('\U0000022b', '\U0000022b'),
+    ('\U0000022d', '\U0000022d'),
+    ('\U0000022f', '\U0000022f'),
+    ('\U00000231', '\U00000231'),
+    ('\U00000233', '\U00000239'),
+    ('\U0000023c', '\U0000023c'),
+    ('\U0000023f', '\U00000240'),
+    ('\U00000242', '\U00000242'),
+    ('\U00000247', '\U00000247'),
+    ('\U00000249', '\U00000249'),
+    ('\U0000024b', '\U0000024b'),
+    ('\U0000024d', '\U0000024d'),
+    ('\U0000024f', '\U00000293'),
+    ('\U00000295', '\U000002af'),
+    ('\U00000371', '\U00000371'),
+    ('\U00000373', '\U00000373'),
+    ('\U00000377', '\U00000377'),
+    ('\U0000037b', '\U0000037d'),
+    ('\U00000390', '\U00000390'),
+    ('\U000003ac', '\U000003ce'),
+    ('\U000003d0', '\U000003d1'),
+    ('\U000003d5', '\U000003d7'),
+    ('\U000003d9', '\U000003d9'),
+    ('\U000003db', '\U000003db'),
+    ('\U000003dd', '\U000003dd'),
+    ('\U000003df', '\U000003df'),
+    ('\U000003e1', '\U000003e1'),
+    ('\U000003e3', '\U000003e3'),
+    ('\U000003e5', '\U000003e5'),
+    ('\U000003e7', '\U000003e7'),
+    ('\U000003e9', '\U000003e9'),
+    ('\U000003eb', '\U000003eb'),
+    ('\U000003ed', '\U000003ed'),
+    ('\U000003ef', '\U000003f3'),
+    ('\U000003f5', '\U000003f5'),
+    ('\U000003f8', '\U000003f8'),
+    ('\U000003fb', '\U000003fc'),
+    ('\U00000430', '\U0000045f'),
+    ('\U00000461', '\U00000461'),
+    ('\U00000463', '\U00000463'),
+    ('\U00000465', '\U00000465'),
+    ('\U00000467', '\U00000467'),
+    ('\U00000469', '\U00000469'),
+    ('\U0000046b', '\U0000046b'),
+    ('\U0000046d', '\U0000046d'),
+    ('\U0000046f', '\U0000046f'),
+    ('\U00000471', '\U00000471'),
+    ('\U00000473', '\U00000473'),
+    ('\U00000475', '\U00000475'),
+    ('\U00000477', '\U00000477'),
+    ('\U00000479', '\U00000479'),
+    ('\U0000047b', '\U0000047b'),
+    ('\U0000047d', '\U0000047d'),
+    ('\U0000047f', '\U0000047f'),
+    ('\U00000481', '\U00000481'),
+    ('\U0000048b', '\U0000048b'),
+    ('\U0000048d', '\U0000048d'),
+    ('\U0000048f', '\U0000048f'),
+    ('\U00000491', '\U00000491'),
+    ('\U00000493', '\U00000493'),
+    ('\U00000495', '\U00000495'),
+    ('\U00000497', '\U00000497'),
+    ('\U00000499', '\U00000499'),
+    ('\U0000049b', '\U0000049b'),
+    ('\U0000049d', '\U0000049d'),
+    ('\U0000049f', '\U0000049f'),
+    ('\U000004a1', '\U000004a1'),
+    ('\U000004a3', '\U000004a3'),
+    ('\U000004a5', '\U000004a5'),
+    ('\U000004a7', '\U000004a7'),
+    ('\U000004a9', '\U000004a9'),
+    ('\U000004ab', '\U000004ab'),
+    ('\U000004ad', '\U000004ad'),
+    ('\U000004af', '\U000004af'),
+    ('\U000004b1', '\U000004b1'),
+    ('\U000004b3', '\U000004b3'),
+    ('\U000004b5', '\U000004b5'),
+    ('\U000004b7', '\U000004b7'),
+    ('\U000004b9', '\U000004b9'),
+    ('\U000004bb', '\U000004bb'),
+    ('\U000004bd', '\U000004bd'),
+    ('\U000004bf', '\U000004bf'),
+    ('\U000004c2', '\U000004c2'),
+    ('\U000004c4', '\U000004c4'),
+    ('\U000004c6', '\U000004c6'),
+    ('\U000004c8', '\U000004c8'),
+    ('\U000004ca', '\U000004ca'),
+    ('\U000004cc', '\U000004cc'),
+    ('\U000004ce', '\U000004cf'),
+    ('\U000004d1', '\U000004d1'),
+    ('\U000004d3', '\U000004d3'),
+    ('\U000004d5', '\U000004d5'),
+    ('\U000004d7', '\U000004d7'),
+    ('\U000004d9', '\U000004d9'),
+    ('\U000004db', '\U000004db'),
+    ('\U000004dd', '\U000004dd'),
+    ('\U000004df', '\U000004df'),
+    ('\U000004e1', '\U000004e1'),
+    ('\U000004e3', '\U000004e3'),
+    ('\U000004e5', '\U000004e5'),
+    ('\U000004e7', '\U000004e7'),
+    ('\U000004e9', '\U000004e9'),
+    ('\U000004eb', '\U000004eb'),
+    ('\U000004ed', '\U000004ed'),
+    ('\U000004ef', '\U000004ef'),
+    ('\U000004f1', '\U000004f1'),
+    ('\U000004f3', '\U000004f3'),
+    ('\U000004f5', '\U000004f5'),
+    ('\U000004f7', '\U000004f7'),
+    ('\U000004f9', '\U000004f9'),
+    ('\U000004fb', '\U000004fb'),
+    ('\U000004fd', '\U000004fd'),
+    ('\U000004ff', '\U000004ff'),
+    ('\U00000501', '\U00000501'),
+    ('\U00000503', '\U00000503'),
+    ('\U00000505', '\U00000505'),
+    ('\U00000507', '\U00000507'),
+    ('\U00000509', '\U00000509'),
+    ('\U0000050b', '\U0000050b'),
+    ('\U0000050d', '\U0000050d'),
+    ('\U0000050f', '\U0000050f'),
+    ('\U00000511', '\U00000511'),
+    ('\U00000513', '\U00000513'),
+    ('\U00000515', '\U00000515'),
+    ('\U00000517', '\U00000517'),
+    ('\U00000519', '\U00000519'),
+    ('\U0000051b', '\U0000051b'),
+    ('\U0000051d', '\U0000051d'),
+    ('\U0000051f', '\U0000051f'),
+    ('\U00000521', '\U00000521'),
+    ('\U00000523', '\U00000523'),
+    ('\U00000525', '\U00000525'),
+    ('\U00000527', '\U00000527'),
+    ('\U00000561', '\U00000587'),
+    ('\U00001d00', '\U00001d2b'),
+    ('\U00001d6b', '\U00001d77'),
+    ('\U00001d79', '\U00001d9a'),
+    ('\U00001e01', '\U00001e01'),
+    ('\U00001e03', '\U00001e03'),
+    ('\U00001e05', '\U00001e05'),
+    ('\U00001e07', '\U00001e07'),
+    ('\U00001e09', '\U00001e09'),
+    ('\U00001e0b', '\U00001e0b'),
+    ('\U00001e0d', '\U00001e0d'),
+    ('\U00001e0f', '\U00001e0f'),
+    ('\U00001e11', '\U00001e11'),
+    ('\U00001e13', '\U00001e13'),
+    ('\U00001e15', '\U00001e15'),
+    ('\U00001e17', '\U00001e17'),
+    ('\U00001e19', '\U00001e19'),
+    ('\U00001e1b', '\U00001e1b'),
+    ('\U00001e1d', '\U00001e1d'),
+    ('\U00001e1f', '\U00001e1f'),
+    ('\U00001e21', '\U00001e21'),
+    ('\U00001e23', '\U00001e23'),
+    ('\U00001e25', '\U00001e25'),
+    ('\U00001e27', '\U00001e27'),
+    ('\U00001e29', '\U00001e29'),
+    ('\U00001e2b', '\U00001e2b'),
+    ('\U00001e2d', '\U00001e2d'),
+    ('\U00001e2f', '\U00001e2f'),
+    ('\U00001e31', '\U00001e31'),
+    ('\U00001e33', '\U00001e33'),
+    ('\U00001e35', '\U00001e35'),
+    ('\U00001e37', '\U00001e37'),
+    ('\U00001e39', '\U00001e39'),
+    ('\U00001e3b', '\U00001e3b'),
+    ('\U00001e3d', '\U00001e3d'),
+    ('\U00001e3f', '\U00001e3f'),
+    ('\U00001e41', '\U00001e41'),
+    ('\U00001e43', '\U00001e43'),
+    ('\U00001e45', '\U00001e45'),
+    ('\U00001e47', '\U00001e47'),
+    ('\U00001e49', '\U00001e49'),
+    ('\U00001e4b', '\U00001e4b'),
+    ('\U00001e4d', '\U00001e4d'),
+    ('\U00001e4f', '\U00001e4f'),
+    ('\U00001e51', '\U00001e51'),
+    ('\U00001e53', '\U00001e53'),
+    ('\U00001e55', '\U00001e55'),
+    ('\U00001e57', '\U00001e57'),
+    ('\U00001e59', '\U00001e59'),
+    ('\U00001e5b', '\U00001e5b'),
+    ('\U00001e5d', '\U00001e5d'),
+    ('\U00001e5f', '\U00001e5f'),
+    ('\U00001e61', '\U00001e61'),
+    ('\U00001e63', '\U00001e63'),
+    ('\U00001e65', '\U00001e65'),
+    ('\U00001e67', '\U00001e67'),
+    ('\U00001e69', '\U00001e69'),
+    ('\U00001e6b', '\U00001e6b'),
+    ('\U00001e6d', '\U00001e6d'),
+    ('\U00001e6f', '\U00001e6f'),
+    ('\U00001e71', '\U00001e71'),
+    ('\U00001e73', '\U00001e73'),
+    ('\U00001e75', '\U00001e75'),
+    ('\U00001e77', '\U00001e77'),
+    ('\U00001e79', '\U00001e79'),
+    ('\U00001e7b', '\U00001e7b'),
+    ('\U00001e7d', '\U00001e7d'),
+    ('\U00001e7f', '\U00001e7f'),
+    ('\U00001e81', '\U00001e81'),
+    ('\U00001e83', '\U00001e83'),
+    ('\U00001e85', '\U00001e85'),
+    ('\U00001e87', '\U00001e87'),
+    ('\U00001e89', '\U00001e89'),
+    ('\U00001e8b', '\U00001e8b'),
+    ('\U00001e8d', '\U00001e8d'),
+    ('\U00001e8f', '\U00001e8f'),
+    ('\U00001e91', '\U00001e91'),
+    ('\U00001e93', '\U00001e93'),
+    ('\U00001e95', '\U00001e9d'),
+    ('\U00001e9f', '\U00001e9f'),
+    ('\U00001ea1', '\U00001ea1'),
+    ('\U00001ea3', '\U00001ea3'),
+    ('\U00001ea5', '\U00001ea5'),
+    ('\U00001ea7', '\U00001ea7'),
+    ('\U00001ea9', '\U00001ea9'),
+    ('\U00001eab', '\U00001eab'),
+    ('\U00001ead', '\U00001ead'),
+    ('\U00001eaf', '\U00001eaf'),
+    ('\U00001eb1', '\U00001eb1'),
+    ('\U00001eb3', '\U00001eb3'),
+    ('\U00001eb5', '\U00001eb5'),
+    ('\U00001eb7', '\U00001eb7'),
+    ('\U00001eb9', '\U00001eb9'),
+    ('\U00001ebb', '\U00001ebb'),
+    ('\U00001ebd', '\U00001ebd'),
+    ('\U00001ebf', '\U00001ebf'),
+    ('\U00001ec1', '\U00001ec1'),
+    ('\U00001ec3', '\U00001ec3'),
+    ('\U00001ec5', '\U00001ec5'),
+    ('\U00001ec7', '\U00001ec7'),
+    ('\U00001ec9', '\U00001ec9'),
+    ('\U00001ecb', '\U00001ecb'),
+    ('\U00001ecd', '\U00001ecd'),
+    ('\U00001ecf', '\U00001ecf'),
+    ('\U00001ed1', '\U00001ed1'),
+    ('\U00001ed3', '\U00001ed3'),
+    ('\U00001ed5', '\U00001ed5'),
+    ('\U00001ed7', '\U00001ed7'),
+    ('\U00001ed9', '\U00001ed9'),
+    ('\U00001edb', '\U00001edb'),
+    ('\U00001edd', '\U00001edd'),
+    ('\U00001edf', '\U00001edf'),
+    ('\U00001ee1', '\U00001ee1'),
+    ('\U00001ee3', '\U00001ee3'),
+    ('\U00001ee5', '\U00001ee5'),
+    ('\U00001ee7', '\U00001ee7'),
+    ('\U00001ee9', '\U00001ee9'),
+    ('\U00001eeb', '\U00001eeb'),
+    ('\U00001eed', '\U00001eed'),
+    ('\U00001eef', '\U00001eef'),
+    ('\U00001ef1', '\U00001ef1'),
+    ('\U00001ef3', '\U00001ef3'),
+    ('\U00001ef5', '\U00001ef5'),
+    ('\U00001ef7', '\U00001ef7'),
+    ('\U00001ef9', '\U00001ef9'),
+    ('\U00001efb', '\U00001efb'),
+    ('\U00001efd', '\U00001efd'),
+    ('\U00001eff', '\U00001f07'),
+    ('\U00001f10', '\U00001f15'),
+    ('\U00001f20', '\U00001f27'),
+    ('\U00001f30', '\U00001f37'),
+    ('\U00001f40', '\U00001f45'),
+    ('\U00001f50', '\U00001f57'),
+    ('\U00001f60', '\U00001f67'),
+    ('\U00001f70', '\U00001f7d'),
+    ('\U00001f80', '\U00001f87'),
+    ('\U00001f90', '\U00001f97'),
+    ('\U00001fa0', '\U00001fa7'),
+    ('\U00001fb0', '\U00001fb4'),
+    ('\U00001fb6', '\U00001fb7'),
+    ('\U00001fbe', '\U00001fbe'),
+    ('\U00001fc2', '\U00001fc4'),
+    ('\U00001fc6', '\U00001fc7'),
+    ('\U00001fd0', '\U00001fd3'),
+    ('\U00001fd6', '\U00001fd7'),
+    ('\U00001fe0', '\U00001fe7'),
+    ('\U00001ff2', '\U00001ff4'),
+    ('\U00001ff6', '\U00001ff7'),
+    ('\U0000210a', '\U0000210a'),
+    ('\U0000210e', '\U0000210f'),
+    ('\U00002113', '\U00002113'),
+    ('\U0000212f', '\U0000212f'),
+    ('\U00002134', '\U00002134'),
+    ('\U00002139', '\U00002139'),
+    ('\U0000213c', '\U0000213d'),
+    ('\U00002146', '\U00002149'),
+    ('\U0000214e', '\U0000214e'),
+    ('\U00002184', '\U00002184'),
+    ('\U00002c30', '\U00002c5e'),
+    ('\U00002c61', '\U00002c61'),
+    ('\U00002c65', '\U00002c66'),
+    ('\U00002c68', '\U00002c68'),
+    ('\U00002c6a', '\U00002c6a'),
+    ('\U00002c6c', '\U00002c6c'),
+    ('\U00002c71', '\U00002c71'),
+    ('\U00002c73', '\U00002c74'),
+    ('\U00002c76', '\U00002c7b'),
+    ('\U00002c81', '\U00002c81'),
+    ('\U00002c83', '\U00002c83'),
+    ('\U00002c85', '\U00002c85'),
+    ('\U00002c87', '\U00002c87'),
+    ('\U00002c89', '\U00002c89'),
+    ('\U00002c8b', '\U00002c8b'),
+    ('\U00002c8d', '\U00002c8d'),
+    ('\U00002c8f', '\U00002c8f'),
+    ('\U00002c91', '\U00002c91'),
+    ('\U00002c93', '\U00002c93'),
+    ('\U00002c95', '\U00002c95'),
+    ('\U00002c97', '\U00002c97'),
+    ('\U00002c99', '\U00002c99'),
+    ('\U00002c9b', '\U00002c9b'),
+    ('\U00002c9d', '\U00002c9d'),
+    ('\U00002c9f', '\U00002c9f'),
+    ('\U00002ca1', '\U00002ca1'),
+    ('\U00002ca3', '\U00002ca3'),
+    ('\U00002ca5', '\U00002ca5'),
+    ('\U00002ca7', '\U00002ca7'),
+    ('\U00002ca9', '\U00002ca9'),
+    ('\U00002cab', '\U00002cab'),
+    ('\U00002cad', '\U00002cad'),
+    ('\U00002caf', '\U00002caf'),
+    ('\U00002cb1', '\U00002cb1'),
+    ('\U00002cb3', '\U00002cb3'),
+    ('\U00002cb5', '\U00002cb5'),
+    ('\U00002cb7', '\U00002cb7'),
+    ('\U00002cb9', '\U00002cb9'),
+    ('\U00002cbb', '\U00002cbb'),
+    ('\U00002cbd', '\U00002cbd'),
+    ('\U00002cbf', '\U00002cbf'),
+    ('\U00002cc1', '\U00002cc1'),
+    ('\U00002cc3', '\U00002cc3'),
+    ('\U00002cc5', '\U00002cc5'),
+    ('\U00002cc7', '\U00002cc7'),
+    ('\U00002cc9', '\U00002cc9'),
+    ('\U00002ccb', '\U00002ccb'),
+    ('\U00002ccd', '\U00002ccd'),
+    ('\U00002ccf', '\U00002ccf'),
+    ('\U00002cd1', '\U00002cd1'),
+    ('\U00002cd3', '\U00002cd3'),
+    ('\U00002cd5', '\U00002cd5'),
+    ('\U00002cd7', '\U00002cd7'),
+    ('\U00002cd9', '\U00002cd9'),
+    ('\U00002cdb', '\U00002cdb'),
+    ('\U00002cdd', '\U00002cdd'),
+    ('\U00002cdf', '\U00002cdf'),
+    ('\U00002ce1', '\U00002ce1'),
+    ('\U00002ce3', '\U00002ce4'),
+    ('\U00002cec', '\U00002cec'),
+    ('\U00002cee', '\U00002cee'),
+    ('\U00002cf3', '\U00002cf3'),
+    ('\U00002d00', '\U00002d25'),
+    ('\U00002d27', '\U00002d27'),
+    ('\U00002d2d', '\U00002d2d'),
+    ('\U0000a641', '\U0000a641'),
+    ('\U0000a643', '\U0000a643'),
+    ('\U0000a645', '\U0000a645'),
+    ('\U0000a647', '\U0000a647'),
+    ('\U0000a649', '\U0000a649'),
+    ('\U0000a64b', '\U0000a64b'),
+    ('\U0000a64d', '\U0000a64d'),
+    ('\U0000a64f', '\U0000a64f'),
+    ('\U0000a651', '\U0000a651'),
+    ('\U0000a653', '\U0000a653'),
+    ('\U0000a655', '\U0000a655'),
+    ('\U0000a657', '\U0000a657'),
+    ('\U0000a659', '\U0000a659'),
+    ('\U0000a65b', '\U0000a65b'),
+    ('\U0000a65d', '\U0000a65d'),
+    ('\U0000a65f', '\U0000a65f'),
+    ('\U0000a661', '\U0000a661'),
+    ('\U0000a663', '\U0000a663'),
+    ('\U0000a665', '\U0000a665'),
+    ('\U0000a667', '\U0000a667'),
+    ('\U0000a669', '\U0000a669'),
+    ('\U0000a66b', '\U0000a66b'),
+    ('\U0000a66d', '\U0000a66d'),
+    ('\U0000a681', '\U0000a681'),
+    ('\U0000a683', '\U0000a683'),
+    ('\U0000a685', '\U0000a685'),
+    ('\U0000a687', '\U0000a687'),
+    ('\U0000a689', '\U0000a689'),
+    ('\U0000a68b', '\U0000a68b'),
+    ('\U0000a68d', '\U0000a68d'),
+    ('\U0000a68f', '\U0000a68f'),
+    ('\U0000a691', '\U0000a691'),
+    ('\U0000a693', '\U0000a693'),
+    ('\U0000a695', '\U0000a695'),
+    ('\U0000a697', '\U0000a697'),
+    ('\U0000a723', '\U0000a723'),
+    ('\U0000a725', '\U0000a725'),
+    ('\U0000a727', '\U0000a727'),
+    ('\U0000a729', '\U0000a729'),
+    ('\U0000a72b', '\U0000a72b'),
+    ('\U0000a72d', '\U0000a72d'),
+    ('\U0000a72f', '\U0000a731'),
+    ('\U0000a733', '\U0000a733'),
+    ('\U0000a735', '\U0000a735'),
+    ('\U0000a737', '\U0000a737'),
+    ('\U0000a739', '\U0000a739'),
+    ('\U0000a73b', '\U0000a73b'),
+    ('\U0000a73d', '\U0000a73d'),
+    ('\U0000a73f', '\U0000a73f'),
+    ('\U0000a741', '\U0000a741'),
+    ('\U0000a743', '\U0000a743'),
+    ('\U0000a745', '\U0000a745'),
+    ('\U0000a747', '\U0000a747'),
+    ('\U0000a749', '\U0000a749'),
+    ('\U0000a74b', '\U0000a74b'),
+    ('\U0000a74d', '\U0000a74d'),
+    ('\U0000a74f', '\U0000a74f'),
+    ('\U0000a751', '\U0000a751'),
+    ('\U0000a753', '\U0000a753'),
+    ('\U0000a755', '\U0000a755'),
+    ('\U0000a757', '\U0000a757'),
+    ('\U0000a759', '\U0000a759'),
+    ('\U0000a75b', '\U0000a75b'),
+    ('\U0000a75d', '\U0000a75d'),
+    ('\U0000a75f', '\U0000a75f'),
+    ('\U0000a761', '\U0000a761'),
+    ('\U0000a763', '\U0000a763'),
+    ('\U0000a765', '\U0000a765'),
+    ('\U0000a767', '\U0000a767'),
+    ('\U0000a769', '\U0000a769'),
+    ('\U0000a76b', '\U0000a76b'),
+    ('\U0000a76d', '\U0000a76d'),
+    ('\U0000a76f', '\U0000a76f'),
+    ('\U0000a771', '\U0000a778'),
+    ('\U0000a77a', '\U0000a77a'),
+    ('\U0000a77c', '\U0000a77c'),
+    ('\U0000a77f', '\U0000a77f'),
+    ('\U0000a781', '\U0000a781'),
+    ('\U0000a783', '\U0000a783'),
+    ('\U0000a785', '\U0000a785'),
+    ('\U0000a787', '\U0000a787'),
+    ('\U0000a78c', '\U0000a78c'),
+    ('\U0000a78e', '\U0000a78e'),
+    ('\U0000a791', '\U0000a791'),
+    ('\U0000a793', '\U0000a793'),
+    ('\U0000a7a1', '\U0000a7a1'),
+    ('\U0000a7a3', '\U0000a7a3'),
+    ('\U0000a7a5', '\U0000a7a5'),
+    ('\U0000a7a7', '\U0000a7a7'),
+    ('\U0000a7a9', '\U0000a7a9'),
+    ('\U0000a7fa', '\U0000a7fa'),
+    ('\U0000fb00', '\U0000fb06'),
+    ('\U0000fb13', '\U0000fb17'),
+    ('\U0000ff41', '\U0000ff5a'),
+    ('\U00010428', '\U0001044f'),
+    ('\U0001d41a', '\U0001d433'),
+    ('\U0001d44e', '\U0001d454'),
+    ('\U0001d456', '\U0001d467'),
+    ('\U0001d482', '\U0001d49b'),
+    ('\U0001d4b6', '\U0001d4b9'),
+    ('\U0001d4bb', '\U0001d4bb'),
+    ('\U0001d4bd', '\U0001d4c3'),
+    ('\U0001d4c5', '\U0001d4cf'),
+    ('\U0001d4ea', '\U0001d503'),
+    ('\U0001d51e', '\U0001d537'),
+    ('\U0001d552', '\U0001d56b'),
+    ('\U0001d586', '\U0001d59f'),
+    ('\U0001d5ba', '\U0001d5d3'),
+    ('\U0001d5ee', '\U0001d607'),
+    ('\U0001d622', '\U0001d63b'),
+    ('\U0001d656', '\U0001d66f'),
+    ('\U0001d68a', '\U0001d6a5'),
+    ('\U0001d6c2', '\U0001d6da'),
+    ('\U0001d6dc', '\U0001d6e1'),
+    ('\U0001d6fc', '\U0001d714'),
+    ('\U0001d716', '\U0001d71b'),
+    ('\U0001d736', '\U0001d74e'),
+    ('\U0001d750', '\U0001d755'),
+    ('\U0001d770', '\U0001d788'),
+    ('\U0001d78a', '\U0001d78f'),
+    ('\U0001d7aa', '\U0001d7c2'),
+    ('\U0001d7c4', '\U0001d7c9'),
+    ('\U0001d7cb', '\U0001d7cb')
+    ]),
+("Lm", &[
+    ('\U000002b0', '\U000002c1'),
+    ('\U000002c6', '\U000002d1'),
+    ('\U000002e0', '\U000002e4'),
+    ('\U000002ec', '\U000002ec'),
+    ('\U000002ee', '\U000002ee'),
+    ('\U00000374', '\U00000374'),
+    ('\U0000037a', '\U0000037a'),
+    ('\U00000559', '\U00000559'),
+    ('\U00000640', '\U00000640'),
+    ('\U000006e5', '\U000006e6'),
+    ('\U000007f4', '\U000007f5'),
+    ('\U000007fa', '\U000007fa'),
+    ('\U0000081a', '\U0000081a'),
+    ('\U00000824', '\U00000824'),
+    ('\U00000828', '\U00000828'),
+    ('\U00000971', '\U00000971'),
+    ('\U00000e46', '\U00000e46'),
+    ('\U00000ec6', '\U00000ec6'),
+    ('\U000010fc', '\U000010fc'),
+    ('\U000017d7', '\U000017d7'),
+    ('\U00001843', '\U00001843'),
+    ('\U00001aa7', '\U00001aa7'),
+    ('\U00001c78', '\U00001c7d'),
+    ('\U00001d2c', '\U00001d6a'),
+    ('\U00001d78', '\U00001d78'),
+    ('\U00001d9b', '\U00001dbf'),
+    ('\U00002071', '\U00002071'),
+    ('\U0000207f', '\U0000207f'),
+    ('\U00002090', '\U0000209c'),
+    ('\U00002c7c', '\U00002c7d'),
+    ('\U00002d6f', '\U00002d6f'),
+    ('\U00002e2f', '\U00002e2f'),
+    ('\U00003005', '\U00003005'),
+    ('\U00003031', '\U00003035'),
+    ('\U0000303b', '\U0000303b'),
+    ('\U0000309d', '\U0000309e'),
+    ('\U000030fc', '\U000030fe'),
+    ('\U0000a015', '\U0000a015'),
+    ('\U0000a4f8', '\U0000a4fd'),
+    ('\U0000a60c', '\U0000a60c'),
+    ('\U0000a67f', '\U0000a67f'),
+    ('\U0000a717', '\U0000a71f'),
+    ('\U0000a770', '\U0000a770'),
+    ('\U0000a788', '\U0000a788'),
+    ('\U0000a7f8', '\U0000a7f9'),
+    ('\U0000a9cf', '\U0000a9cf'),
+    ('\U0000aa70', '\U0000aa70'),
+    ('\U0000aadd', '\U0000aadd'),
+    ('\U0000aaf3', '\U0000aaf4'),
+    ('\U0000ff70', '\U0000ff70'),
+    ('\U0000ff9e', '\U0000ff9f'),
+    ('\U00016f93', '\U00016f9f')
+    ]),
+("Lo", &[
+    ('\U000000aa', '\U000000aa'),
+    ('\U000000ba', '\U000000ba'),
+    ('\U000001bb', '\U000001bb'),
+    ('\U000001c0', '\U000001c3'),
+    ('\U00000294', '\U00000294'),
+    ('\U000005d0', '\U000005ea'),
+    ('\U000005f0', '\U000005f2'),
+    ('\U00000620', '\U0000063f'),
+    ('\U00000641', '\U0000064a'),
+    ('\U0000066e', '\U0000066f'),
+    ('\U00000671', '\U000006d3'),
+    ('\U000006d5', '\U000006d5'),
+    ('\U000006ee', '\U000006ef'),
+    ('\U000006fa', '\U000006fc'),
+    ('\U000006ff', '\U000006ff'),
+    ('\U00000710', '\U00000710'),
+    ('\U00000712', '\U0000072f'),
+    ('\U0000074d', '\U000007a5'),
+    ('\U000007b1', '\U000007b1'),
+    ('\U000007ca', '\U000007ea'),
+    ('\U00000800', '\U00000815'),
+    ('\U00000840', '\U00000858'),
+    ('\U000008a0', '\U000008a0'),
+    ('\U000008a2', '\U000008ac'),
+    ('\U00000904', '\U00000939'),
+    ('\U0000093d', '\U0000093d'),
+    ('\U00000950', '\U00000950'),
+    ('\U00000958', '\U00000961'),
+    ('\U00000972', '\U00000977'),
+    ('\U00000979', '\U0000097f'),
+    ('\U00000985', '\U0000098c'),
+    ('\U0000098f', '\U00000990'),
+    ('\U00000993', '\U000009a8'),
+    ('\U000009aa', '\U000009b0'),
+    ('\U000009b2', '\U000009b2'),
+    ('\U000009b6', '\U000009b9'),
+    ('\U000009bd', '\U000009bd'),
+    ('\U000009ce', '\U000009ce'),
+    ('\U000009dc', '\U000009dd'),
+    ('\U000009df', '\U000009e1'),
+    ('\U000009f0', '\U000009f1'),
+    ('\U00000a05', '\U00000a0a'),
+    ('\U00000a0f', '\U00000a10'),
+    ('\U00000a13', '\U00000a28'),
+    ('\U00000a2a', '\U00000a30'),
+    ('\U00000a32', '\U00000a33'),
+    ('\U00000a35', '\U00000a36'),
+    ('\U00000a38', '\U00000a39'),
+    ('\U00000a59', '\U00000a5c'),
+    ('\U00000a5e', '\U00000a5e'),
+    ('\U00000a72', '\U00000a74'),
+    ('\U00000a85', '\U00000a8d'),
+    ('\U00000a8f', '\U00000a91'),
+    ('\U00000a93', '\U00000aa8'),
+    ('\U00000aaa', '\U00000ab0'),
+    ('\U00000ab2', '\U00000ab3'),
+    ('\U00000ab5', '\U00000ab9'),
+    ('\U00000abd', '\U00000abd'),
+    ('\U00000ad0', '\U00000ad0'),
+    ('\U00000ae0', '\U00000ae1'),
+    ('\U00000b05', '\U00000b0c'),
+    ('\U00000b0f', '\U00000b10'),
+    ('\U00000b13', '\U00000b28'),
+    ('\U00000b2a', '\U00000b30'),
+    ('\U00000b32', '\U00000b33'),
+    ('\U00000b35', '\U00000b39'),
+    ('\U00000b3d', '\U00000b3d'),
+    ('\U00000b5c', '\U00000b5d'),
+    ('\U00000b5f', '\U00000b61'),
+    ('\U00000b71', '\U00000b71'),
+    ('\U00000b83', '\U00000b83'),
+    ('\U00000b85', '\U00000b8a'),
+    ('\U00000b8e', '\U00000b90'),
+    ('\U00000b92', '\U00000b95'),
+    ('\U00000b99', '\U00000b9a'),
+    ('\U00000b9c', '\U00000b9c'),
+    ('\U00000b9e', '\U00000b9f'),
+    ('\U00000ba3', '\U00000ba4'),
+    ('\U00000ba8', '\U00000baa'),
+    ('\U00000bae', '\U00000bb9'),
+    ('\U00000bd0', '\U00000bd0'),
+    ('\U00000c05', '\U00000c0c'),
+    ('\U00000c0e', '\U00000c10'),
+    ('\U00000c12', '\U00000c28'),
+    ('\U00000c2a', '\U00000c33'),
+    ('\U00000c35', '\U00000c39'),
+    ('\U00000c3d', '\U00000c3d'),
+    ('\U00000c58', '\U00000c59'),
+    ('\U00000c60', '\U00000c61'),
+    ('\U00000c85', '\U00000c8c'),
+    ('\U00000c8e', '\U00000c90'),
+    ('\U00000c92', '\U00000ca8'),
+    ('\U00000caa', '\U00000cb3'),
+    ('\U00000cb5', '\U00000cb9'),
+    ('\U00000cbd', '\U00000cbd'),
+    ('\U00000cde', '\U00000cde'),
+    ('\U00000ce0', '\U00000ce1'),
+    ('\U00000cf1', '\U00000cf2'),
+    ('\U00000d05', '\U00000d0c'),
+    ('\U00000d0e', '\U00000d10'),
+    ('\U00000d12', '\U00000d3a'),
+    ('\U00000d3d', '\U00000d3d'),
+    ('\U00000d4e', '\U00000d4e'),
+    ('\U00000d60', '\U00000d61'),
+    ('\U00000d7a', '\U00000d7f'),
+    ('\U00000d85', '\U00000d96'),
+    ('\U00000d9a', '\U00000db1'),
+    ('\U00000db3', '\U00000dbb'),
+    ('\U00000dbd', '\U00000dbd'),
+    ('\U00000dc0', '\U00000dc6'),
+    ('\U00000e01', '\U00000e30'),
+    ('\U00000e32', '\U00000e33'),
+    ('\U00000e40', '\U00000e45'),
+    ('\U00000e81', '\U00000e82'),
+    ('\U00000e84', '\U00000e84'),
+    ('\U00000e87', '\U00000e88'),
+    ('\U00000e8a', '\U00000e8a'),
+    ('\U00000e8d', '\U00000e8d'),
+    ('\U00000e94', '\U00000e97'),
+    ('\U00000e99', '\U00000e9f'),
+    ('\U00000ea1', '\U00000ea3'),
+    ('\U00000ea5', '\U00000ea5'),
+    ('\U00000ea7', '\U00000ea7'),
+    ('\U00000eaa', '\U00000eab'),
+    ('\U00000ead', '\U00000eb0'),
+    ('\U00000eb2', '\U00000eb3'),
+    ('\U00000ebd', '\U00000ebd'),
+    ('\U00000ec0', '\U00000ec4'),
+    ('\U00000edc', '\U00000edf'),
+    ('\U00000f00', '\U00000f00'),
+    ('\U00000f40', '\U00000f47'),
+    ('\U00000f49', '\U00000f6c'),
+    ('\U00000f88', '\U00000f8c'),
+    ('\U00001000', '\U0000102a'),
+    ('\U0000103f', '\U0000103f'),
+    ('\U00001050', '\U00001055'),
+    ('\U0000105a', '\U0000105d'),
+    ('\U00001061', '\U00001061'),
+    ('\U00001065', '\U00001066'),
+    ('\U0000106e', '\U00001070'),
+    ('\U00001075', '\U00001081'),
+    ('\U0000108e', '\U0000108e'),
+    ('\U000010d0', '\U000010fa'),
+    ('\U000010fd', '\U00001248'),
+    ('\U0000124a', '\U0000124d'),
+    ('\U00001250', '\U00001256'),
+    ('\U00001258', '\U00001258'),
+    ('\U0000125a', '\U0000125d'),
+    ('\U00001260', '\U00001288'),
+    ('\U0000128a', '\U0000128d'),
+    ('\U00001290', '\U000012b0'),
+    ('\U000012b2', '\U000012b5'),
+    ('\U000012b8', '\U000012be'),
+    ('\U000012c0', '\U000012c0'),
+    ('\U000012c2', '\U000012c5'),
+    ('\U000012c8', '\U000012d6'),
+    ('\U000012d8', '\U00001310'),
+    ('\U00001312', '\U00001315'),
+    ('\U00001318', '\U0000135a'),
+    ('\U00001380', '\U0000138f'),
+    ('\U000013a0', '\U000013f4'),
+    ('\U00001401', '\U0000166c'),
+    ('\U0000166f', '\U0000167f'),
+    ('\U00001681', '\U0000169a'),
+    ('\U000016a0', '\U000016ea'),
+    ('\U00001700', '\U0000170c'),
+    ('\U0000170e', '\U00001711'),
+    ('\U00001720', '\U00001731'),
+    ('\U00001740', '\U00001751'),
+    ('\U00001760', '\U0000176c'),
+    ('\U0000176e', '\U00001770'),
+    ('\U00001780', '\U000017b3'),
+    ('\U000017dc', '\U000017dc'),
+    ('\U00001820', '\U00001842'),
+    ('\U00001844', '\U00001877'),
+    ('\U00001880', '\U000018a8'),
+    ('\U000018aa', '\U000018aa'),
+    ('\U000018b0', '\U000018f5'),
+    ('\U00001900', '\U0000191c'),
+    ('\U00001950', '\U0000196d'),
+    ('\U00001970', '\U00001974'),
+    ('\U00001980', '\U000019ab'),
+    ('\U000019c1', '\U000019c7'),
+    ('\U00001a00', '\U00001a16'),
+    ('\U00001a20', '\U00001a54'),
+    ('\U00001b05', '\U00001b33'),
+    ('\U00001b45', '\U00001b4b'),
+    ('\U00001b83', '\U00001ba0'),
+    ('\U00001bae', '\U00001baf'),
+    ('\U00001bba', '\U00001be5'),
+    ('\U00001c00', '\U00001c23'),
+    ('\U00001c4d', '\U00001c4f'),
+    ('\U00001c5a', '\U00001c77'),
+    ('\U00001ce9', '\U00001cec'),
+    ('\U00001cee', '\U00001cf1'),
+    ('\U00001cf5', '\U00001cf6'),
+    ('\U00002135', '\U00002138'),
+    ('\U00002d30', '\U00002d67'),
+    ('\U00002d80', '\U00002d96'),
+    ('\U00002da0', '\U00002da6'),
+    ('\U00002da8', '\U00002dae'),
+    ('\U00002db0', '\U00002db6'),
+    ('\U00002db8', '\U00002dbe'),
+    ('\U00002dc0', '\U00002dc6'),
+    ('\U00002dc8', '\U00002dce'),
+    ('\U00002dd0', '\U00002dd6'),
+    ('\U00002dd8', '\U00002dde'),
+    ('\U00003006', '\U00003006'),
+    ('\U0000303c', '\U0000303c'),
+    ('\U00003041', '\U00003096'),
+    ('\U0000309f', '\U0000309f'),
+    ('\U000030a1', '\U000030fa'),
+    ('\U000030ff', '\U000030ff'),
+    ('\U00003105', '\U0000312d'),
+    ('\U00003131', '\U0000318e'),
+    ('\U000031a0', '\U000031ba'),
+    ('\U000031f0', '\U000031ff'),
+    ('\U00003400', '\U00003400'),
+    ('\U00004db5', '\U00004db5'),
+    ('\U00004e00', '\U00004e00'),
+    ('\U00009fcc', '\U00009fcc'),
+    ('\U0000a000', '\U0000a014'),
+    ('\U0000a016', '\U0000a48c'),
+    ('\U0000a4d0', '\U0000a4f7'),
+    ('\U0000a500', '\U0000a60b'),
+    ('\U0000a610', '\U0000a61f'),
+    ('\U0000a62a', '\U0000a62b'),
+    ('\U0000a66e', '\U0000a66e'),
+    ('\U0000a6a0', '\U0000a6e5'),
+    ('\U0000a7fb', '\U0000a801'),
+    ('\U0000a803', '\U0000a805'),
+    ('\U0000a807', '\U0000a80a'),
+    ('\U0000a80c', '\U0000a822'),
+    ('\U0000a840', '\U0000a873'),
+    ('\U0000a882', '\U0000a8b3'),
+    ('\U0000a8f2', '\U0000a8f7'),
+    ('\U0000a8fb', '\U0000a8fb'),
+    ('\U0000a90a', '\U0000a925'),
+    ('\U0000a930', '\U0000a946'),
+    ('\U0000a960', '\U0000a97c'),
+    ('\U0000a984', '\U0000a9b2'),
+    ('\U0000aa00', '\U0000aa28'),
+    ('\U0000aa40', '\U0000aa42'),
+    ('\U0000aa44', '\U0000aa4b'),
+    ('\U0000aa60', '\U0000aa6f'),
+    ('\U0000aa71', '\U0000aa76'),
+    ('\U0000aa7a', '\U0000aa7a'),
+    ('\U0000aa80', '\U0000aaaf'),
+    ('\U0000aab1', '\U0000aab1'),
+    ('\U0000aab5', '\U0000aab6'),
+    ('\U0000aab9', '\U0000aabd'),
+    ('\U0000aac0', '\U0000aac0'),
+    ('\U0000aac2', '\U0000aac2'),
+    ('\U0000aadb', '\U0000aadc'),
+    ('\U0000aae0', '\U0000aaea'),
+    ('\U0000aaf2', '\U0000aaf2'),
+    ('\U0000ab01', '\U0000ab06'),
+    ('\U0000ab09', '\U0000ab0e'),
+    ('\U0000ab11', '\U0000ab16'),
+    ('\U0000ab20', '\U0000ab26'),
+    ('\U0000ab28', '\U0000ab2e'),
+    ('\U0000abc0', '\U0000abe2'),
+    ('\U0000ac00', '\U0000ac00'),
+    ('\U0000d7a3', '\U0000d7a3'),
+    ('\U0000d7b0', '\U0000d7c6'),
+    ('\U0000d7cb', '\U0000d7fb'),
+    ('\U0000f900', '\U0000fa6d'),
+    ('\U0000fa70', '\U0000fad9'),
+    ('\U0000fb1d', '\U0000fb1d'),
+    ('\U0000fb1f', '\U0000fb28'),
+    ('\U0000fb2a', '\U0000fb36'),
+    ('\U0000fb38', '\U0000fb3c'),
+    ('\U0000fb3e', '\U0000fb3e'),
+    ('\U0000fb40', '\U0000fb41'),
+    ('\U0000fb43', '\U0000fb44'),
+    ('\U0000fb46', '\U0000fbb1'),
+    ('\U0000fbd3', '\U0000fd3d'),
+    ('\U0000fd50', '\U0000fd8f'),
+    ('\U0000fd92', '\U0000fdc7'),
+    ('\U0000fdf0', '\U0000fdfb'),
+    ('\U0000fe70', '\U0000fe74'),
+    ('\U0000fe76', '\U0000fefc'),
+    ('\U0000ff66', '\U0000ff6f'),
+    ('\U0000ff71', '\U0000ff9d'),
+    ('\U0000ffa0', '\U0000ffbe'),
+    ('\U0000ffc2', '\U0000ffc7'),
+    ('\U0000ffca', '\U0000ffcf'),
+    ('\U0000ffd2', '\U0000ffd7'),
+    ('\U0000ffda', '\U0000ffdc'),
+    ('\U00010000', '\U0001000b'),
+    ('\U0001000d', '\U00010026'),
+    ('\U00010028', '\U0001003a'),
+    ('\U0001003c', '\U0001003d'),
+    ('\U0001003f', '\U0001004d'),
+    ('\U00010050', '\U0001005d'),
+    ('\U00010080', '\U000100fa'),
+    ('\U00010280', '\U0001029c'),
+    ('\U000102a0', '\U000102d0'),
+    ('\U00010300', '\U0001031e'),
+    ('\U00010330', '\U00010340'),
+    ('\U00010342', '\U00010349'),
+    ('\U00010380', '\U0001039d'),
+    ('\U000103a0', '\U000103c3'),
+    ('\U000103c8', '\U000103cf'),
+    ('\U00010450', '\U0001049d'),
+    ('\U00010800', '\U00010805'),
+    ('\U00010808', '\U00010808'),
+    ('\U0001080a', '\U00010835'),
+    ('\U00010837', '\U00010838'),
+    ('\U0001083c', '\U0001083c'),
+    ('\U0001083f', '\U00010855'),
+    ('\U00010900', '\U00010915'),
+    ('\U00010920', '\U00010939'),
+    ('\U00010980', '\U000109b7'),
+    ('\U000109be', '\U000109bf'),
+    ('\U00010a00', '\U00010a00'),
+    ('\U00010a10', '\U00010a13'),
+    ('\U00010a15', '\U00010a17'),
+    ('\U00010a19', '\U00010a33'),
+    ('\U00010a60', '\U00010a7c'),
+    ('\U00010b00', '\U00010b35'),
+    ('\U00010b40', '\U00010b55'),
+    ('\U00010b60', '\U00010b72'),
+    ('\U00010c00', '\U00010c48'),
+    ('\U00011003', '\U00011037'),
+    ('\U00011083', '\U000110af'),
+    ('\U000110d0', '\U000110e8'),
+    ('\U00011103', '\U00011126'),
+    ('\U00011183', '\U000111b2'),
+    ('\U000111c1', '\U000111c4'),
+    ('\U00011680', '\U000116aa'),
+    ('\U00012000', '\U0001236e'),
+    ('\U00013000', '\U0001342e'),
+    ('\U00016800', '\U00016a38'),
+    ('\U00016f00', '\U00016f44'),
+    ('\U00016f50', '\U00016f50'),
+    ('\U0001b000', '\U0001b001'),
+    ('\U0001ee00', '\U0001ee03'),
+    ('\U0001ee05', '\U0001ee1f'),
+    ('\U0001ee21', '\U0001ee22'),
+    ('\U0001ee24', '\U0001ee24'),
+    ('\U0001ee27', '\U0001ee27'),
+    ('\U0001ee29', '\U0001ee32'),
+    ('\U0001ee34', '\U0001ee37'),
+    ('\U0001ee39', '\U0001ee39'),
+    ('\U0001ee3b', '\U0001ee3b'),
+    ('\U0001ee42', '\U0001ee42'),
+    ('\U0001ee47', '\U0001ee47'),
+    ('\U0001ee49', '\U0001ee49'),
+    ('\U0001ee4b', '\U0001ee4b'),
+    ('\U0001ee4d', '\U0001ee4f'),
+    ('\U0001ee51', '\U0001ee52'),
+    ('\U0001ee54', '\U0001ee54'),
+    ('\U0001ee57', '\U0001ee57'),
+    ('\U0001ee59', '\U0001ee59'),
+    ('\U0001ee5b', '\U0001ee5b'),
+    ('\U0001ee5d', '\U0001ee5d'),
+    ('\U0001ee5f', '\U0001ee5f'),
+    ('\U0001ee61', '\U0001ee62'),
+    ('\U0001ee64', '\U0001ee64'),
+    ('\U0001ee67', '\U0001ee6a'),
+    ('\U0001ee6c', '\U0001ee72'),
+    ('\U0001ee74', '\U0001ee77'),
+    ('\U0001ee79', '\U0001ee7c'),
+    ('\U0001ee7e', '\U0001ee7e'),
+    ('\U0001ee80', '\U0001ee89'),
+    ('\U0001ee8b', '\U0001ee9b'),
+    ('\U0001eea1', '\U0001eea3'),
+    ('\U0001eea5', '\U0001eea9'),
+    ('\U0001eeab', '\U0001eebb'),
+    ('\U00020000', '\U00020000'),
+    ('\U0002a6d6', '\U0002a6d6'),
+    ('\U0002a700', '\U0002a700'),
+    ('\U0002b734', '\U0002b734'),
+    ('\U0002b740', '\U0002b740'),
+    ('\U0002b81d', '\U0002b81d'),
+    ('\U0002f800', '\U0002fa1d')
+    ]),
+("Lt", &[
+    ('\U000001c5', '\U000001c5'),
+    ('\U000001c8', '\U000001c8'),
+    ('\U000001cb', '\U000001cb'),
+    ('\U000001f2', '\U000001f2'),
+    ('\U00001f88', '\U00001f8f'),
+    ('\U00001f98', '\U00001f9f'),
+    ('\U00001fa8', '\U00001faf'),
+    ('\U00001fbc', '\U00001fbc'),
+    ('\U00001fcc', '\U00001fcc'),
+    ('\U00001ffc', '\U00001ffc')
+    ]),
+("Lu", &[
+    ('\U00000041', '\U0000005a'),
+    ('\U000000c0', '\U000000d6'),
+    ('\U000000d8', '\U000000de'),
+    ('\U00000100', '\U00000100'),
+    ('\U00000102', '\U00000102'),
+    ('\U00000104', '\U00000104'),
+    ('\U00000106', '\U00000106'),
+    ('\U00000108', '\U00000108'),
+    ('\U0000010a', '\U0000010a'),
+    ('\U0000010c', '\U0000010c'),
+    ('\U0000010e', '\U0000010e'),
+    ('\U00000110', '\U00000110'),
+    ('\U00000112', '\U00000112'),
+    ('\U00000114', '\U00000114'),
+    ('\U00000116', '\U00000116'),
+    ('\U00000118', '\U00000118'),
+    ('\U0000011a', '\U0000011a'),
+    ('\U0000011c', '\U0000011c'),
+    ('\U0000011e', '\U0000011e'),
+    ('\U00000120', '\U00000120'),
+    ('\U00000122', '\U00000122'),
+    ('\U00000124', '\U00000124'),
+    ('\U00000126', '\U00000126'),
+    ('\U00000128', '\U00000128'),
+    ('\U0000012a', '\U0000012a'),
+    ('\U0000012c', '\U0000012c'),
+    ('\U0000012e', '\U0000012e'),
+    ('\U00000130', '\U00000130'),
+    ('\U00000132', '\U00000132'),
+    ('\U00000134', '\U00000134'),
+    ('\U00000136', '\U00000136'),
+    ('\U00000139', '\U00000139'),
+    ('\U0000013b', '\U0000013b'),
+    ('\U0000013d', '\U0000013d'),
+    ('\U0000013f', '\U0000013f'),
+    ('\U00000141', '\U00000141'),
+    ('\U00000143', '\U00000143'),
+    ('\U00000145', '\U00000145'),
+    ('\U00000147', '\U00000147'),
+    ('\U0000014a', '\U0000014a'),
+    ('\U0000014c', '\U0000014c'),
+    ('\U0000014e', '\U0000014e'),
+    ('\U00000150', '\U00000150'),
+    ('\U00000152', '\U00000152'),
+    ('\U00000154', '\U00000154'),
+    ('\U00000156', '\U00000156'),
+    ('\U00000158', '\U00000158'),
+    ('\U0000015a', '\U0000015a'),
+    ('\U0000015c', '\U0000015c'),
+    ('\U0000015e', '\U0000015e'),
+    ('\U00000160', '\U00000160'),
+    ('\U00000162', '\U00000162'),
+    ('\U00000164', '\U00000164'),
+    ('\U00000166', '\U00000166'),
+    ('\U00000168', '\U00000168'),
+    ('\U0000016a', '\U0000016a'),
+    ('\U0000016c', '\U0000016c'),
+    ('\U0000016e', '\U0000016e'),
+    ('\U00000170', '\U00000170'),
+    ('\U00000172', '\U00000172'),
+    ('\U00000174', '\U00000174'),
+    ('\U00000176', '\U00000176'),
+    ('\U00000178', '\U00000179'),
+    ('\U0000017b', '\U0000017b'),
+    ('\U0000017d', '\U0000017d'),
+    ('\U00000181', '\U00000182'),
+    ('\U00000184', '\U00000184'),
+    ('\U00000186', '\U00000187'),
+    ('\U00000189', '\U0000018b'),
+    ('\U0000018e', '\U00000191'),
+    ('\U00000193', '\U00000194'),
+    ('\U00000196', '\U00000198'),
+    ('\U0000019c', '\U0000019d'),
+    ('\U0000019f', '\U000001a0'),
+    ('\U000001a2', '\U000001a2'),
+    ('\U000001a4', '\U000001a4'),
+    ('\U000001a6', '\U000001a7'),
+    ('\U000001a9', '\U000001a9'),
+    ('\U000001ac', '\U000001ac'),
+    ('\U000001ae', '\U000001af'),
+    ('\U000001b1', '\U000001b3'),
+    ('\U000001b5', '\U000001b5'),
+    ('\U000001b7', '\U000001b8'),
+    ('\U000001bc', '\U000001bc'),
+    ('\U000001c4', '\U000001c4'),
+    ('\U000001c7', '\U000001c7'),
+    ('\U000001ca', '\U000001ca'),
+    ('\U000001cd', '\U000001cd'),
+    ('\U000001cf', '\U000001cf'),
+    ('\U000001d1', '\U000001d1'),
+    ('\U000001d3', '\U000001d3'),
+    ('\U000001d5', '\U000001d5'),
+    ('\U000001d7', '\U000001d7'),
+    ('\U000001d9', '\U000001d9'),
+    ('\U000001db', '\U000001db'),
+    ('\U000001de', '\U000001de'),
+    ('\U000001e0', '\U000001e0'),
+    ('\U000001e2', '\U000001e2'),
+    ('\U000001e4', '\U000001e4'),
+    ('\U000001e6', '\U000001e6'),
+    ('\U000001e8', '\U000001e8'),
+    ('\U000001ea', '\U000001ea'),
+    ('\U000001ec', '\U000001ec'),
+    ('\U000001ee', '\U000001ee'),
+    ('\U000001f1', '\U000001f1'),
+    ('\U000001f4', '\U000001f4'),
+    ('\U000001f6', '\U000001f8'),
+    ('\U000001fa', '\U000001fa'),
+    ('\U000001fc', '\U000001fc'),
+    ('\U000001fe', '\U000001fe'),
+    ('\U00000200', '\U00000200'),
+    ('\U00000202', '\U00000202'),
+    ('\U00000204', '\U00000204'),
+    ('\U00000206', '\U00000206'),
+    ('\U00000208', '\U00000208'),
+    ('\U0000020a', '\U0000020a'),
+    ('\U0000020c', '\U0000020c'),
+    ('\U0000020e', '\U0000020e'),
+    ('\U00000210', '\U00000210'),
+    ('\U00000212', '\U00000212'),
+    ('\U00000214', '\U00000214'),
+    ('\U00000216', '\U00000216'),
+    ('\U00000218', '\U00000218'),
+    ('\U0000021a', '\U0000021a'),
+    ('\U0000021c', '\U0000021c'),
+    ('\U0000021e', '\U0000021e'),
+    ('\U00000220', '\U00000220'),
+    ('\U00000222', '\U00000222'),
+    ('\U00000224', '\U00000224'),
+    ('\U00000226', '\U00000226'),
+    ('\U00000228', '\U00000228'),
+    ('\U0000022a', '\U0000022a'),
+    ('\U0000022c', '\U0000022c'),
+    ('\U0000022e', '\U0000022e'),
+    ('\U00000230', '\U00000230'),
+    ('\U00000232', '\U00000232'),
+    ('\U0000023a', '\U0000023b'),
+    ('\U0000023d', '\U0000023e'),
+    ('\U00000241', '\U00000241'),
+    ('\U00000243', '\U00000246'),
+    ('\U00000248', '\U00000248'),
+    ('\U0000024a', '\U0000024a'),
+    ('\U0000024c', '\U0000024c'),
+    ('\U0000024e', '\U0000024e'),
+    ('\U00000370', '\U00000370'),
+    ('\U00000372', '\U00000372'),
+    ('\U00000376', '\U00000376'),
+    ('\U00000386', '\U00000386'),
+    ('\U00000388', '\U0000038a'),
+    ('\U0000038c', '\U0000038c'),
+    ('\U0000038e', '\U0000038f'),
+    ('\U00000391', '\U000003a1'),
+    ('\U000003a3', '\U000003ab'),
+    ('\U000003cf', '\U000003cf'),
+    ('\U000003d2', '\U000003d4'),
+    ('\U000003d8', '\U000003d8'),
+    ('\U000003da', '\U000003da'),
+    ('\U000003dc', '\U000003dc'),
+    ('\U000003de', '\U000003de'),
+    ('\U000003e0', '\U000003e0'),
+    ('\U000003e2', '\U000003e2'),
+    ('\U000003e4', '\U000003e4'),
+    ('\U000003e6', '\U000003e6'),
+    ('\U000003e8', '\U000003e8'),
+    ('\U000003ea', '\U000003ea'),
+    ('\U000003ec', '\U000003ec'),
+    ('\U000003ee', '\U000003ee'),
+    ('\U000003f4', '\U000003f4'),
+    ('\U000003f7', '\U000003f7'),
+    ('\U000003f9', '\U000003fa'),
+    ('\U000003fd', '\U0000042f'),
+    ('\U00000460', '\U00000460'),
+    ('\U00000462', '\U00000462'),
+    ('\U00000464', '\U00000464'),
+    ('\U00000466', '\U00000466'),
+    ('\U00000468', '\U00000468'),
+    ('\U0000046a', '\U0000046a'),
+    ('\U0000046c', '\U0000046c'),
+    ('\U0000046e', '\U0000046e'),
+    ('\U00000470', '\U00000470'),
+    ('\U00000472', '\U00000472'),
+    ('\U00000474', '\U00000474'),
+    ('\U00000476', '\U00000476'),
+    ('\U00000478', '\U00000478'),
+    ('\U0000047a', '\U0000047a'),
+    ('\U0000047c', '\U0000047c'),
+    ('\U0000047e', '\U0000047e'),
+    ('\U00000480', '\U00000480'),
+    ('\U0000048a', '\U0000048a'),
+    ('\U0000048c', '\U0000048c'),
+    ('\U0000048e', '\U0000048e'),
+    ('\U00000490', '\U00000490'),
+    ('\U00000492', '\U00000492'),
+    ('\U00000494', '\U00000494'),
+    ('\U00000496', '\U00000496'),
+    ('\U00000498', '\U00000498'),
+    ('\U0000049a', '\U0000049a'),
+    ('\U0000049c', '\U0000049c'),
+    ('\U0000049e', '\U0000049e'),
+    ('\U000004a0', '\U000004a0'),
+    ('\U000004a2', '\U000004a2'),
+    ('\U000004a4', '\U000004a4'),
+    ('\U000004a6', '\U000004a6'),
+    ('\U000004a8', '\U000004a8'),
+    ('\U000004aa', '\U000004aa'),
+    ('\U000004ac', '\U000004ac'),
+    ('\U000004ae', '\U000004ae'),
+    ('\U000004b0', '\U000004b0'),
+    ('\U000004b2', '\U000004b2'),
+    ('\U000004b4', '\U000004b4'),
+    ('\U000004b6', '\U000004b6'),
+    ('\U000004b8', '\U000004b8'),
+    ('\U000004ba', '\U000004ba'),
+    ('\U000004bc', '\U000004bc'),
+    ('\U000004be', '\U000004be'),
+    ('\U000004c0', '\U000004c1'),
+    ('\U000004c3', '\U000004c3'),
+    ('\U000004c5', '\U000004c5'),
+    ('\U000004c7', '\U000004c7'),
+    ('\U000004c9', '\U000004c9'),
+    ('\U000004cb', '\U000004cb'),
+    ('\U000004cd', '\U000004cd'),
+    ('\U000004d0', '\U000004d0'),
+    ('\U000004d2', '\U000004d2'),
+    ('\U000004d4', '\U000004d4'),
+    ('\U000004d6', '\U000004d6'),
+    ('\U000004d8', '\U000004d8'),
+    ('\U000004da', '\U000004da'),
+    ('\U000004dc', '\U000004dc'),
+    ('\U000004de', '\U000004de'),
+    ('\U000004e0', '\U000004e0'),
+    ('\U000004e2', '\U000004e2'),
+    ('\U000004e4', '\U000004e4'),
+    ('\U000004e6', '\U000004e6'),
+    ('\U000004e8', '\U000004e8'),
+    ('\U000004ea', '\U000004ea'),
+    ('\U000004ec', '\U000004ec'),
+    ('\U000004ee', '\U000004ee'),
+    ('\U000004f0', '\U000004f0'),
+    ('\U000004f2', '\U000004f2'),
+    ('\U000004f4', '\U000004f4'),
+    ('\U000004f6', '\U000004f6'),
+    ('\U000004f8', '\U000004f8'),
+    ('\U000004fa', '\U000004fa'),
+    ('\U000004fc', '\U000004fc'),
+    ('\U000004fe', '\U000004fe'),
+    ('\U00000500', '\U00000500'),
+    ('\U00000502', '\U00000502'),
+    ('\U00000504', '\U00000504'),
+    ('\U00000506', '\U00000506'),
+    ('\U00000508', '\U00000508'),
+    ('\U0000050a', '\U0000050a'),
+    ('\U0000050c', '\U0000050c'),
+    ('\U0000050e', '\U0000050e'),
+    ('\U00000510', '\U00000510'),
+    ('\U00000512', '\U00000512'),
+    ('\U00000514', '\U00000514'),
+    ('\U00000516', '\U00000516'),
+    ('\U00000518', '\U00000518'),
+    ('\U0000051a', '\U0000051a'),
+    ('\U0000051c', '\U0000051c'),
+    ('\U0000051e', '\U0000051e'),
+    ('\U00000520', '\U00000520'),
+    ('\U00000522', '\U00000522'),
+    ('\U00000524', '\U00000524'),
+    ('\U00000526', '\U00000526'),
+    ('\U00000531', '\U00000556'),
+    ('\U000010a0', '\U000010c5'),
+    ('\U000010c7', '\U000010c7'),
+    ('\U000010cd', '\U000010cd'),
+    ('\U00001e00', '\U00001e00'),
+    ('\U00001e02', '\U00001e02'),
+    ('\U00001e04', '\U00001e04'),
+    ('\U00001e06', '\U00001e06'),
+    ('\U00001e08', '\U00001e08'),
+    ('\U00001e0a', '\U00001e0a'),
+    ('\U00001e0c', '\U00001e0c'),
+    ('\U00001e0e', '\U00001e0e'),
+    ('\U00001e10', '\U00001e10'),
+    ('\U00001e12', '\U00001e12'),
+    ('\U00001e14', '\U00001e14'),
+    ('\U00001e16', '\U00001e16'),
+    ('\U00001e18', '\U00001e18'),
+    ('\U00001e1a', '\U00001e1a'),
+    ('\U00001e1c', '\U00001e1c'),
+    ('\U00001e1e', '\U00001e1e'),
+    ('\U00001e20', '\U00001e20'),
+    ('\U00001e22', '\U00001e22'),
+    ('\U00001e24', '\U00001e24'),
+    ('\U00001e26', '\U00001e26'),
+    ('\U00001e28', '\U00001e28'),
+    ('\U00001e2a', '\U00001e2a'),
+    ('\U00001e2c', '\U00001e2c'),
+    ('\U00001e2e', '\U00001e2e'),
+    ('\U00001e30', '\U00001e30'),
+    ('\U00001e32', '\U00001e32'),
+    ('\U00001e34', '\U00001e34'),
+    ('\U00001e36', '\U00001e36'),
+    ('\U00001e38', '\U00001e38'),
+    ('\U00001e3a', '\U00001e3a'),
+    ('\U00001e3c', '\U00001e3c'),
+    ('\U00001e3e', '\U00001e3e'),
+    ('\U00001e40', '\U00001e40'),
+    ('\U00001e42', '\U00001e42'),
+    ('\U00001e44', '\U00001e44'),
+    ('\U00001e46', '\U00001e46'),
+    ('\U00001e48', '\U00001e48'),
+    ('\U00001e4a', '\U00001e4a'),
+    ('\U00001e4c', '\U00001e4c'),
+    ('\U00001e4e', '\U00001e4e'),
+    ('\U00001e50', '\U00001e50'),
+    ('\U00001e52', '\U00001e52'),
+    ('\U00001e54', '\U00001e54'),
+    ('\U00001e56', '\U00001e56'),
+    ('\U00001e58', '\U00001e58'),
+    ('\U00001e5a', '\U00001e5a'),
+    ('\U00001e5c', '\U00001e5c'),
+    ('\U00001e5e', '\U00001e5e'),
+    ('\U00001e60', '\U00001e60'),
+    ('\U00001e62', '\U00001e62'),
+    ('\U00001e64', '\U00001e64'),
+    ('\U00001e66', '\U00001e66'),
+    ('\U00001e68', '\U00001e68'),
+    ('\U00001e6a', '\U00001e6a'),
+    ('\U00001e6c', '\U00001e6c'),
+    ('\U00001e6e', '\U00001e6e'),
+    ('\U00001e70', '\U00001e70'),
+    ('\U00001e72', '\U00001e72'),
+    ('\U00001e74', '\U00001e74'),
+    ('\U00001e76', '\U00001e76'),
+    ('\U00001e78', '\U00001e78'),
+    ('\U00001e7a', '\U00001e7a'),
+    ('\U00001e7c', '\U00001e7c'),
+    ('\U00001e7e', '\U00001e7e'),
+    ('\U00001e80', '\U00001e80'),
+    ('\U00001e82', '\U00001e82'),
+    ('\U00001e84', '\U00001e84'),
+    ('\U00001e86', '\U00001e86'),
+    ('\U00001e88', '\U00001e88'),
+    ('\U00001e8a', '\U00001e8a'),
+    ('\U00001e8c', '\U00001e8c'),
+    ('\U00001e8e', '\U00001e8e'),
+    ('\U00001e90', '\U00001e90'),
+    ('\U00001e92', '\U00001e92'),
+    ('\U00001e94', '\U00001e94'),
+    ('\U00001e9e', '\U00001e9e'),
+    ('\U00001ea0', '\U00001ea0'),
+    ('\U00001ea2', '\U00001ea2'),
+    ('\U00001ea4', '\U00001ea4'),
+    ('\U00001ea6', '\U00001ea6'),
+    ('\U00001ea8', '\U00001ea8'),
+    ('\U00001eaa', '\U00001eaa'),
+    ('\U00001eac', '\U00001eac'),
+    ('\U00001eae', '\U00001eae'),
+    ('\U00001eb0', '\U00001eb0'),
+    ('\U00001eb2', '\U00001eb2'),
+    ('\U00001eb4', '\U00001eb4'),
+    ('\U00001eb6', '\U00001eb6'),
+    ('\U00001eb8', '\U00001eb8'),
+    ('\U00001eba', '\U00001eba'),
+    ('\U00001ebc', '\U00001ebc'),
+    ('\U00001ebe', '\U00001ebe'),
+    ('\U00001ec0', '\U00001ec0'),
+    ('\U00001ec2', '\U00001ec2'),
+    ('\U00001ec4', '\U00001ec4'),
+    ('\U00001ec6', '\U00001ec6'),
+    ('\U00001ec8', '\U00001ec8'),
+    ('\U00001eca', '\U00001eca'),
+    ('\U00001ecc', '\U00001ecc'),
+    ('\U00001ece', '\U00001ece'),
+    ('\U00001ed0', '\U00001ed0'),
+    ('\U00001ed2', '\U00001ed2'),
+    ('\U00001ed4', '\U00001ed4'),
+    ('\U00001ed6', '\U00001ed6'),
+    ('\U00001ed8', '\U00001ed8'),
+    ('\U00001eda', '\U00001eda'),
+    ('\U00001edc', '\U00001edc'),
+    ('\U00001ede', '\U00001ede'),
+    ('\U00001ee0', '\U00001ee0'),
+    ('\U00001ee2', '\U00001ee2'),
+    ('\U00001ee4', '\U00001ee4'),
+    ('\U00001ee6', '\U00001ee6'),
+    ('\U00001ee8', '\U00001ee8'),
+    ('\U00001eea', '\U00001eea'),
+    ('\U00001eec', '\U00001eec'),
+    ('\U00001eee', '\U00001eee'),
+    ('\U00001ef0', '\U00001ef0'),
+    ('\U00001ef2', '\U00001ef2'),
+    ('\U00001ef4', '\U00001ef4'),
+    ('\U00001ef6', '\U00001ef6'),
+    ('\U00001ef8', '\U00001ef8'),
+    ('\U00001efa', '\U00001efa'),
+    ('\U00001efc', '\U00001efc'),
+    ('\U00001efe', '\U00001efe'),
+    ('\U00001f08', '\U00001f0f'),
+    ('\U00001f18', '\U00001f1d'),
+    ('\U00001f28', '\U00001f2f'),
+    ('\U00001f38', '\U00001f3f'),
+    ('\U00001f48', '\U00001f4d'),
+    ('\U00001f59', '\U00001f59'),
+    ('\U00001f5b', '\U00001f5b'),
+    ('\U00001f5d', '\U00001f5d'),
+    ('\U00001f5f', '\U00001f5f'),
+    ('\U00001f68', '\U00001f6f'),
+    ('\U00001fb8', '\U00001fbb'),
+    ('\U00001fc8', '\U00001fcb'),
+    ('\U00001fd8', '\U00001fdb'),
+    ('\U00001fe8', '\U00001fec'),
+    ('\U00001ff8', '\U00001ffb'),
+    ('\U00002102', '\U00002102'),
+    ('\U00002107', '\U00002107'),
+    ('\U0000210b', '\U0000210d'),
+    ('\U00002110', '\U00002112'),
+    ('\U00002115', '\U00002115'),
+    ('\U00002119', '\U0000211d'),
+    ('\U00002124', '\U00002124'),
+    ('\U00002126', '\U00002126'),
+    ('\U00002128', '\U00002128'),
+    ('\U0000212a', '\U0000212d'),
+    ('\U00002130', '\U00002133'),
+    ('\U0000213e', '\U0000213f'),
+    ('\U00002145', '\U00002145'),
+    ('\U00002183', '\U00002183'),
+    ('\U00002c00', '\U00002c2e'),
+    ('\U00002c60', '\U00002c60'),
+    ('\U00002c62', '\U00002c64'),
+    ('\U00002c67', '\U00002c67'),
+    ('\U00002c69', '\U00002c69'),
+    ('\U00002c6b', '\U00002c6b'),
+    ('\U00002c6d', '\U00002c70'),
+    ('\U00002c72', '\U00002c72'),
+    ('\U00002c75', '\U00002c75'),
+    ('\U00002c7e', '\U00002c80'),
+    ('\U00002c82', '\U00002c82'),
+    ('\U00002c84', '\U00002c84'),
+    ('\U00002c86', '\U00002c86'),
+    ('\U00002c88', '\U00002c88'),
+    ('\U00002c8a', '\U00002c8a'),
+    ('\U00002c8c', '\U00002c8c'),
+    ('\U00002c8e', '\U00002c8e'),
+    ('\U00002c90', '\U00002c90'),
+    ('\U00002c92', '\U00002c92'),
+    ('\U00002c94', '\U00002c94'),
+    ('\U00002c96', '\U00002c96'),
+    ('\U00002c98', '\U00002c98'),
+    ('\U00002c9a', '\U00002c9a'),
+    ('\U00002c9c', '\U00002c9c'),
+    ('\U00002c9e', '\U00002c9e'),
+    ('\U00002ca0', '\U00002ca0'),
+    ('\U00002ca2', '\U00002ca2'),
+    ('\U00002ca4', '\U00002ca4'),
+    ('\U00002ca6', '\U00002ca6'),
+    ('\U00002ca8', '\U00002ca8'),
+    ('\U00002caa', '\U00002caa'),
+    ('\U00002cac', '\U00002cac'),
+    ('\U00002cae', '\U00002cae'),
+    ('\U00002cb0', '\U00002cb0'),
+    ('\U00002cb2', '\U00002cb2'),
+    ('\U00002cb4', '\U00002cb4'),
+    ('\U00002cb6', '\U00002cb6'),
+    ('\U00002cb8', '\U00002cb8'),
+    ('\U00002cba', '\U00002cba'),
+    ('\U00002cbc', '\U00002cbc'),
+    ('\U00002cbe', '\U00002cbe'),
+    ('\U00002cc0', '\U00002cc0'),
+    ('\U00002cc2', '\U00002cc2'),
+    ('\U00002cc4', '\U00002cc4'),
+    ('\U00002cc6', '\U00002cc6'),
+    ('\U00002cc8', '\U00002cc8'),
+    ('\U00002cca', '\U00002cca'),
+    ('\U00002ccc', '\U00002ccc'),
+    ('\U00002cce', '\U00002cce'),
+    ('\U00002cd0', '\U00002cd0'),
+    ('\U00002cd2', '\U00002cd2'),
+    ('\U00002cd4', '\U00002cd4'),
+    ('\U00002cd6', '\U00002cd6'),
+    ('\U00002cd8', '\U00002cd8'),
+    ('\U00002cda', '\U00002cda'),
+    ('\U00002cdc', '\U00002cdc'),
+    ('\U00002cde', '\U00002cde'),
+    ('\U00002ce0', '\U00002ce0'),
+    ('\U00002ce2', '\U00002ce2'),
+    ('\U00002ceb', '\U00002ceb'),
+    ('\U00002ced', '\U00002ced'),
+    ('\U00002cf2', '\U00002cf2'),
+    ('\U0000a640', '\U0000a640'),
+    ('\U0000a642', '\U0000a642'),
+    ('\U0000a644', '\U0000a644'),
+    ('\U0000a646', '\U0000a646'),
+    ('\U0000a648', '\U0000a648'),
+    ('\U0000a64a', '\U0000a64a'),
+    ('\U0000a64c', '\U0000a64c'),
+    ('\U0000a64e', '\U0000a64e'),
+    ('\U0000a650', '\U0000a650'),
+    ('\U0000a652', '\U0000a652'),
+    ('\U0000a654', '\U0000a654'),
+    ('\U0000a656', '\U0000a656'),
+    ('\U0000a658', '\U0000a658'),
+    ('\U0000a65a', '\U0000a65a'),
+    ('\U0000a65c', '\U0000a65c'),
+    ('\U0000a65e', '\U0000a65e'),
+    ('\U0000a660', '\U0000a660'),
+    ('\U0000a662', '\U0000a662'),
+    ('\U0000a664', '\U0000a664'),
+    ('\U0000a666', '\U0000a666'),
+    ('\U0000a668', '\U0000a668'),
+    ('\U0000a66a', '\U0000a66a'),
+    ('\U0000a66c', '\U0000a66c'),
+    ('\U0000a680', '\U0000a680'),
+    ('\U0000a682', '\U0000a682'),
+    ('\U0000a684', '\U0000a684'),
+    ('\U0000a686', '\U0000a686'),
+    ('\U0000a688', '\U0000a688'),
+    ('\U0000a68a', '\U0000a68a'),
+    ('\U0000a68c', '\U0000a68c'),
+    ('\U0000a68e', '\U0000a68e'),
+    ('\U0000a690', '\U0000a690'),
+    ('\U0000a692', '\U0000a692'),
+    ('\U0000a694', '\U0000a694'),
+    ('\U0000a696', '\U0000a696'),
+    ('\U0000a722', '\U0000a722'),
+    ('\U0000a724', '\U0000a724'),
+    ('\U0000a726', '\U0000a726'),
+    ('\U0000a728', '\U0000a728'),
+    ('\U0000a72a', '\U0000a72a'),
+    ('\U0000a72c', '\U0000a72c'),
+    ('\U0000a72e', '\U0000a72e'),
+    ('\U0000a732', '\U0000a732'),
+    ('\U0000a734', '\U0000a734'),
+    ('\U0000a736', '\U0000a736'),
+    ('\U0000a738', '\U0000a738'),
+    ('\U0000a73a', '\U0000a73a'),
+    ('\U0000a73c', '\U0000a73c'),
+    ('\U0000a73e', '\U0000a73e'),
+    ('\U0000a740', '\U0000a740'),
+    ('\U0000a742', '\U0000a742'),
+    ('\U0000a744', '\U0000a744'),
+    ('\U0000a746', '\U0000a746'),
+    ('\U0000a748', '\U0000a748'),
+    ('\U0000a74a', '\U0000a74a'),
+    ('\U0000a74c', '\U0000a74c'),
+    ('\U0000a74e', '\U0000a74e'),
+    ('\U0000a750', '\U0000a750'),
+    ('\U0000a752', '\U0000a752'),
+    ('\U0000a754', '\U0000a754'),
+    ('\U0000a756', '\U0000a756'),
+    ('\U0000a758', '\U0000a758'),
+    ('\U0000a75a', '\U0000a75a'),
+    ('\U0000a75c', '\U0000a75c'),
+    ('\U0000a75e', '\U0000a75e'),
+    ('\U0000a760', '\U0000a760'),
+    ('\U0000a762', '\U0000a762'),
+    ('\U0000a764', '\U0000a764'),
+    ('\U0000a766', '\U0000a766'),
+    ('\U0000a768', '\U0000a768'),
+    ('\U0000a76a', '\U0000a76a'),
+    ('\U0000a76c', '\U0000a76c'),
+    ('\U0000a76e', '\U0000a76e'),
+    ('\U0000a779', '\U0000a779'),
+    ('\U0000a77b', '\U0000a77b'),
+    ('\U0000a77d', '\U0000a77e'),
+    ('\U0000a780', '\U0000a780'),
+    ('\U0000a782', '\U0000a782'),
+    ('\U0000a784', '\U0000a784'),
+    ('\U0000a786', '\U0000a786'),
+    ('\U0000a78b', '\U0000a78b'),
+    ('\U0000a78d', '\U0000a78d'),
+    ('\U0000a790', '\U0000a790'),
+    ('\U0000a792', '\U0000a792'),
+    ('\U0000a7a0', '\U0000a7a0'),
+    ('\U0000a7a2', '\U0000a7a2'),
+    ('\U0000a7a4', '\U0000a7a4'),
+    ('\U0000a7a6', '\U0000a7a6'),
+    ('\U0000a7a8', '\U0000a7a8'),
+    ('\U0000a7aa', '\U0000a7aa'),
+    ('\U0000ff21', '\U0000ff3a'),
+    ('\U00010400', '\U00010427'),
+    ('\U0001d400', '\U0001d419'),
+    ('\U0001d434', '\U0001d44d'),
+    ('\U0001d468', '\U0001d481'),
+    ('\U0001d49c', '\U0001d49c'),
+    ('\U0001d49e', '\U0001d49f'),
+    ('\U0001d4a2', '\U0001d4a2'),
+    ('\U0001d4a5', '\U0001d4a6'),
+    ('\U0001d4a9', '\U0001d4ac'),
+    ('\U0001d4ae', '\U0001d4b5'),
+    ('\U0001d4d0', '\U0001d4e9'),
+    ('\U0001d504', '\U0001d505'),
+    ('\U0001d507', '\U0001d50a'),
+    ('\U0001d50d', '\U0001d514'),
+    ('\U0001d516', '\U0001d51c'),
+    ('\U0001d538', '\U0001d539'),
+    ('\U0001d53b', '\U0001d53e'),
+    ('\U0001d540', '\U0001d544'),
+    ('\U0001d546', '\U0001d546'),
+    ('\U0001d54a', '\U0001d550'),
+    ('\U0001d56c', '\U0001d585'),
+    ('\U0001d5a0', '\U0001d5b9'),
+    ('\U0001d5d4', '\U0001d5ed'),
+    ('\U0001d608', '\U0001d621'),
+    ('\U0001d63c', '\U0001d655'),
+    ('\U0001d670', '\U0001d689'),
+    ('\U0001d6a8', '\U0001d6c0'),
+    ('\U0001d6e2', '\U0001d6fa'),
+    ('\U0001d71c', '\U0001d734'),
+    ('\U0001d756', '\U0001d76e'),
+    ('\U0001d790', '\U0001d7a8'),
+    ('\U0001d7ca', '\U0001d7ca')
+    ]),
+("Lycian", &[
+    ('\U00010280', '\U0001029c')
+    ]),
+("Lydian", &[
+    ('\U00010920', '\U00010939'),
+    ('\U0001093f', '\U0001093f')
+    ]),
+("M", &[
+    ('\U00000300', '\U0000036f'),
+    ('\U00000483', '\U00000489'),
+    ('\U00000591', '\U000005bd'),
+    ('\U000005bf', '\U000005bf'),
+    ('\U000005c1', '\U000005c2'),
+    ('\U000005c4', '\U000005c5'),
+    ('\U000005c7', '\U000005c7'),
+    ('\U00000610', '\U0000061a'),
+    ('\U0000064b', '\U0000065f'),
+    ('\U00000670', '\U00000670'),
+    ('\U000006d6', '\U000006dc'),
+    ('\U000006df', '\U000006e4'),
+    ('\U000006e7', '\U000006e8'),
+    ('\U000006ea', '\U000006ed'),
+    ('\U00000711', '\U00000711'),
+    ('\U00000730', '\U0000074a'),
+    ('\U000007a6', '\U000007b0'),
+    ('\U000007eb', '\U000007f3'),
+    ('\U00000816', '\U00000819'),
+    ('\U0000081b', '\U00000823'),
+    ('\U00000825', '\U00000827'),
+    ('\U00000829', '\U0000082d'),
+    ('\U00000859', '\U0000085b'),
+    ('\U000008e4', '\U000008fe'),
+    ('\U00000900', '\U00000903'),
+    ('\U0000093a', '\U0000093c'),
+    ('\U0000093e', '\U0000094f'),
+    ('\U00000951', '\U00000957'),
+    ('\U00000962', '\U00000963'),
+    ('\U00000981', '\U00000983'),
+    ('\U000009bc', '\U000009bc'),
+    ('\U000009be', '\U000009c4'),
+    ('\U000009c7', '\U000009c8'),
+    ('\U000009cb', '\U000009cd'),
+    ('\U000009d7', '\U000009d7'),
+    ('\U000009e2', '\U000009e3'),
+    ('\U00000a01', '\U00000a03'),
+    ('\U00000a3c', '\U00000a3c'),
+    ('\U00000a3e', '\U00000a42'),
+    ('\U00000a47', '\U00000a48'),
+    ('\U00000a4b', '\U00000a4d'),
+    ('\U00000a51', '\U00000a51'),
+    ('\U00000a70', '\U00000a71'),
+    ('\U00000a75', '\U00000a75'),
+    ('\U00000a81', '\U00000a83'),
+    ('\U00000abc', '\U00000abc'),
+    ('\U00000abe', '\U00000ac5'),
+    ('\U00000ac7', '\U00000ac9'),
+    ('\U00000acb', '\U00000acd'),
+    ('\U00000ae2', '\U00000ae3'),
+    ('\U00000b01', '\U00000b03'),
+    ('\U00000b3c', '\U00000b3c'),
+    ('\U00000b3e', '\U00000b44'),
+    ('\U00000b47', '\U00000b48'),
+    ('\U00000b4b', '\U00000b4d'),
+    ('\U00000b56', '\U00000b57'),
+    ('\U00000b62', '\U00000b63'),
+    ('\U00000b82', '\U00000b82'),
+    ('\U00000bbe', '\U00000bc2'),
+    ('\U00000bc6', '\U00000bc8'),
+    ('\U00000bca', '\U00000bcd'),
+    ('\U00000bd7', '\U00000bd7'),
+    ('\U00000c01', '\U00000c03'),
+    ('\U00000c3e', '\U00000c44'),
+    ('\U00000c46', '\U00000c48'),
+    ('\U00000c4a', '\U00000c4d'),
+    ('\U00000c55', '\U00000c56'),
+    ('\U00000c62', '\U00000c63'),
+    ('\U00000c82', '\U00000c83'),
+    ('\U00000cbc', '\U00000cbc'),
+    ('\U00000cbe', '\U00000cc4'),
+    ('\U00000cc6', '\U00000cc8'),
+    ('\U00000cca', '\U00000ccd'),
+    ('\U00000cd5', '\U00000cd6'),
+    ('\U00000ce2', '\U00000ce3'),
+    ('\U00000d02', '\U00000d03'),
+    ('\U00000d3e', '\U00000d44'),
+    ('\U00000d46', '\U00000d48'),
+    ('\U00000d4a', '\U00000d4d'),
+    ('\U00000d57', '\U00000d57'),
+    ('\U00000d62', '\U00000d63'),
+    ('\U00000d82', '\U00000d83'),
+    ('\U00000dca', '\U00000dca'),
+    ('\U00000dcf', '\U00000dd4'),
+    ('\U00000dd6', '\U00000dd6'),
+    ('\U00000dd8', '\U00000ddf'),
+    ('\U00000df2', '\U00000df3'),
+    ('\U00000e31', '\U00000e31'),
+    ('\U00000e34', '\U00000e3a'),
+    ('\U00000e47', '\U00000e4e'),
+    ('\U00000eb1', '\U00000eb1'),
+    ('\U00000eb4', '\U00000eb9'),
+    ('\U00000ebb', '\U00000ebc'),
+    ('\U00000ec8', '\U00000ecd'),
+    ('\U00000f18', '\U00000f19'),
+    ('\U00000f35', '\U00000f35'),
+    ('\U00000f37', '\U00000f37'),
+    ('\U00000f39', '\U00000f39'),
+    ('\U00000f3e', '\U00000f3f'),
+    ('\U00000f71', '\U00000f84'),
+    ('\U00000f86', '\U00000f87'),
+    ('\U00000f8d', '\U00000f97'),
+    ('\U00000f99', '\U00000fbc'),
+    ('\U00000fc6', '\U00000fc6'),
+    ('\U0000102b', '\U0000103e'),
+    ('\U00001056', '\U00001059'),
+    ('\U0000105e', '\U00001060'),
+    ('\U00001062', '\U00001064'),
+    ('\U00001067', '\U0000106d'),
+    ('\U00001071', '\U00001074'),
+    ('\U00001082', '\U0000108d'),
+    ('\U0000108f', '\U0000108f'),
+    ('\U0000109a', '\U0000109d'),
+    ('\U0000135d', '\U0000135f'),
+    ('\U00001712', '\U00001714'),
+    ('\U00001732', '\U00001734'),
+    ('\U00001752', '\U00001753'),
+    ('\U00001772', '\U00001773'),
+    ('\U000017b4', '\U000017d3'),
+    ('\U000017dd', '\U000017dd'),
+    ('\U0000180b', '\U0000180d'),
+    ('\U000018a9', '\U000018a9'),
+    ('\U00001920', '\U0000192b'),
+    ('\U00001930', '\U0000193b'),
+    ('\U000019b0', '\U000019c0'),
+    ('\U000019c8', '\U000019c9'),
+    ('\U00001a17', '\U00001a1b'),
+    ('\U00001a55', '\U00001a5e'),
+    ('\U00001a60', '\U00001a7c'),
+    ('\U00001a7f', '\U00001a7f'),
+    ('\U00001b00', '\U00001b04'),
+    ('\U00001b34', '\U00001b44'),
+    ('\U00001b6b', '\U00001b73'),
+    ('\U00001b80', '\U00001b82'),
+    ('\U00001ba1', '\U00001bad'),
+    ('\U00001be6', '\U00001bf3'),
+    ('\U00001c24', '\U00001c37'),
+    ('\U00001cd0', '\U00001cd2'),
+    ('\U00001cd4', '\U00001ce8'),
+    ('\U00001ced', '\U00001ced'),
+    ('\U00001cf2', '\U00001cf4'),
+    ('\U00001dc0', '\U00001de6'),
+    ('\U00001dfc', '\U00001dff'),
+    ('\U000020d0', '\U000020f0'),
+    ('\U00002cef', '\U00002cf1'),
+    ('\U00002d7f', '\U00002d7f'),
+    ('\U00002de0', '\U00002dff'),
+    ('\U0000302a', '\U0000302f'),
+    ('\U00003099', '\U0000309a'),
+    ('\U0000a66f', '\U0000a672'),
+    ('\U0000a674', '\U0000a67d'),
+    ('\U0000a69f', '\U0000a69f'),
+    ('\U0000a6f0', '\U0000a6f1'),
+    ('\U0000a802', '\U0000a802'),
+    ('\U0000a806', '\U0000a806'),
+    ('\U0000a80b', '\U0000a80b'),
+    ('\U0000a823', '\U0000a827'),
+    ('\U0000a880', '\U0000a881'),
+    ('\U0000a8b4', '\U0000a8c4'),
+    ('\U0000a8e0', '\U0000a8f1'),
+    ('\U0000a926', '\U0000a92d'),
+    ('\U0000a947', '\U0000a953'),
+    ('\U0000a980', '\U0000a983'),
+    ('\U0000a9b3', '\U0000a9c0'),
+    ('\U0000aa29', '\U0000aa36'),
+    ('\U0000aa43', '\U0000aa43'),
+    ('\U0000aa4c', '\U0000aa4d'),
+    ('\U0000aa7b', '\U0000aa7b'),
+    ('\U0000aab0', '\U0000aab0'),
+    ('\U0000aab2', '\U0000aab4'),
+    ('\U0000aab7', '\U0000aab8'),
+    ('\U0000aabe', '\U0000aabf'),
+    ('\U0000aac1', '\U0000aac1'),
+    ('\U0000aaeb', '\U0000aaef'),
+    ('\U0000aaf5', '\U0000aaf6'),
+    ('\U0000abe3', '\U0000abea'),
+    ('\U0000abec', '\U0000abed'),
+    ('\U0000fb1e', '\U0000fb1e'),
+    ('\U0000fe00', '\U0000fe0f'),
+    ('\U0000fe20', '\U0000fe26'),
+    ('\U000101fd', '\U000101fd'),
+    ('\U00010a01', '\U00010a03'),
+    ('\U00010a05', '\U00010a06'),
+    ('\U00010a0c', '\U00010a0f'),
+    ('\U00010a38', '\U00010a3a'),
+    ('\U00010a3f', '\U00010a3f'),
+    ('\U00011000', '\U00011002'),
+    ('\U00011038', '\U00011046'),
+    ('\U00011080', '\U00011082'),
+    ('\U000110b0', '\U000110ba'),
+    ('\U00011100', '\U00011102'),
+    ('\U00011127', '\U00011134'),
+    ('\U00011180', '\U00011182'),
+    ('\U000111b3', '\U000111c0'),
+    ('\U000116ab', '\U000116b7'),
+    ('\U00016f51', '\U00016f7e'),
+    ('\U00016f8f', '\U00016f92'),
+    ('\U0001d165', '\U0001d169'),
+    ('\U0001d16d', '\U0001d172'),
+    ('\U0001d17b', '\U0001d182'),
+    ('\U0001d185', '\U0001d18b'),
+    ('\U0001d1aa', '\U0001d1ad'),
+    ('\U0001d242', '\U0001d244'),
+    ('\U000e0100', '\U000e01ef')
+    ]),
+("Malayalam", &[
+    ('\U00000d02', '\U00000d03'),
+    ('\U00000d05', '\U00000d0c'),
+    ('\U00000d0e', '\U00000d10'),
+    ('\U00000d12', '\U00000d3a'),
+    ('\U00000d3d', '\U00000d44'),
+    ('\U00000d46', '\U00000d48'),
+    ('\U00000d4a', '\U00000d4e'),
+    ('\U00000d57', '\U00000d57'),
+    ('\U00000d60', '\U00000d63'),
+    ('\U00000d66', '\U00000d75'),
+    ('\U00000d79', '\U00000d7f')
+    ]),
+("Mandaic", &[
+    ('\U00000840', '\U0000085b'),
+    ('\U0000085e', '\U0000085e')
+    ]),
+("Mc", &[
+    ('\U00000903', '\U00000903'),
+    ('\U0000093b', '\U0000093b'),
+    ('\U0000093e', '\U00000940'),
+    ('\U00000949', '\U0000094c'),
+    ('\U0000094e', '\U0000094f'),
+    ('\U00000982', '\U00000983'),
+    ('\U000009be', '\U000009c0'),
+    ('\U000009c7', '\U000009c8'),
+    ('\U000009cb', '\U000009cc'),
+    ('\U000009d7', '\U000009d7'),
+    ('\U00000a03', '\U00000a03'),
+    ('\U00000a3e', '\U00000a40'),
+    ('\U00000a83', '\U00000a83'),
+    ('\U00000abe', '\U00000ac0'),
+    ('\U00000ac9', '\U00000ac9'),
+    ('\U00000acb', '\U00000acc'),
+    ('\U00000b02', '\U00000b03'),
+    ('\U00000b3e', '\U00000b3e'),
+    ('\U00000b40', '\U00000b40'),
+    ('\U00000b47', '\U00000b48'),
+    ('\U00000b4b', '\U00000b4c'),
+    ('\U00000b57', '\U00000b57'),
+    ('\U00000bbe', '\U00000bbf'),
+    ('\U00000bc1', '\U00000bc2'),
+    ('\U00000bc6', '\U00000bc8'),
+    ('\U00000bca', '\U00000bcc'),
+    ('\U00000bd7', '\U00000bd7'),
+    ('\U00000c01', '\U00000c03'),
+    ('\U00000c41', '\U00000c44'),
+    ('\U00000c82', '\U00000c83'),
+    ('\U00000cbe', '\U00000cbe'),
+    ('\U00000cc0', '\U00000cc4'),
+    ('\U00000cc7', '\U00000cc8'),
+    ('\U00000cca', '\U00000ccb'),
+    ('\U00000cd5', '\U00000cd6'),
+    ('\U00000d02', '\U00000d03'),
+    ('\U00000d3e', '\U00000d40'),
+    ('\U00000d46', '\U00000d48'),
+    ('\U00000d4a', '\U00000d4c'),
+    ('\U00000d57', '\U00000d57'),
+    ('\U00000d82', '\U00000d83'),
+    ('\U00000dcf', '\U00000dd1'),
+    ('\U00000dd8', '\U00000ddf'),
+    ('\U00000df2', '\U00000df3'),
+    ('\U00000f3e', '\U00000f3f'),
+    ('\U00000f7f', '\U00000f7f'),
+    ('\U0000102b', '\U0000102c'),
+    ('\U00001031', '\U00001031'),
+    ('\U00001038', '\U00001038'),
+    ('\U0000103b', '\U0000103c'),
+    ('\U00001056', '\U00001057'),
+    ('\U00001062', '\U00001064'),
+    ('\U00001067', '\U0000106d'),
+    ('\U00001083', '\U00001084'),
+    ('\U00001087', '\U0000108c'),
+    ('\U0000108f', '\U0000108f'),
+    ('\U0000109a', '\U0000109c'),
+    ('\U000017b6', '\U000017b6'),
+    ('\U000017be', '\U000017c5'),
+    ('\U000017c7', '\U000017c8'),
+    ('\U00001923', '\U00001926'),
+    ('\U00001929', '\U0000192b'),
+    ('\U00001930', '\U00001931'),
+    ('\U00001933', '\U00001938'),
+    ('\U000019b0', '\U000019c0'),
+    ('\U000019c8', '\U000019c9'),
+    ('\U00001a19', '\U00001a1a'),
+    ('\U00001a55', '\U00001a55'),
+    ('\U00001a57', '\U00001a57'),
+    ('\U00001a61', '\U00001a61'),
+    ('\U00001a63', '\U00001a64'),
+    ('\U00001a6d', '\U00001a72'),
+    ('\U00001b04', '\U00001b04'),
+    ('\U00001b35', '\U00001b35'),
+    ('\U00001b3b', '\U00001b3b'),
+    ('\U00001b3d', '\U00001b41'),
+    ('\U00001b43', '\U00001b44'),
+    ('\U00001b82', '\U00001b82'),
+    ('\U00001ba1', '\U00001ba1'),
+    ('\U00001ba6', '\U00001ba7'),
+    ('\U00001baa', '\U00001baa'),
+    ('\U00001bac', '\U00001bad'),
+    ('\U00001be7', '\U00001be7'),
+    ('\U00001bea', '\U00001bec'),
+    ('\U00001bee', '\U00001bee'),
+    ('\U00001bf2', '\U00001bf3'),
+    ('\U00001c24', '\U00001c2b'),
+    ('\U00001c34', '\U00001c35'),
+    ('\U00001ce1', '\U00001ce1'),
+    ('\U00001cf2', '\U00001cf3'),
+    ('\U0000302e', '\U0000302f'),
+    ('\U0000a823', '\U0000a824'),
+    ('\U0000a827', '\U0000a827'),
+    ('\U0000a880', '\U0000a881'),
+    ('\U0000a8b4', '\U0000a8c3'),
+    ('\U0000a952', '\U0000a953'),
+    ('\U0000a983', '\U0000a983'),
+    ('\U0000a9b4', '\U0000a9b5'),
+    ('\U0000a9ba', '\U0000a9bb'),
+    ('\U0000a9bd', '\U0000a9c0'),
+    ('\U0000aa2f', '\U0000aa30'),
+    ('\U0000aa33', '\U0000aa34'),
+    ('\U0000aa4d', '\U0000aa4d'),
+    ('\U0000aa7b', '\U0000aa7b'),
+    ('\U0000aaeb', '\U0000aaeb'),
+    ('\U0000aaee', '\U0000aaef'),
+    ('\U0000aaf5', '\U0000aaf5'),
+    ('\U0000abe3', '\U0000abe4'),
+    ('\U0000abe6', '\U0000abe7'),
+    ('\U0000abe9', '\U0000abea'),
+    ('\U0000abec', '\U0000abec'),
+    ('\U00011000', '\U00011000'),
+    ('\U00011002', '\U00011002'),
+    ('\U00011082', '\U00011082'),
+    ('\U000110b0', '\U000110b2'),
+    ('\U000110b7', '\U000110b8'),
+    ('\U0001112c', '\U0001112c'),
+    ('\U00011182', '\U00011182'),
+    ('\U000111b3', '\U000111b5'),
+    ('\U000111bf', '\U000111c0'),
+    ('\U000116ac', '\U000116ac'),
+    ('\U000116ae', '\U000116af'),
+    ('\U000116b6', '\U000116b6'),
+    ('\U00016f51', '\U00016f7e'),
+    ('\U0001d165', '\U0001d166'),
+    ('\U0001d16d', '\U0001d172')
+    ]),
+("Me", &[
+    ('\U00000488', '\U00000489'),
+    ('\U000020dd', '\U000020e0'),
+    ('\U000020e2', '\U000020e4'),
+    ('\U0000a670', '\U0000a672')
+    ]),
+("Meetei_Mayek", &[
+    ('\U0000aae0', '\U0000aaf6'),
+    ('\U0000abc0', '\U0000abed'),
+    ('\U0000abf0', '\U0000abf9')
+    ]),
+("Meroitic_Cursive", &[
+    ('\U000109a0', '\U000109b7'),
+    ('\U000109be', '\U000109bf')
+    ]),
+("Meroitic_Hieroglyphs", &[
+    ('\U00010980', '\U0001099f')
+    ]),
+("Miao", &[
+    ('\U00016f00', '\U00016f44'),
+    ('\U00016f50', '\U00016f7e'),
+    ('\U00016f8f', '\U00016f9f')
+    ]),
+("Mn", &[
+    ('\U00000300', '\U0000036f'),
+    ('\U00000483', '\U00000487'),
+    ('\U00000591', '\U000005bd'),
+    ('\U000005bf', '\U000005bf'),
+    ('\U000005c1', '\U000005c2'),
+    ('\U000005c4', '\U000005c5'),
+    ('\U000005c7', '\U000005c7'),
+    ('\U00000610', '\U0000061a'),
+    ('\U0000064b', '\U0000065f'),
+    ('\U00000670', '\U00000670'),
+    ('\U000006d6', '\U000006dc'),
+    ('\U000006df', '\U000006e4'),
+    ('\U000006e7', '\U000006e8'),
+    ('\U000006ea', '\U000006ed'),
+    ('\U00000711', '\U00000711'),
+    ('\U00000730', '\U0000074a'),
+    ('\U000007a6', '\U000007b0'),
+    ('\U000007eb', '\U000007f3'),
+    ('\U00000816', '\U00000819'),
+    ('\U0000081b', '\U00000823'),
+    ('\U00000825', '\U00000827'),
+    ('\U00000829', '\U0000082d'),
+    ('\U00000859', '\U0000085b'),
+    ('\U000008e4', '\U000008fe'),
+    ('\U00000900', '\U00000902'),
+    ('\U0000093a', '\U0000093a'),
+    ('\U0000093c', '\U0000093c'),
+    ('\U00000941', '\U00000948'),
+    ('\U0000094d', '\U0000094d'),
+    ('\U00000951', '\U00000957'),
+    ('\U00000962', '\U00000963'),
+    ('\U00000981', '\U00000981'),
+    ('\U000009bc', '\U000009bc'),
+    ('\U000009c1', '\U000009c4'),
+    ('\U000009cd', '\U000009cd'),
+    ('\U000009e2', '\U000009e3'),
+    ('\U00000a01', '\U00000a02'),
+    ('\U00000a3c', '\U00000a3c'),
+    ('\U00000a41', '\U00000a42'),
+    ('\U00000a47', '\U00000a48'),
+    ('\U00000a4b', '\U00000a4d'),
+    ('\U00000a51', '\U00000a51'),
+    ('\U00000a70', '\U00000a71'),
+    ('\U00000a75', '\U00000a75'),
+    ('\U00000a81', '\U00000a82'),
+    ('\U00000abc', '\U00000abc'),
+    ('\U00000ac1', '\U00000ac5'),
+    ('\U00000ac7', '\U00000ac8'),
+    ('\U00000acd', '\U00000acd'),
+    ('\U00000ae2', '\U00000ae3'),
+    ('\U00000b01', '\U00000b01'),
+    ('\U00000b3c', '\U00000b3c'),
+    ('\U00000b3f', '\U00000b3f'),
+    ('\U00000b41', '\U00000b44'),
+    ('\U00000b4d', '\U00000b4d'),
+    ('\U00000b56', '\U00000b56'),
+    ('\U00000b62', '\U00000b63'),
+    ('\U00000b82', '\U00000b82'),
+    ('\U00000bc0', '\U00000bc0'),
+    ('\U00000bcd', '\U00000bcd'),
+    ('\U00000c3e', '\U00000c40'),
+    ('\U00000c46', '\U00000c48'),
+    ('\U00000c4a', '\U00000c4d'),
+    ('\U00000c55', '\U00000c56'),
+    ('\U00000c62', '\U00000c63'),
+    ('\U00000cbc', '\U00000cbc'),
+    ('\U00000cbf', '\U00000cbf'),
+    ('\U00000cc6', '\U00000cc6'),
+    ('\U00000ccc', '\U00000ccd'),
+    ('\U00000ce2', '\U00000ce3'),
+    ('\U00000d41', '\U00000d44'),
+    ('\U00000d4d', '\U00000d4d'),
+    ('\U00000d62', '\U00000d63'),
+    ('\U00000dca', '\U00000dca'),
+    ('\U00000dd2', '\U00000dd4'),
+    ('\U00000dd6', '\U00000dd6'),
+    ('\U00000e31', '\U00000e31'),
+    ('\U00000e34', '\U00000e3a'),
+    ('\U00000e47', '\U00000e4e'),
+    ('\U00000eb1', '\U00000eb1'),
+    ('\U00000eb4', '\U00000eb9'),
+    ('\U00000ebb', '\U00000ebc'),
+    ('\U00000ec8', '\U00000ecd'),
+    ('\U00000f18', '\U00000f19'),
+    ('\U00000f35', '\U00000f35'),
+    ('\U00000f37', '\U00000f37'),
+    ('\U00000f39', '\U00000f39'),
+    ('\U00000f71', '\U00000f7e'),
+    ('\U00000f80', '\U00000f84'),
+    ('\U00000f86', '\U00000f87'),
+    ('\U00000f8d', '\U00000f97'),
+    ('\U00000f99', '\U00000fbc'),
+    ('\U00000fc6', '\U00000fc6'),
+    ('\U0000102d', '\U00001030'),
+    ('\U00001032', '\U00001037'),
+    ('\U00001039', '\U0000103a'),
+    ('\U0000103d', '\U0000103e'),
+    ('\U00001058', '\U00001059'),
+    ('\U0000105e', '\U00001060'),
+    ('\U00001071', '\U00001074'),
+    ('\U00001082', '\U00001082'),
+    ('\U00001085', '\U00001086'),
+    ('\U0000108d', '\U0000108d'),
+    ('\U0000109d', '\U0000109d'),
+    ('\U0000135d', '\U0000135f'),
+    ('\U00001712', '\U00001714'),
+    ('\U00001732', '\U00001734'),
+    ('\U00001752', '\U00001753'),
+    ('\U00001772', '\U00001773'),
+    ('\U000017b4', '\U000017b5'),
+    ('\U000017b7', '\U000017bd'),
+    ('\U000017c6', '\U000017c6'),
+    ('\U000017c9', '\U000017d3'),
+    ('\U000017dd', '\U000017dd'),
+    ('\U0000180b', '\U0000180d'),
+    ('\U000018a9', '\U000018a9'),
+    ('\U00001920', '\U00001922'),
+    ('\U00001927', '\U00001928'),
+    ('\U00001932', '\U00001932'),
+    ('\U00001939', '\U0000193b'),
+    ('\U00001a17', '\U00001a18'),
+    ('\U00001a1b', '\U00001a1b'),
+    ('\U00001a56', '\U00001a56'),
+    ('\U00001a58', '\U00001a5e'),
+    ('\U00001a60', '\U00001a60'),
+    ('\U00001a62', '\U00001a62'),
+    ('\U00001a65', '\U00001a6c'),
+    ('\U00001a73', '\U00001a7c'),
+    ('\U00001a7f', '\U00001a7f'),
+    ('\U00001b00', '\U00001b03'),
+    ('\U00001b34', '\U00001b34'),
+    ('\U00001b36', '\U00001b3a'),
+    ('\U00001b3c', '\U00001b3c'),
+    ('\U00001b42', '\U00001b42'),
+    ('\U00001b6b', '\U00001b73'),
+    ('\U00001b80', '\U00001b81'),
+    ('\U00001ba2', '\U00001ba5'),
+    ('\U00001ba8', '\U00001ba9'),
+    ('\U00001bab', '\U00001bab'),
+    ('\U00001be6', '\U00001be6'),
+    ('\U00001be8', '\U00001be9'),
+    ('\U00001bed', '\U00001bed'),
+    ('\U00001bef', '\U00001bf1'),
+    ('\U00001c2c', '\U00001c33'),
+    ('\U00001c36', '\U00001c37'),
+    ('\U00001cd0', '\U00001cd2'),
+    ('\U00001cd4', '\U00001ce0'),
+    ('\U00001ce2', '\U00001ce8'),
+    ('\U00001ced', '\U00001ced'),
+    ('\U00001cf4', '\U00001cf4'),
+    ('\U00001dc0', '\U00001de6'),
+    ('\U00001dfc', '\U00001dff'),
+    ('\U000020d0', '\U000020dc'),
+    ('\U000020e1', '\U000020e1'),
+    ('\U000020e5', '\U000020f0'),
+    ('\U00002cef', '\U00002cf1'),
+    ('\U00002d7f', '\U00002d7f'),
+    ('\U00002de0', '\U00002dff'),
+    ('\U0000302a', '\U0000302d'),
+    ('\U00003099', '\U0000309a'),
+    ('\U0000a66f', '\U0000a66f'),
+    ('\U0000a674', '\U0000a67d'),
+    ('\U0000a69f', '\U0000a69f'),
+    ('\U0000a6f0', '\U0000a6f1'),
+    ('\U0000a802', '\U0000a802'),
+    ('\U0000a806', '\U0000a806'),
+    ('\U0000a80b', '\U0000a80b'),
+    ('\U0000a825', '\U0000a826'),
+    ('\U0000a8c4', '\U0000a8c4'),
+    ('\U0000a8e0', '\U0000a8f1'),
+    ('\U0000a926', '\U0000a92d'),
+    ('\U0000a947', '\U0000a951'),
+    ('\U0000a980', '\U0000a982'),
+    ('\U0000a9b3', '\U0000a9b3'),
+    ('\U0000a9b6', '\U0000a9b9'),
+    ('\U0000a9bc', '\U0000a9bc'),
+    ('\U0000aa29', '\U0000aa2e'),
+    ('\U0000aa31', '\U0000aa32'),
+    ('\U0000aa35', '\U0000aa36'),
+    ('\U0000aa43', '\U0000aa43'),
+    ('\U0000aa4c', '\U0000aa4c'),
+    ('\U0000aab0', '\U0000aab0'),
+    ('\U0000aab2', '\U0000aab4'),
+    ('\U0000aab7', '\U0000aab8'),
+    ('\U0000aabe', '\U0000aabf'),
+    ('\U0000aac1', '\U0000aac1'),
+    ('\U0000aaec', '\U0000aaed'),
+    ('\U0000aaf6', '\U0000aaf6'),
+    ('\U0000abe5', '\U0000abe5'),
+    ('\U0000abe8', '\U0000abe8'),
+    ('\U0000abed', '\U0000abed'),
+    ('\U0000fb1e', '\U0000fb1e'),
+    ('\U0000fe00', '\U0000fe0f'),
+    ('\U0000fe20', '\U0000fe26'),
+    ('\U000101fd', '\U000101fd'),
+    ('\U00010a01', '\U00010a03'),
+    ('\U00010a05', '\U00010a06'),
+    ('\U00010a0c', '\U00010a0f'),
+    ('\U00010a38', '\U00010a3a'),
+    ('\U00010a3f', '\U00010a3f'),
+    ('\U00011001', '\U00011001'),
+    ('\U00011038', '\U00011046'),
+    ('\U00011080', '\U00011081'),
+    ('\U000110b3', '\U000110b6'),
+    ('\U000110b9', '\U000110ba'),
+    ('\U00011100', '\U00011102'),
+    ('\U00011127', '\U0001112b'),
+    ('\U0001112d', '\U00011134'),
+    ('\U00011180', '\U00011181'),
+    ('\U000111b6', '\U000111be'),
+    ('\U000116ab', '\U000116ab'),
+    ('\U000116ad', '\U000116ad'),
+    ('\U000116b0', '\U000116b5'),
+    ('\U000116b7', '\U000116b7'),
+    ('\U00016f8f', '\U00016f92'),
+    ('\U0001d167', '\U0001d169'),
+    ('\U0001d17b', '\U0001d182'),
+    ('\U0001d185', '\U0001d18b'),
+    ('\U0001d1aa', '\U0001d1ad'),
+    ('\U0001d242', '\U0001d244'),
+    ('\U000e0100', '\U000e01ef')
+    ]),
+("Mongolian", &[
+    ('\U00001800', '\U00001801'),
+    ('\U00001804', '\U00001804'),
+    ('\U00001806', '\U0000180e'),
+    ('\U00001810', '\U00001819'),
+    ('\U00001820', '\U00001877'),
+    ('\U00001880', '\U000018aa')
+    ]),
+("Myanmar", &[
+    ('\U00001000', '\U0000109f'),
+    ('\U0000aa60', '\U0000aa7b')
+    ]),
+("N", &[
+    ('\U00000030', '\U00000039'),
+    ('\U00000660', '\U00000669'),
+    ('\U000006f0', '\U000006f9'),
+    ('\U000007c0', '\U000007c9'),
+    ('\U00000966', '\U0000096f'),
+    ('\U000009e6', '\U000009ef'),
+    ('\U00000a66', '\U00000a6f'),
+    ('\U00000ae6', '\U00000aef'),
+    ('\U00000b66', '\U00000b6f'),
+    ('\U00000be6', '\U00000bef'),
+    ('\U00000c66', '\U00000c6f'),
+    ('\U00000ce6', '\U00000cef'),
+    ('\U00000d66', '\U00000d6f'),
+    ('\U00000e50', '\U00000e59'),
+    ('\U00000ed0', '\U00000ed9'),
+    ('\U00000f20', '\U00000f29'),
+    ('\U00001040', '\U00001049'),
+    ('\U00001090', '\U00001099'),
+    ('\U000016ee', '\U000016f0'),
+    ('\U000017e0', '\U000017e9'),
+    ('\U00001810', '\U00001819'),
+    ('\U00001946', '\U0000194f'),
+    ('\U000019d0', '\U000019d9'),
+    ('\U00001a80', '\U00001a89'),
+    ('\U00001a90', '\U00001a99'),
+    ('\U00001b50', '\U00001b59'),
+    ('\U00001bb0', '\U00001bb9'),
+    ('\U00001c40', '\U00001c49'),
+    ('\U00001c50', '\U00001c59'),
+    ('\U00002160', '\U00002182'),
+    ('\U00002185', '\U00002188'),
+    ('\U00003007', '\U00003007'),
+    ('\U00003021', '\U00003029'),
+    ('\U00003038', '\U0000303a'),
+    ('\U0000a620', '\U0000a629'),
+    ('\U0000a6e6', '\U0000a6ef'),
+    ('\U0000a8d0', '\U0000a8d9'),
+    ('\U0000a900', '\U0000a909'),
+    ('\U0000a9d0', '\U0000a9d9'),
+    ('\U0000aa50', '\U0000aa59'),
+    ('\U0000abf0', '\U0000abf9'),
+    ('\U0000ff10', '\U0000ff19'),
+    ('\U00010140', '\U00010174'),
+    ('\U00010341', '\U00010341'),
+    ('\U0001034a', '\U0001034a'),
+    ('\U000103d1', '\U000103d5'),
+    ('\U000104a0', '\U000104a9'),
+    ('\U00011066', '\U0001106f'),
+    ('\U000110f0', '\U000110f9'),
+    ('\U00011136', '\U0001113f'),
+    ('\U000111d0', '\U000111d9'),
+    ('\U000116c0', '\U000116c9'),
+    ('\U00012400', '\U00012462'),
+    ('\U0001d7ce', '\U0001d7ff')
+    ]),
+("Nd", &[
+    ('\U00000030', '\U00000039'),
+    ('\U00000660', '\U00000669'),
+    ('\U000006f0', '\U000006f9'),
+    ('\U000007c0', '\U000007c9'),
+    ('\U00000966', '\U0000096f'),
+    ('\U000009e6', '\U000009ef'),
+    ('\U00000a66', '\U00000a6f'),
+    ('\U00000ae6', '\U00000aef'),
+    ('\U00000b66', '\U00000b6f'),
+    ('\U00000be6', '\U00000bef'),
+    ('\U00000c66', '\U00000c6f'),
+    ('\U00000ce6', '\U00000cef'),
+    ('\U00000d66', '\U00000d6f'),
+    ('\U00000e50', '\U00000e59'),
+    ('\U00000ed0', '\U00000ed9'),
+    ('\U00000f20', '\U00000f29'),
+    ('\U00001040', '\U00001049'),
+    ('\U00001090', '\U00001099'),
+    ('\U000017e0', '\U000017e9'),
+    ('\U00001810', '\U00001819'),
+    ('\U00001946', '\U0000194f'),
+    ('\U000019d0', '\U000019d9'),
+    ('\U00001a80', '\U00001a89'),
+    ('\U00001a90', '\U00001a99'),
+    ('\U00001b50', '\U00001b59'),
+    ('\U00001bb0', '\U00001bb9'),
+    ('\U00001c40', '\U00001c49'),
+    ('\U00001c50', '\U00001c59'),
+    ('\U0000a620', '\U0000a629'),
+    ('\U0000a8d0', '\U0000a8d9'),
+    ('\U0000a900', '\U0000a909'),
+    ('\U0000a9d0', '\U0000a9d9'),
+    ('\U0000aa50', '\U0000aa59'),
+    ('\U0000abf0', '\U0000abf9'),
+    ('\U0000ff10', '\U0000ff19'),
+    ('\U000104a0', '\U000104a9'),
+    ('\U00011066', '\U0001106f'),
+    ('\U000110f0', '\U000110f9'),
+    ('\U00011136', '\U0001113f'),
+    ('\U000111d0', '\U000111d9'),
+    ('\U000116c0', '\U000116c9'),
+    ('\U0001d7ce', '\U0001d7ff')
+    ]),
+("New_Tai_Lue", &[
+    ('\U00001980', '\U000019ab'),
+    ('\U000019b0', '\U000019c9'),
+    ('\U000019d0', '\U000019da'),
+    ('\U000019de', '\U000019df')
+    ]),
+("Nko", &[
+    ('\U000007c0', '\U000007fa')
+    ]),
+("Nl", &[
+    ('\U000016ee', '\U000016f0'),
+    ('\U00002160', '\U00002182'),
+    ('\U00002185', '\U00002188'),
+    ('\U00003007', '\U00003007'),
+    ('\U00003021', '\U00003029'),
+    ('\U00003038', '\U0000303a'),
+    ('\U0000a6e6', '\U0000a6ef'),
+    ('\U00010140', '\U00010174'),
+    ('\U00010341', '\U00010341'),
+    ('\U0001034a', '\U0001034a'),
+    ('\U000103d1', '\U000103d5'),
+    ('\U00012400', '\U00012462')
+    ]),
+("No", &[
+    ('\U000000b2', '\U000000b3'),
+    ('\U000000b9', '\U000000b9'),
+    ('\U000000bc', '\U000000be'),
+    ('\U000009f4', '\U000009f9'),
+    ('\U00000b72', '\U00000b77'),
+    ('\U00000bf0', '\U00000bf2'),
+    ('\U00000c78', '\U00000c7e'),
+    ('\U00000d70', '\U00000d75'),
+    ('\U00000f2a', '\U00000f33'),
+    ('\U00001369', '\U0000137c'),
+    ('\U000017f0', '\U000017f9'),
+    ('\U000019da', '\U000019da'),
+    ('\U00002070', '\U00002070'),
+    ('\U00002074', '\U00002079'),
+    ('\U00002080', '\U00002089'),
+    ('\U00002150', '\U0000215f'),
+    ('\U00002189', '\U00002189'),
+    ('\U00002460', '\U0000249b'),
+    ('\U000024ea', '\U000024ff'),
+    ('\U00002776', '\U00002793'),
+    ('\U00002cfd', '\U00002cfd'),
+    ('\U00003192', '\U00003195'),
+    ('\U00003220', '\U00003229'),
+    ('\U00003248', '\U0000324f'),
+    ('\U00003251', '\U0000325f'),
+    ('\U00003280', '\U00003289'),
+    ('\U000032b1', '\U000032bf'),
+    ('\U0000a830', '\U0000a835'),
+    ('\U00010107', '\U00010133'),
+    ('\U00010175', '\U00010178'),
+    ('\U0001018a', '\U0001018a'),
+    ('\U00010320', '\U00010323'),
+    ('\U00010858', '\U0001085f'),
+    ('\U00010916', '\U0001091b'),
+    ('\U00010a40', '\U00010a47'),
+    ('\U00010a7d', '\U00010a7e'),
+    ('\U00010b58', '\U00010b5f'),
+    ('\U00010b78', '\U00010b7f'),
+    ('\U00010e60', '\U00010e7e'),
+    ('\U00011052', '\U00011065'),
+    ('\U0001d360', '\U0001d371'),
+    ('\U0001f100', '\U0001f10a')
+    ]),
+("Ogham", &[
+    ('\U00001680', '\U0000169c')
+    ]),
+("Ol_Chiki", &[
+    ('\U00001c50', '\U00001c7f')
+    ]),
+("Old_Italic", &[
+    ('\U00010300', '\U0001031e'),
+    ('\U00010320', '\U00010323')
+    ]),
+("Old_Persian", &[
+    ('\U000103a0', '\U000103c3'),
+    ('\U000103c8', '\U000103d5')
+    ]),
+("Old_South_Arabian", &[
+    ('\U00010a60', '\U00010a7f')
+    ]),
+("Old_Turkic", &[
+    ('\U00010c00', '\U00010c48')
+    ]),
+("Oriya", &[
+    ('\U00000b01', '\U00000b03'),
+    ('\U00000b05', '\U00000b0c'),
+    ('\U00000b0f', '\U00000b10'),
+    ('\U00000b13', '\U00000b28'),
+    ('\U00000b2a', '\U00000b30'),
+    ('\U00000b32', '\U00000b33'),
+    ('\U00000b35', '\U00000b39'),
+    ('\U00000b3c', '\U00000b44'),
+    ('\U00000b47', '\U00000b48'),
+    ('\U00000b4b', '\U00000b4d'),
+    ('\U00000b56', '\U00000b57'),
+    ('\U00000b5c', '\U00000b5d'),
+    ('\U00000b5f', '\U00000b63'),
+    ('\U00000b66', '\U00000b77')
+    ]),
+("Osmanya", &[
+    ('\U00010480', '\U0001049d'),
+    ('\U000104a0', '\U000104a9')
+    ]),
+("P", &[
+    ('\U00000021', '\U00000023'),
+    ('\U00000025', '\U0000002a'),
+    ('\U0000002c', '\U0000002f'),
+    ('\U0000003a', '\U0000003b'),
+    ('\U0000003f', '\U00000040'),
+    ('\U0000005b', '\U0000005d'),
+    ('\U0000005f', '\U0000005f'),
+    ('\U0000007b', '\U0000007b'),
+    ('\U0000007d', '\U0000007d'),
+    ('\U000000a1', '\U000000a1'),
+    ('\U000000a7', '\U000000a7'),
+    ('\U000000ab', '\U000000ab'),
+    ('\U000000b6', '\U000000b7'),
+    ('\U000000bb', '\U000000bb'),
+    ('\U000000bf', '\U000000bf'),
+    ('\U0000037e', '\U0000037e'),
+    ('\U00000387', '\U00000387'),
+    ('\U0000055a', '\U0000055f'),
+    ('\U00000589', '\U0000058a'),
+    ('\U000005be', '\U000005be'),
+    ('\U000005c0', '\U000005c0'),
+    ('\U000005c3', '\U000005c3'),
+    ('\U000005c6', '\U000005c6'),
+    ('\U000005f3', '\U000005f4'),
+    ('\U00000609', '\U0000060a'),
+    ('\U0000060c', '\U0000060d'),
+    ('\U0000061b', '\U0000061b'),
+    ('\U0000061e', '\U0000061f'),
+    ('\U0000066a', '\U0000066d'),
+    ('\U000006d4', '\U000006d4'),
+    ('\U00000700', '\U0000070d'),
+    ('\U000007f7', '\U000007f9'),
+    ('\U00000830', '\U0000083e'),
+    ('\U0000085e', '\U0000085e'),
+    ('\U00000964', '\U00000965'),
+    ('\U00000970', '\U00000970'),
+    ('\U00000af0', '\U00000af0'),
+    ('\U00000df4', '\U00000df4'),
+    ('\U00000e4f', '\U00000e4f'),
+    ('\U00000e5a', '\U00000e5b'),
+    ('\U00000f04', '\U00000f12'),
+    ('\U00000f14', '\U00000f14'),
+    ('\U00000f3a', '\U00000f3d'),
+    ('\U00000f85', '\U00000f85'),
+    ('\U00000fd0', '\U00000fd4'),
+    ('\U00000fd9', '\U00000fda'),
+    ('\U0000104a', '\U0000104f'),
+    ('\U000010fb', '\U000010fb'),
+    ('\U00001360', '\U00001368'),
+    ('\U00001400', '\U00001400'),
+    ('\U0000166d', '\U0000166e'),
+    ('\U0000169b', '\U0000169c'),
+    ('\U000016eb', '\U000016ed'),
+    ('\U00001735', '\U00001736'),
+    ('\U000017d4', '\U000017d6'),
+    ('\U000017d8', '\U000017da'),
+    ('\U00001800', '\U0000180a'),
+    ('\U00001944', '\U00001945'),
+    ('\U00001a1e', '\U00001a1f'),
+    ('\U00001aa0', '\U00001aa6'),
+    ('\U00001aa8', '\U00001aad'),
+    ('\U00001b5a', '\U00001b60'),
+    ('\U00001bfc', '\U00001bff'),
+    ('\U00001c3b', '\U00001c3f'),
+    ('\U00001c7e', '\U00001c7f'),
+    ('\U00001cc0', '\U00001cc7'),
+    ('\U00001cd3', '\U00001cd3'),
+    ('\U00002010', '\U00002027'),
+    ('\U00002030', '\U00002043'),
+    ('\U00002045', '\U00002051'),
+    ('\U00002053', '\U0000205e'),
+    ('\U0000207d', '\U0000207e'),
+    ('\U0000208d', '\U0000208e'),
+    ('\U00002308', '\U0000230b'),
+    ('\U00002329', '\U0000232a'),
+    ('\U00002768', '\U00002775'),
+    ('\U000027c5', '\U000027c6'),
+    ('\U000027e6', '\U000027ef'),
+    ('\U00002983', '\U00002998'),
+    ('\U000029d8', '\U000029db'),
+    ('\U000029fc', '\U000029fd'),
+    ('\U00002cf9', '\U00002cfc'),
+    ('\U00002cfe', '\U00002cff'),
+    ('\U00002d70', '\U00002d70'),
+    ('\U00002e00', '\U00002e2e'),
+    ('\U00002e30', '\U00002e3b'),
+    ('\U00003001', '\U00003003'),
+    ('\U00003008', '\U00003011'),
+    ('\U00003014', '\U0000301f'),
+    ('\U00003030', '\U00003030'),
+    ('\U0000303d', '\U0000303d'),
+    ('\U000030a0', '\U000030a0'),
+    ('\U000030fb', '\U000030fb'),
+    ('\U0000a4fe', '\U0000a4ff'),
+    ('\U0000a60d', '\U0000a60f'),
+    ('\U0000a673', '\U0000a673'),
+    ('\U0000a67e', '\U0000a67e'),
+    ('\U0000a6f2', '\U0000a6f7'),
+    ('\U0000a874', '\U0000a877'),
+    ('\U0000a8ce', '\U0000a8cf'),
+    ('\U0000a8f8', '\U0000a8fa'),
+    ('\U0000a92e', '\U0000a92f'),
+    ('\U0000a95f', '\U0000a95f'),
+    ('\U0000a9c1', '\U0000a9cd'),
+    ('\U0000a9de', '\U0000a9df'),
+    ('\U0000aa5c', '\U0000aa5f'),
+    ('\U0000aade', '\U0000aadf'),
+    ('\U0000aaf0', '\U0000aaf1'),
+    ('\U0000abeb', '\U0000abeb'),
+    ('\U0000fd3e', '\U0000fd3f'),
+    ('\U0000fe10', '\U0000fe19'),
+    ('\U0000fe30', '\U0000fe52'),
+    ('\U0000fe54', '\U0000fe61'),
+    ('\U0000fe63', '\U0000fe63'),
+    ('\U0000fe68', '\U0000fe68'),
+    ('\U0000fe6a', '\U0000fe6b'),
+    ('\U0000ff01', '\U0000ff03'),
+    ('\U0000ff05', '\U0000ff0a'),
+    ('\U0000ff0c', '\U0000ff0f'),
+    ('\U0000ff1a', '\U0000ff1b'),
+    ('\U0000ff1f', '\U0000ff20'),
+    ('\U0000ff3b', '\U0000ff3d'),
+    ('\U0000ff3f', '\U0000ff3f'),
+    ('\U0000ff5b', '\U0000ff5b'),
+    ('\U0000ff5d', '\U0000ff5d'),
+    ('\U0000ff5f', '\U0000ff65'),
+    ('\U00010100', '\U00010102'),
+    ('\U0001039f', '\U0001039f'),
+    ('\U000103d0', '\U000103d0'),
+    ('\U00010857', '\U00010857'),
+    ('\U0001091f', '\U0001091f'),
+    ('\U0001093f', '\U0001093f'),
+    ('\U00010a50', '\U00010a58'),
+    ('\U00010a7f', '\U00010a7f'),
+    ('\U00010b39', '\U00010b3f'),
+    ('\U00011047', '\U0001104d'),
+    ('\U000110bb', '\U000110bc'),
+    ('\U000110be', '\U000110c1'),
+    ('\U00011140', '\U00011143'),
+    ('\U000111c5', '\U000111c8'),
+    ('\U00012470', '\U00012473')
+    ]),
+("Pc", &[
+    ('\U0000005f', '\U0000005f'),
+    ('\U0000203f', '\U00002040'),
+    ('\U00002054', '\U00002054'),
+    ('\U0000fe33', '\U0000fe34'),
+    ('\U0000fe4d', '\U0000fe4f'),
+    ('\U0000ff3f', '\U0000ff3f')
+    ]),
+("Pd", &[
+    ('\U0000002d', '\U0000002d'),
+    ('\U0000058a', '\U0000058a'),
+    ('\U000005be', '\U000005be'),
+    ('\U00001400', '\U00001400'),
+    ('\U00001806', '\U00001806'),
+    ('\U00002010', '\U00002015'),
+    ('\U00002e17', '\U00002e17'),
+    ('\U00002e1a', '\U00002e1a'),
+    ('\U00002e3a', '\U00002e3b'),
+    ('\U0000301c', '\U0000301c'),
+    ('\U00003030', '\U00003030'),
+    ('\U000030a0', '\U000030a0'),
+    ('\U0000fe31', '\U0000fe32'),
+    ('\U0000fe58', '\U0000fe58'),
+    ('\U0000fe63', '\U0000fe63'),
+    ('\U0000ff0d', '\U0000ff0d')
+    ]),
+("Pe", &[
+    ('\U00000029', '\U00000029'),
+    ('\U0000005d', '\U0000005d'),
+    ('\U0000007d', '\U0000007d'),
+    ('\U00000f3b', '\U00000f3b'),
+    ('\U00000f3d', '\U00000f3d'),
+    ('\U0000169c', '\U0000169c'),
+    ('\U00002046', '\U00002046'),
+    ('\U0000207e', '\U0000207e'),
+    ('\U0000208e', '\U0000208e'),
+    ('\U00002309', '\U00002309'),
+    ('\U0000230b', '\U0000230b'),
+    ('\U0000232a', '\U0000232a'),
+    ('\U00002769', '\U00002769'),
+    ('\U0000276b', '\U0000276b'),
+    ('\U0000276d', '\U0000276d'),
+    ('\U0000276f', '\U0000276f'),
+    ('\U00002771', '\U00002771'),
+    ('\U00002773', '\U00002773'),
+    ('\U00002775', '\U00002775'),
+    ('\U000027c6', '\U000027c6'),
+    ('\U000027e7', '\U000027e7'),
+    ('\U000027e9', '\U000027e9'),
+    ('\U000027eb', '\U000027eb'),
+    ('\U000027ed', '\U000027ed'),
+    ('\U000027ef', '\U000027ef'),
+    ('\U00002984', '\U00002984'),
+    ('\U00002986', '\U00002986'),
+    ('\U00002988', '\U00002988'),
+    ('\U0000298a', '\U0000298a'),
+    ('\U0000298c', '\U0000298c'),
+    ('\U0000298e', '\U0000298e'),
+    ('\U00002990', '\U00002990'),
+    ('\U00002992', '\U00002992'),
+    ('\U00002994', '\U00002994'),
+    ('\U00002996', '\U00002996'),
+    ('\U00002998', '\U00002998'),
+    ('\U000029d9', '\U000029d9'),
+    ('\U000029db', '\U000029db'),
+    ('\U000029fd', '\U000029fd'),
+    ('\U00002e23', '\U00002e23'),
+    ('\U00002e25', '\U00002e25'),
+    ('\U00002e27', '\U00002e27'),
+    ('\U00002e29', '\U00002e29'),
+    ('\U00003009', '\U00003009'),
+    ('\U0000300b', '\U0000300b'),
+    ('\U0000300d', '\U0000300d'),
+    ('\U0000300f', '\U0000300f'),
+    ('\U00003011', '\U00003011'),
+    ('\U00003015', '\U00003015'),
+    ('\U00003017', '\U00003017'),
+    ('\U00003019', '\U00003019'),
+    ('\U0000301b', '\U0000301b'),
+    ('\U0000301e', '\U0000301f'),
+    ('\U0000fd3f', '\U0000fd3f'),
+    ('\U0000fe18', '\U0000fe18'),
+    ('\U0000fe36', '\U0000fe36'),
+    ('\U0000fe38', '\U0000fe38'),
+    ('\U0000fe3a', '\U0000fe3a'),
+    ('\U0000fe3c', '\U0000fe3c'),
+    ('\U0000fe3e', '\U0000fe3e'),
+    ('\U0000fe40', '\U0000fe40'),
+    ('\U0000fe42', '\U0000fe42'),
+    ('\U0000fe44', '\U0000fe44'),
+    ('\U0000fe48', '\U0000fe48'),
+    ('\U0000fe5a', '\U0000fe5a'),
+    ('\U0000fe5c', '\U0000fe5c'),
+    ('\U0000fe5e', '\U0000fe5e'),
+    ('\U0000ff09', '\U0000ff09'),
+    ('\U0000ff3d', '\U0000ff3d'),
+    ('\U0000ff5d', '\U0000ff5d'),
+    ('\U0000ff60', '\U0000ff60'),
+    ('\U0000ff63', '\U0000ff63')
+    ]),
+("Pf", &[
+    ('\U000000bb', '\U000000bb'),
+    ('\U00002019', '\U00002019'),
+    ('\U0000201d', '\U0000201d'),
+    ('\U0000203a', '\U0000203a'),
+    ('\U00002e03', '\U00002e03'),
+    ('\U00002e05', '\U00002e05'),
+    ('\U00002e0a', '\U00002e0a'),
+    ('\U00002e0d', '\U00002e0d'),
+    ('\U00002e1d', '\U00002e1d'),
+    ('\U00002e21', '\U00002e21')
+    ]),
+("Phags_Pa", &[
+    ('\U0000a840', '\U0000a877')
+    ]),
+("Phoenician", &[
+    ('\U00010900', '\U0001091b'),
+    ('\U0001091f', '\U0001091f')
+    ]),
+("Pi", &[
+    ('\U000000ab', '\U000000ab'),
+    ('\U00002018', '\U00002018'),
+    ('\U0000201b', '\U0000201c'),
+    ('\U0000201f', '\U0000201f'),
+    ('\U00002039', '\U00002039'),
+    ('\U00002e02', '\U00002e02'),
+    ('\U00002e04', '\U00002e04'),
+    ('\U00002e09', '\U00002e09'),
+    ('\U00002e0c', '\U00002e0c'),
+    ('\U00002e1c', '\U00002e1c'),
+    ('\U00002e20', '\U00002e20')
+    ]),
+("Po", &[
+    ('\U00000021', '\U00000023'),
+    ('\U00000025', '\U00000027'),
+    ('\U0000002a', '\U0000002a'),
+    ('\U0000002c', '\U0000002c'),
+    ('\U0000002e', '\U0000002f'),
+    ('\U0000003a', '\U0000003b'),
+    ('\U0000003f', '\U00000040'),
+    ('\U0000005c', '\U0000005c'),
+    ('\U000000a1', '\U000000a1'),
+    ('\U000000a7', '\U000000a7'),
+    ('\U000000b6', '\U000000b7'),
+    ('\U000000bf', '\U000000bf'),
+    ('\U0000037e', '\U0000037e'),
+    ('\U00000387', '\U00000387'),
+    ('\U0000055a', '\U0000055f'),
+    ('\U00000589', '\U00000589'),
+    ('\U000005c0', '\U000005c0'),
+    ('\U000005c3', '\U000005c3'),
+    ('\U000005c6', '\U000005c6'),
+    ('\U000005f3', '\U000005f4'),
+    ('\U00000609', '\U0000060a'),
+    ('\U0000060c', '\U0000060d'),
+    ('\U0000061b', '\U0000061b'),
+    ('\U0000061e', '\U0000061f'),
+    ('\U0000066a', '\U0000066d'),
+    ('\U000006d4', '\U000006d4'),
+    ('\U00000700', '\U0000070d'),
+    ('\U000007f7', '\U000007f9'),
+    ('\U00000830', '\U0000083e'),
+    ('\U0000085e', '\U0000085e'),
+    ('\U00000964', '\U00000965'),
+    ('\U00000970', '\U00000970'),
+    ('\U00000af0', '\U00000af0'),
+    ('\U00000df4', '\U00000df4'),
+    ('\U00000e4f', '\U00000e4f'),
+    ('\U00000e5a', '\U00000e5b'),
+    ('\U00000f04', '\U00000f12'),
+    ('\U00000f14', '\U00000f14'),
+    ('\U00000f85', '\U00000f85'),
+    ('\U00000fd0', '\U00000fd4'),
+    ('\U00000fd9', '\U00000fda'),
+    ('\U0000104a', '\U0000104f'),
+    ('\U000010fb', '\U000010fb'),
+    ('\U00001360', '\U00001368'),
+    ('\U0000166d', '\U0000166e'),
+    ('\U000016eb', '\U000016ed'),
+    ('\U00001735', '\U00001736'),
+    ('\U000017d4', '\U000017d6'),
+    ('\U000017d8', '\U000017da'),
+    ('\U00001800', '\U00001805'),
+    ('\U00001807', '\U0000180a'),
+    ('\U00001944', '\U00001945'),
+    ('\U00001a1e', '\U00001a1f'),
+    ('\U00001aa0', '\U00001aa6'),
+    ('\U00001aa8', '\U00001aad'),
+    ('\U00001b5a', '\U00001b60'),
+    ('\U00001bfc', '\U00001bff'),
+    ('\U00001c3b', '\U00001c3f'),
+    ('\U00001c7e', '\U00001c7f'),
+    ('\U00001cc0', '\U00001cc7'),
+    ('\U00001cd3', '\U00001cd3'),
+    ('\U00002016', '\U00002017'),
+    ('\U00002020', '\U00002027'),
+    ('\U00002030', '\U00002038'),
+    ('\U0000203b', '\U0000203e'),
+    ('\U00002041', '\U00002043'),
+    ('\U00002047', '\U00002051'),
+    ('\U00002053', '\U00002053'),
+    ('\U00002055', '\U0000205e'),
+    ('\U00002cf9', '\U00002cfc'),
+    ('\U00002cfe', '\U00002cff'),
+    ('\U00002d70', '\U00002d70'),
+    ('\U00002e00', '\U00002e01'),
+    ('\U00002e06', '\U00002e08'),
+    ('\U00002e0b', '\U00002e0b'),
+    ('\U00002e0e', '\U00002e16'),
+    ('\U00002e18', '\U00002e19'),
+    ('\U00002e1b', '\U00002e1b'),
+    ('\U00002e1e', '\U00002e1f'),
+    ('\U00002e2a', '\U00002e2e'),
+    ('\U00002e30', '\U00002e39'),
+    ('\U00003001', '\U00003003'),
+    ('\U0000303d', '\U0000303d'),
+    ('\U000030fb', '\U000030fb'),
+    ('\U0000a4fe', '\U0000a4ff'),
+    ('\U0000a60d', '\U0000a60f'),
+    ('\U0000a673', '\U0000a673'),
+    ('\U0000a67e', '\U0000a67e'),
+    ('\U0000a6f2', '\U0000a6f7'),
+    ('\U0000a874', '\U0000a877'),
+    ('\U0000a8ce', '\U0000a8cf'),
+    ('\U0000a8f8', '\U0000a8fa'),
+    ('\U0000a92e', '\U0000a92f'),
+    ('\U0000a95f', '\U0000a95f'),
+    ('\U0000a9c1', '\U0000a9cd'),
+    ('\U0000a9de', '\U0000a9df'),
+    ('\U0000aa5c', '\U0000aa5f'),
+    ('\U0000aade', '\U0000aadf'),
+    ('\U0000aaf0', '\U0000aaf1'),
+    ('\U0000abeb', '\U0000abeb'),
+    ('\U0000fe10', '\U0000fe16'),
+    ('\U0000fe19', '\U0000fe19'),
+    ('\U0000fe30', '\U0000fe30'),
+    ('\U0000fe45', '\U0000fe46'),
+    ('\U0000fe49', '\U0000fe4c'),
+    ('\U0000fe50', '\U0000fe52'),
+    ('\U0000fe54', '\U0000fe57'),
+    ('\U0000fe5f', '\U0000fe61'),
+    ('\U0000fe68', '\U0000fe68'),
+    ('\U0000fe6a', '\U0000fe6b'),
+    ('\U0000ff01', '\U0000ff03'),
+    ('\U0000ff05', '\U0000ff07'),
+    ('\U0000ff0a', '\U0000ff0a'),
+    ('\U0000ff0c', '\U0000ff0c'),
+    ('\U0000ff0e', '\U0000ff0f'),
+    ('\U0000ff1a', '\U0000ff1b'),
+    ('\U0000ff1f', '\U0000ff20'),
+    ('\U0000ff3c', '\U0000ff3c'),
+    ('\U0000ff61', '\U0000ff61'),
+    ('\U0000ff64', '\U0000ff65'),
+    ('\U00010100', '\U00010102'),
+    ('\U0001039f', '\U0001039f'),
+    ('\U000103d0', '\U000103d0'),
+    ('\U00010857', '\U00010857'),
+    ('\U0001091f', '\U0001091f'),
+    ('\U0001093f', '\U0001093f'),
+    ('\U00010a50', '\U00010a58'),
+    ('\U00010a7f', '\U00010a7f'),
+    ('\U00010b39', '\U00010b3f'),
+    ('\U00011047', '\U0001104d'),
+    ('\U000110bb', '\U000110bc'),
+    ('\U000110be', '\U000110c1'),
+    ('\U00011140', '\U00011143'),
+    ('\U000111c5', '\U000111c8'),
+    ('\U00012470', '\U00012473')
+    ]),
+("Ps", &[
+    ('\U00000028', '\U00000028'),
+    ('\U0000005b', '\U0000005b'),
+    ('\U0000007b', '\U0000007b'),
+    ('\U00000f3a', '\U00000f3a'),
+    ('\U00000f3c', '\U00000f3c'),
+    ('\U0000169b', '\U0000169b'),
+    ('\U0000201a', '\U0000201a'),
+    ('\U0000201e', '\U0000201e'),
+    ('\U00002045', '\U00002045'),
+    ('\U0000207d', '\U0000207d'),
+    ('\U0000208d', '\U0000208d'),
+    ('\U00002308', '\U00002308'),
+    ('\U0000230a', '\U0000230a'),
+    ('\U00002329', '\U00002329'),
+    ('\U00002768', '\U00002768'),
+    ('\U0000276a', '\U0000276a'),
+    ('\U0000276c', '\U0000276c'),
+    ('\U0000276e', '\U0000276e'),
+    ('\U00002770', '\U00002770'),
+    ('\U00002772', '\U00002772'),
+    ('\U00002774', '\U00002774'),
+    ('\U000027c5', '\U000027c5'),
+    ('\U000027e6', '\U000027e6'),
+    ('\U000027e8', '\U000027e8'),
+    ('\U000027ea', '\U000027ea'),
+    ('\U000027ec', '\U000027ec'),
+    ('\U000027ee', '\U000027ee'),
+    ('\U00002983', '\U00002983'),
+    ('\U00002985', '\U00002985'),
+    ('\U00002987', '\U00002987'),
+    ('\U00002989', '\U00002989'),
+    ('\U0000298b', '\U0000298b'),
+    ('\U0000298d', '\U0000298d'),
+    ('\U0000298f', '\U0000298f'),
+    ('\U00002991', '\U00002991'),
+    ('\U00002993', '\U00002993'),
+    ('\U00002995', '\U00002995'),
+    ('\U00002997', '\U00002997'),
+    ('\U000029d8', '\U000029d8'),
+    ('\U000029da', '\U000029da'),
+    ('\U000029fc', '\U000029fc'),
+    ('\U00002e22', '\U00002e22'),
+    ('\U00002e24', '\U00002e24'),
+    ('\U00002e26', '\U00002e26'),
+    ('\U00002e28', '\U00002e28'),
+    ('\U00003008', '\U00003008'),
+    ('\U0000300a', '\U0000300a'),
+    ('\U0000300c', '\U0000300c'),
+    ('\U0000300e', '\U0000300e'),
+    ('\U00003010', '\U00003010'),
+    ('\U00003014', '\U00003014'),
+    ('\U00003016', '\U00003016'),
+    ('\U00003018', '\U00003018'),
+    ('\U0000301a', '\U0000301a'),
+    ('\U0000301d', '\U0000301d'),
+    ('\U0000fd3e', '\U0000fd3e'),
+    ('\U0000fe17', '\U0000fe17'),
+    ('\U0000fe35', '\U0000fe35'),
+    ('\U0000fe37', '\U0000fe37'),
+    ('\U0000fe39', '\U0000fe39'),
+    ('\U0000fe3b', '\U0000fe3b'),
+    ('\U0000fe3d', '\U0000fe3d'),
+    ('\U0000fe3f', '\U0000fe3f'),
+    ('\U0000fe41', '\U0000fe41'),
+    ('\U0000fe43', '\U0000fe43'),
+    ('\U0000fe47', '\U0000fe47'),
+    ('\U0000fe59', '\U0000fe59'),
+    ('\U0000fe5b', '\U0000fe5b'),
+    ('\U0000fe5d', '\U0000fe5d'),
+    ('\U0000ff08', '\U0000ff08'),
+    ('\U0000ff3b', '\U0000ff3b'),
+    ('\U0000ff5b', '\U0000ff5b'),
+    ('\U0000ff5f', '\U0000ff5f'),
+    ('\U0000ff62', '\U0000ff62')
+    ]),
+("Rejang", &[
+    ('\U0000a930', '\U0000a953'),
+    ('\U0000a95f', '\U0000a95f')
+    ]),
+("Runic", &[
+    ('\U000016a0', '\U000016ea'),
+    ('\U000016ee', '\U000016f0')
+    ]),
+("S", &[
+    ('\U00000024', '\U00000024'),
+    ('\U0000002b', '\U0000002b'),
+    ('\U0000003c', '\U0000003e'),
+    ('\U0000005e', '\U0000005e'),
+    ('\U00000060', '\U00000060'),
+    ('\U0000007c', '\U0000007c'),
+    ('\U0000007e', '\U0000007e'),
+    ('\U000000a2', '\U000000a6'),
+    ('\U000000a8', '\U000000a9'),
+    ('\U000000ac', '\U000000ac'),
+    ('\U000000ae', '\U000000b1'),
+    ('\U000000b4', '\U000000b4'),
+    ('\U000000b8', '\U000000b8'),
+    ('\U000000d7', '\U000000d7'),
+    ('\U000000f7', '\U000000f7'),
+    ('\U000002c2', '\U000002c5'),
+    ('\U000002d2', '\U000002df'),
+    ('\U000002e5', '\U000002eb'),
+    ('\U000002ed', '\U000002ed'),
+    ('\U000002ef', '\U000002ff'),
+    ('\U00000375', '\U00000375'),
+    ('\U00000384', '\U00000385'),
+    ('\U000003f6', '\U000003f6'),
+    ('\U00000482', '\U00000482'),
+    ('\U0000058f', '\U0000058f'),
+    ('\U00000606', '\U00000608'),
+    ('\U0000060b', '\U0000060b'),
+    ('\U0000060e', '\U0000060f'),
+    ('\U000006de', '\U000006de'),
+    ('\U000006e9', '\U000006e9'),
+    ('\U000006fd', '\U000006fe'),
+    ('\U000007f6', '\U000007f6'),
+    ('\U000009f2', '\U000009f3'),
+    ('\U000009fa', '\U000009fb'),
+    ('\U00000af1', '\U00000af1'),
+    ('\U00000b70', '\U00000b70'),
+    ('\U00000bf3', '\U00000bfa'),
+    ('\U00000c7f', '\U00000c7f'),
+    ('\U00000d79', '\U00000d79'),
+    ('\U00000e3f', '\U00000e3f'),
+    ('\U00000f01', '\U00000f03'),
+    ('\U00000f13', '\U00000f13'),
+    ('\U00000f15', '\U00000f17'),
+    ('\U00000f1a', '\U00000f1f'),
+    ('\U00000f34', '\U00000f34'),
+    ('\U00000f36', '\U00000f36'),
+    ('\U00000f38', '\U00000f38'),
+    ('\U00000fbe', '\U00000fc5'),
+    ('\U00000fc7', '\U00000fcc'),
+    ('\U00000fce', '\U00000fcf'),
+    ('\U00000fd5', '\U00000fd8'),
+    ('\U0000109e', '\U0000109f'),
+    ('\U00001390', '\U00001399'),
+    ('\U000017db', '\U000017db'),
+    ('\U00001940', '\U00001940'),
+    ('\U000019de', '\U000019ff'),
+    ('\U00001b61', '\U00001b6a'),
+    ('\U00001b74', '\U00001b7c'),
+    ('\U00001fbd', '\U00001fbd'),
+    ('\U00001fbf', '\U00001fc1'),
+    ('\U00001fcd', '\U00001fcf'),
+    ('\U00001fdd', '\U00001fdf'),
+    ('\U00001fed', '\U00001fef'),
+    ('\U00001ffd', '\U00001ffe'),
+    ('\U00002044', '\U00002044'),
+    ('\U00002052', '\U00002052'),
+    ('\U0000207a', '\U0000207c'),
+    ('\U0000208a', '\U0000208c'),
+    ('\U000020a0', '\U000020ba'),
+    ('\U00002100', '\U00002101'),
+    ('\U00002103', '\U00002106'),
+    ('\U00002108', '\U00002109'),
+    ('\U00002114', '\U00002114'),
+    ('\U00002116', '\U00002118'),
+    ('\U0000211e', '\U00002123'),
+    ('\U00002125', '\U00002125'),
+    ('\U00002127', '\U00002127'),
+    ('\U00002129', '\U00002129'),
+    ('\U0000212e', '\U0000212e'),
+    ('\U0000213a', '\U0000213b'),
+    ('\U00002140', '\U00002144'),
+    ('\U0000214a', '\U0000214d'),
+    ('\U0000214f', '\U0000214f'),
+    ('\U00002190', '\U00002307'),
+    ('\U0000230c', '\U00002328'),
+    ('\U0000232b', '\U000023f3'),
+    ('\U00002400', '\U00002426'),
+    ('\U00002440', '\U0000244a'),
+    ('\U0000249c', '\U000024e9'),
+    ('\U00002500', '\U000026ff'),
+    ('\U00002701', '\U00002767'),
+    ('\U00002794', '\U000027c4'),
+    ('\U000027c7', '\U000027e5'),
+    ('\U000027f0', '\U00002982'),
+    ('\U00002999', '\U000029d7'),
+    ('\U000029dc', '\U000029fb'),
+    ('\U000029fe', '\U00002b4c'),
+    ('\U00002b50', '\U00002b59'),
+    ('\U00002ce5', '\U00002cea'),
+    ('\U00002e80', '\U00002e99'),
+    ('\U00002e9b', '\U00002ef3'),
+    ('\U00002f00', '\U00002fd5'),
+    ('\U00002ff0', '\U00002ffb'),
+    ('\U00003004', '\U00003004'),
+    ('\U00003012', '\U00003013'),
+    ('\U00003020', '\U00003020'),
+    ('\U00003036', '\U00003037'),
+    ('\U0000303e', '\U0000303f'),
+    ('\U0000309b', '\U0000309c'),
+    ('\U00003190', '\U00003191'),
+    ('\U00003196', '\U0000319f'),
+    ('\U000031c0', '\U000031e3'),
+    ('\U00003200', '\U0000321e'),
+    ('\U0000322a', '\U00003247'),
+    ('\U00003250', '\U00003250'),
+    ('\U00003260', '\U0000327f'),
+    ('\U0000328a', '\U000032b0'),
+    ('\U000032c0', '\U000032fe'),
+    ('\U00003300', '\U000033ff'),
+    ('\U00004dc0', '\U00004dff'),
+    ('\U0000a490', '\U0000a4c6'),
+    ('\U0000a700', '\U0000a716'),
+    ('\U0000a720', '\U0000a721'),
+    ('\U0000a789', '\U0000a78a'),
+    ('\U0000a828', '\U0000a82b'),
+    ('\U0000a836', '\U0000a839'),
+    ('\U0000aa77', '\U0000aa79'),
+    ('\U0000fb29', '\U0000fb29'),
+    ('\U0000fbb2', '\U0000fbc1'),
+    ('\U0000fdfc', '\U0000fdfd'),
+    ('\U0000fe62', '\U0000fe62'),
+    ('\U0000fe64', '\U0000fe66'),
+    ('\U0000fe69', '\U0000fe69'),
+    ('\U0000ff04', '\U0000ff04'),
+    ('\U0000ff0b', '\U0000ff0b'),
+    ('\U0000ff1c', '\U0000ff1e'),
+    ('\U0000ff3e', '\U0000ff3e'),
+    ('\U0000ff40', '\U0000ff40'),
+    ('\U0000ff5c', '\U0000ff5c'),
+    ('\U0000ff5e', '\U0000ff5e'),
+    ('\U0000ffe0', '\U0000ffe6'),
+    ('\U0000ffe8', '\U0000ffee'),
+    ('\U0000fffc', '\U0000fffd'),
+    ('\U00010137', '\U0001013f'),
+    ('\U00010179', '\U00010189'),
+    ('\U00010190', '\U0001019b'),
+    ('\U000101d0', '\U000101fc'),
+    ('\U0001d000', '\U0001d0f5'),
+    ('\U0001d100', '\U0001d126'),
+    ('\U0001d129', '\U0001d164'),
+    ('\U0001d16a', '\U0001d16c'),
+    ('\U0001d183', '\U0001d184'),
+    ('\U0001d18c', '\U0001d1a9'),
+    ('\U0001d1ae', '\U0001d1dd'),
+    ('\U0001d200', '\U0001d241'),
+    ('\U0001d245', '\U0001d245'),
+    ('\U0001d300', '\U0001d356'),
+    ('\U0001d6c1', '\U0001d6c1'),
+    ('\U0001d6db', '\U0001d6db'),
+    ('\U0001d6fb', '\U0001d6fb'),
+    ('\U0001d715', '\U0001d715'),
+    ('\U0001d735', '\U0001d735'),
+    ('\U0001d74f', '\U0001d74f'),
+    ('\U0001d76f', '\U0001d76f'),
+    ('\U0001d789', '\U0001d789'),
+    ('\U0001d7a9', '\U0001d7a9'),
+    ('\U0001d7c3', '\U0001d7c3'),
+    ('\U0001eef0', '\U0001eef1'),
+    ('\U0001f000', '\U0001f02b'),
+    ('\U0001f030', '\U0001f093'),
+    ('\U0001f0a0', '\U0001f0ae'),
+    ('\U0001f0b1', '\U0001f0be'),
+    ('\U0001f0c1', '\U0001f0cf'),
+    ('\U0001f0d1', '\U0001f0df'),
+    ('\U0001f110', '\U0001f12e'),
+    ('\U0001f130', '\U0001f16b'),
+    ('\U0001f170', '\U0001f19a'),
+    ('\U0001f1e6', '\U0001f202'),
+    ('\U0001f210', '\U0001f23a'),
+    ('\U0001f240', '\U0001f248'),
+    ('\U0001f250', '\U0001f251'),
+    ('\U0001f300', '\U0001f320'),
+    ('\U0001f330', '\U0001f335'),
+    ('\U0001f337', '\U0001f37c'),
+    ('\U0001f380', '\U0001f393'),
+    ('\U0001f3a0', '\U0001f3c4'),
+    ('\U0001f3c6', '\U0001f3ca'),
+    ('\U0001f3e0', '\U0001f3f0'),
+    ('\U0001f400', '\U0001f43e'),
+    ('\U0001f440', '\U0001f440'),
+    ('\U0001f442', '\U0001f4f7'),
+    ('\U0001f4f9', '\U0001f4fc'),
+    ('\U0001f500', '\U0001f53d'),
+    ('\U0001f540', '\U0001f543'),
+    ('\U0001f550', '\U0001f567'),
+    ('\U0001f5fb', '\U0001f640'),
+    ('\U0001f645', '\U0001f64f'),
+    ('\U0001f680', '\U0001f6c5'),
+    ('\U0001f700', '\U0001f773')
+    ]),
+("Samaritan", &[
+    ('\U00000800', '\U0000082d'),
+    ('\U00000830', '\U0000083e')
+    ]),
+("Saurashtra", &[
+    ('\U0000a880', '\U0000a8c4'),
+    ('\U0000a8ce', '\U0000a8d9')
+    ]),
+("Sc", &[
+    ('\U00000024', '\U00000024'),
+    ('\U000000a2', '\U000000a5'),
+    ('\U0000058f', '\U0000058f'),
+    ('\U0000060b', '\U0000060b'),
+    ('\U000009f2', '\U000009f3'),
+    ('\U000009fb', '\U000009fb'),
+    ('\U00000af1', '\U00000af1'),
+    ('\U00000bf9', '\U00000bf9'),
+    ('\U00000e3f', '\U00000e3f'),
+    ('\U000017db', '\U000017db'),
+    ('\U000020a0', '\U000020ba'),
+    ('\U0000a838', '\U0000a838'),
+    ('\U0000fdfc', '\U0000fdfc'),
+    ('\U0000fe69', '\U0000fe69'),
+    ('\U0000ff04', '\U0000ff04'),
+    ('\U0000ffe0', '\U0000ffe1'),
+    ('\U0000ffe5', '\U0000ffe6')
+    ]),
+("Sharada", &[
+    ('\U00011180', '\U000111c8'),
+    ('\U000111d0', '\U000111d9')
+    ]),
+("Shavian", &[
+    ('\U00010450', '\U0001047f')
+    ]),
+("Sinhala", &[
+    ('\U00000d82', '\U00000d83'),
+    ('\U00000d85', '\U00000d96'),
+    ('\U00000d9a', '\U00000db1'),
+    ('\U00000db3', '\U00000dbb'),
+    ('\U00000dbd', '\U00000dbd'),
+    ('\U00000dc0', '\U00000dc6'),
+    ('\U00000dca', '\U00000dca'),
+    ('\U00000dcf', '\U00000dd4'),
+    ('\U00000dd6', '\U00000dd6'),
+    ('\U00000dd8', '\U00000ddf'),
+    ('\U00000df2', '\U00000df4')
+    ]),
+("Sk", &[
+    ('\U0000005e', '\U0000005e'),
+    ('\U00000060', '\U00000060'),
+    ('\U000000a8', '\U000000a8'),
+    ('\U000000af', '\U000000af'),
+    ('\U000000b4', '\U000000b4'),
+    ('\U000000b8', '\U000000b8'),
+    ('\U000002c2', '\U000002c5'),
+    ('\U000002d2', '\U000002df'),
+    ('\U000002e5', '\U000002eb'),
+    ('\U000002ed', '\U000002ed'),
+    ('\U000002ef', '\U000002ff'),
+    ('\U00000375', '\U00000375'),
+    ('\U00000384', '\U00000385'),
+    ('\U00001fbd', '\U00001fbd'),
+    ('\U00001fbf', '\U00001fc1'),
+    ('\U00001fcd', '\U00001fcf'),
+    ('\U00001fdd', '\U00001fdf'),
+    ('\U00001fed', '\U00001fef'),
+    ('\U00001ffd', '\U00001ffe'),
+    ('\U0000309b', '\U0000309c'),
+    ('\U0000a700', '\U0000a716'),
+    ('\U0000a720', '\U0000a721'),
+    ('\U0000a789', '\U0000a78a'),
+    ('\U0000fbb2', '\U0000fbc1'),
+    ('\U0000ff3e', '\U0000ff3e'),
+    ('\U0000ff40', '\U0000ff40'),
+    ('\U0000ffe3', '\U0000ffe3')
+    ]),
+("Sm", &[
+    ('\U0000002b', '\U0000002b'),
+    ('\U0000003c', '\U0000003e'),
+    ('\U0000007c', '\U0000007c'),
+    ('\U0000007e', '\U0000007e'),
+    ('\U000000ac', '\U000000ac'),
+    ('\U000000b1', '\U000000b1'),
+    ('\U000000d7', '\U000000d7'),
+    ('\U000000f7', '\U000000f7'),
+    ('\U000003f6', '\U000003f6'),
+    ('\U00000606', '\U00000608'),
+    ('\U00002044', '\U00002044'),
+    ('\U00002052', '\U00002052'),
+    ('\U0000207a', '\U0000207c'),
+    ('\U0000208a', '\U0000208c'),
+    ('\U00002118', '\U00002118'),
+    ('\U00002140', '\U00002144'),
+    ('\U0000214b', '\U0000214b'),
+    ('\U00002190', '\U00002194'),
+    ('\U0000219a', '\U0000219b'),
+    ('\U000021a0', '\U000021a0'),
+    ('\U000021a3', '\U000021a3'),
+    ('\U000021a6', '\U000021a6'),
+    ('\U000021ae', '\U000021ae'),
+    ('\U000021ce', '\U000021cf'),
+    ('\U000021d2', '\U000021d2'),
+    ('\U000021d4', '\U000021d4'),
+    ('\U000021f4', '\U000022ff'),
+    ('\U00002320', '\U00002321'),
+    ('\U0000237c', '\U0000237c'),
+    ('\U0000239b', '\U000023b3'),
+    ('\U000023dc', '\U000023e1'),
+    ('\U000025b7', '\U000025b7'),
+    ('\U000025c1', '\U000025c1'),
+    ('\U000025f8', '\U000025ff'),
+    ('\U0000266f', '\U0000266f'),
+    ('\U000027c0', '\U000027c4'),
+    ('\U000027c7', '\U000027e5'),
+    ('\U000027f0', '\U000027ff'),
+    ('\U00002900', '\U00002982'),
+    ('\U00002999', '\U000029d7'),
+    ('\U000029dc', '\U000029fb'),
+    ('\U000029fe', '\U00002aff'),
+    ('\U00002b30', '\U00002b44'),
+    ('\U00002b47', '\U00002b4c'),
+    ('\U0000fb29', '\U0000fb29'),
+    ('\U0000fe62', '\U0000fe62'),
+    ('\U0000fe64', '\U0000fe66'),
+    ('\U0000ff0b', '\U0000ff0b'),
+    ('\U0000ff1c', '\U0000ff1e'),
+    ('\U0000ff5c', '\U0000ff5c'),
+    ('\U0000ff5e', '\U0000ff5e'),
+    ('\U0000ffe2', '\U0000ffe2'),
+    ('\U0000ffe9', '\U0000ffec'),
+    ('\U0001d6c1', '\U0001d6c1'),
+    ('\U0001d6db', '\U0001d6db'),
+    ('\U0001d6fb', '\U0001d6fb'),
+    ('\U0001d715', '\U0001d715'),
+    ('\U0001d735', '\U0001d735'),
+    ('\U0001d74f', '\U0001d74f'),
+    ('\U0001d76f', '\U0001d76f'),
+    ('\U0001d789', '\U0001d789'),
+    ('\U0001d7a9', '\U0001d7a9'),
+    ('\U0001d7c3', '\U0001d7c3'),
+    ('\U0001eef0', '\U0001eef1')
+    ]),
+("So", &[
+    ('\U000000a6', '\U000000a6'),
+    ('\U000000a9', '\U000000a9'),
+    ('\U000000ae', '\U000000ae'),
+    ('\U000000b0', '\U000000b0'),
+    ('\U00000482', '\U00000482'),
+    ('\U0000060e', '\U0000060f'),
+    ('\U000006de', '\U000006de'),
+    ('\U000006e9', '\U000006e9'),
+    ('\U000006fd', '\U000006fe'),
+    ('\U000007f6', '\U000007f6'),
+    ('\U000009fa', '\U000009fa'),
+    ('\U00000b70', '\U00000b70'),
+    ('\U00000bf3', '\U00000bf8'),
+    ('\U00000bfa', '\U00000bfa'),
+    ('\U00000c7f', '\U00000c7f'),
+    ('\U00000d79', '\U00000d79'),
+    ('\U00000f01', '\U00000f03'),
+    ('\U00000f13', '\U00000f13'),
+    ('\U00000f15', '\U00000f17'),
+    ('\U00000f1a', '\U00000f1f'),
+    ('\U00000f34', '\U00000f34'),
+    ('\U00000f36', '\U00000f36'),
+    ('\U00000f38', '\U00000f38'),
+    ('\U00000fbe', '\U00000fc5'),
+    ('\U00000fc7', '\U00000fcc'),
+    ('\U00000fce', '\U00000fcf'),
+    ('\U00000fd5', '\U00000fd8'),
+    ('\U0000109e', '\U0000109f'),
+    ('\U00001390', '\U00001399'),
+    ('\U00001940', '\U00001940'),
+    ('\U000019de', '\U000019ff'),
+    ('\U00001b61', '\U00001b6a'),
+    ('\U00001b74', '\U00001b7c'),
+    ('\U00002100', '\U00002101'),
+    ('\U00002103', '\U00002106'),
+    ('\U00002108', '\U00002109'),
+    ('\U00002114', '\U00002114'),
+    ('\U00002116', '\U00002117'),
+    ('\U0000211e', '\U00002123'),
+    ('\U00002125', '\U00002125'),
+    ('\U00002127', '\U00002127'),
+    ('\U00002129', '\U00002129'),
+    ('\U0000212e', '\U0000212e'),
+    ('\U0000213a', '\U0000213b'),
+    ('\U0000214a', '\U0000214a'),
+    ('\U0000214c', '\U0000214d'),
+    ('\U0000214f', '\U0000214f'),
+    ('\U00002195', '\U00002199'),
+    ('\U0000219c', '\U0000219f'),
+    ('\U000021a1', '\U000021a2'),
+    ('\U000021a4', '\U000021a5'),
+    ('\U000021a7', '\U000021ad'),
+    ('\U000021af', '\U000021cd'),
+    ('\U000021d0', '\U000021d1'),
+    ('\U000021d3', '\U000021d3'),
+    ('\U000021d5', '\U000021f3'),
+    ('\U00002300', '\U00002307'),
+    ('\U0000230c', '\U0000231f'),
+    ('\U00002322', '\U00002328'),
+    ('\U0000232b', '\U0000237b'),
+    ('\U0000237d', '\U0000239a'),
+    ('\U000023b4', '\U000023db'),
+    ('\U000023e2', '\U000023f3'),
+    ('\U00002400', '\U00002426'),
+    ('\U00002440', '\U0000244a'),
+    ('\U0000249c', '\U000024e9'),
+    ('\U00002500', '\U000025b6'),
+    ('\U000025b8', '\U000025c0'),
+    ('\U000025c2', '\U000025f7'),
+    ('\U00002600', '\U0000266e'),
+    ('\U00002670', '\U000026ff'),
+    ('\U00002701', '\U00002767'),
+    ('\U00002794', '\U000027bf'),
+    ('\U00002800', '\U000028ff'),
+    ('\U00002b00', '\U00002b2f'),
+    ('\U00002b45', '\U00002b46'),
+    ('\U00002b50', '\U00002b59'),
+    ('\U00002ce5', '\U00002cea'),
+    ('\U00002e80', '\U00002e99'),
+    ('\U00002e9b', '\U00002ef3'),
+    ('\U00002f00', '\U00002fd5'),
+    ('\U00002ff0', '\U00002ffb'),
+    ('\U00003004', '\U00003004'),
+    ('\U00003012', '\U00003013'),
+    ('\U00003020', '\U00003020'),
+    ('\U00003036', '\U00003037'),
+    ('\U0000303e', '\U0000303f'),
+    ('\U00003190', '\U00003191'),
+    ('\U00003196', '\U0000319f'),
+    ('\U000031c0', '\U000031e3'),
+    ('\U00003200', '\U0000321e'),
+    ('\U0000322a', '\U00003247'),
+    ('\U00003250', '\U00003250'),
+    ('\U00003260', '\U0000327f'),
+    ('\U0000328a', '\U000032b0'),
+    ('\U000032c0', '\U000032fe'),
+    ('\U00003300', '\U000033ff'),
+    ('\U00004dc0', '\U00004dff'),
+    ('\U0000a490', '\U0000a4c6'),
+    ('\U0000a828', '\U0000a82b'),
+    ('\U0000a836', '\U0000a837'),
+    ('\U0000a839', '\U0000a839'),
+    ('\U0000aa77', '\U0000aa79'),
+    ('\U0000fdfd', '\U0000fdfd'),
+    ('\U0000ffe4', '\U0000ffe4'),
+    ('\U0000ffe8', '\U0000ffe8'),
+    ('\U0000ffed', '\U0000ffee'),
+    ('\U0000fffc', '\U0000fffd'),
+    ('\U00010137', '\U0001013f'),
+    ('\U00010179', '\U00010189'),
+    ('\U00010190', '\U0001019b'),
+    ('\U000101d0', '\U000101fc'),
+    ('\U0001d000', '\U0001d0f5'),
+    ('\U0001d100', '\U0001d126'),
+    ('\U0001d129', '\U0001d164'),
+    ('\U0001d16a', '\U0001d16c'),
+    ('\U0001d183', '\U0001d184'),
+    ('\U0001d18c', '\U0001d1a9'),
+    ('\U0001d1ae', '\U0001d1dd'),
+    ('\U0001d200', '\U0001d241'),
+    ('\U0001d245', '\U0001d245'),
+    ('\U0001d300', '\U0001d356'),
+    ('\U0001f000', '\U0001f02b'),
+    ('\U0001f030', '\U0001f093'),
+    ('\U0001f0a0', '\U0001f0ae'),
+    ('\U0001f0b1', '\U0001f0be'),
+    ('\U0001f0c1', '\U0001f0cf'),
+    ('\U0001f0d1', '\U0001f0df'),
+    ('\U0001f110', '\U0001f12e'),
+    ('\U0001f130', '\U0001f16b'),
+    ('\U0001f170', '\U0001f19a'),
+    ('\U0001f1e6', '\U0001f202'),
+    ('\U0001f210', '\U0001f23a'),
+    ('\U0001f240', '\U0001f248'),
+    ('\U0001f250', '\U0001f251'),
+    ('\U0001f300', '\U0001f320'),
+    ('\U0001f330', '\U0001f335'),
+    ('\U0001f337', '\U0001f37c'),
+    ('\U0001f380', '\U0001f393'),
+    ('\U0001f3a0', '\U0001f3c4'),
+    ('\U0001f3c6', '\U0001f3ca'),
+    ('\U0001f3e0', '\U0001f3f0'),
+    ('\U0001f400', '\U0001f43e'),
+    ('\U0001f440', '\U0001f440'),
+    ('\U0001f442', '\U0001f4f7'),
+    ('\U0001f4f9', '\U0001f4fc'),
+    ('\U0001f500', '\U0001f53d'),
+    ('\U0001f540', '\U0001f543'),
+    ('\U0001f550', '\U0001f567'),
+    ('\U0001f5fb', '\U0001f640'),
+    ('\U0001f645', '\U0001f64f'),
+    ('\U0001f680', '\U0001f6c5'),
+    ('\U0001f700', '\U0001f773')
+    ]),
+("Sora_Sompeng", &[
+    ('\U000110d0', '\U000110e8'),
+    ('\U000110f0', '\U000110f9')
+    ]),
+("Sundanese", &[
+    ('\U00001b80', '\U00001bbf'),
+    ('\U00001cc0', '\U00001cc7')
+    ]),
+("Syloti_Nagri", &[
+    ('\U0000a800', '\U0000a82b')
+    ]),
+("Syriac", &[
+    ('\U00000700', '\U0000070d'),
+    ('\U0000070f', '\U0000074a'),
+    ('\U0000074d', '\U0000074f')
+    ]),
+("Tagalog", &[
+    ('\U00001700', '\U0000170c'),
+    ('\U0000170e', '\U00001714')
+    ]),
+("Tagbanwa", &[
+    ('\U00001760', '\U0000176c'),
+    ('\U0000176e', '\U00001770'),
+    ('\U00001772', '\U00001773')
+    ]),
+("Tai_Le", &[
+    ('\U00001950', '\U0000196d'),
+    ('\U00001970', '\U00001974')
+    ]),
+("Tai_Tham", &[
+    ('\U00001a20', '\U00001a5e'),
+    ('\U00001a60', '\U00001a7c'),
+    ('\U00001a7f', '\U00001a89'),
+    ('\U00001a90', '\U00001a99'),
+    ('\U00001aa0', '\U00001aad')
+    ]),
+("Tai_Viet", &[
+    ('\U0000aa80', '\U0000aac2'),
+    ('\U0000aadb', '\U0000aadf')
+    ]),
+("Takri", &[
+    ('\U00011680', '\U000116b7'),
+    ('\U000116c0', '\U000116c9')
+    ]),
+("Tamil", &[
+    ('\U00000b82', '\U00000b83'),
+    ('\U00000b85', '\U00000b8a'),
+    ('\U00000b8e', '\U00000b90'),
+    ('\U00000b92', '\U00000b95'),
+    ('\U00000b99', '\U00000b9a'),
+    ('\U00000b9c', '\U00000b9c'),
+    ('\U00000b9e', '\U00000b9f'),
+    ('\U00000ba3', '\U00000ba4'),
+    ('\U00000ba8', '\U00000baa'),
+    ('\U00000bae', '\U00000bb9'),
+    ('\U00000bbe', '\U00000bc2'),
+    ('\U00000bc6', '\U00000bc8'),
+    ('\U00000bca', '\U00000bcd'),
+    ('\U00000bd0', '\U00000bd0'),
+    ('\U00000bd7', '\U00000bd7'),
+    ('\U00000be6', '\U00000bfa')
+    ]),
+("Telugu", &[
+    ('\U00000c01', '\U00000c03'),
+    ('\U00000c05', '\U00000c0c'),
+    ('\U00000c0e', '\U00000c10'),
+    ('\U00000c12', '\U00000c28'),
+    ('\U00000c2a', '\U00000c33'),
+    ('\U00000c35', '\U00000c39'),
+    ('\U00000c3d', '\U00000c44'),
+    ('\U00000c46', '\U00000c48'),
+    ('\U00000c4a', '\U00000c4d'),
+    ('\U00000c55', '\U00000c56'),
+    ('\U00000c58', '\U00000c59'),
+    ('\U00000c60', '\U00000c63'),
+    ('\U00000c66', '\U00000c6f'),
+    ('\U00000c78', '\U00000c7f')
+    ]),
+("Thaana", &[
+    ('\U00000780', '\U000007b1')
+    ]),
+("Thai", &[
+    ('\U00000e01', '\U00000e3a'),
+    ('\U00000e40', '\U00000e5b')
+    ]),
+("Tibetan", &[
+    ('\U00000f00', '\U00000f47'),
+    ('\U00000f49', '\U00000f6c'),
+    ('\U00000f71', '\U00000f97'),
+    ('\U00000f99', '\U00000fbc'),
+    ('\U00000fbe', '\U00000fcc'),
+    ('\U00000fce', '\U00000fd4'),
+    ('\U00000fd9', '\U00000fda')
+    ]),
+("Tifinagh", &[
+    ('\U00002d30', '\U00002d67'),
+    ('\U00002d6f', '\U00002d70'),
+    ('\U00002d7f', '\U00002d7f')
+    ]),
+("Ugaritic", &[
+    ('\U00010380', '\U0001039d'),
+    ('\U0001039f', '\U0001039f')
+    ]),
+("Vai", &[
+    ('\U0000a500', '\U0000a62b')
+    ]),
+("Yi", &[
+    ('\U0000a000', '\U0000a48c'),
+    ('\U0000a490', '\U0000a4c6')
+    ]),
+("Z", &[
+    ('\U00000020', '\U00000020'),
+    ('\U000000a0', '\U000000a0'),
+    ('\U00001680', '\U00001680'),
+    ('\U00002000', '\U0000200a'),
+    ('\U00002028', '\U00002029'),
+    ('\U0000202f', '\U0000202f'),
+    ('\U0000205f', '\U0000205f'),
+    ('\U00003000', '\U00003000')
+    ]),
+("Zl", &[
+    ('\U00002028', '\U00002028')
+    ]),
+("Zp", &[
+    ('\U00002029', '\U00002029')
+    ]),
+("Zs", &[
+    ('\U00000020', '\U00000020'),
+    ('\U000000a0', '\U000000a0'),
+    ('\U00001680', '\U00001680'),
+    ('\U00002000', '\U0000200a'),
+    ('\U0000202f', '\U0000202f'),
+    ('\U0000205f', '\U0000205f'),
+    ('\U00003000', '\U00003000')
+    ]),
+
+];
+
+pub static PERLD: Class = &[
+    ('\U00000030', '\U00000039'),
+    ('\U00000660', '\U00000669'),
+    ('\U000006f0', '\U000006f9'),
+    ('\U000007c0', '\U000007c9'),
+    ('\U00000966', '\U0000096f'),
+    ('\U000009e6', '\U000009ef'),
+    ('\U00000a66', '\U00000a6f'),
+    ('\U00000ae6', '\U00000aef'),
+    ('\U00000b66', '\U00000b6f'),
+    ('\U00000be6', '\U00000bef'),
+    ('\U00000c66', '\U00000c6f'),
+    ('\U00000ce6', '\U00000cef'),
+    ('\U00000d66', '\U00000d6f'),
+    ('\U00000e50', '\U00000e59'),
+    ('\U00000ed0', '\U00000ed9'),
+    ('\U00000f20', '\U00000f29'),
+    ('\U00001040', '\U00001049'),
+    ('\U00001090', '\U00001099'),
+    ('\U000017e0', '\U000017e9'),
+    ('\U00001810', '\U00001819'),
+    ('\U00001946', '\U0000194f'),
+    ('\U000019d0', '\U000019d9'),
+    ('\U00001a80', '\U00001a89'),
+    ('\U00001a90', '\U00001a99'),
+    ('\U00001b50', '\U00001b59'),
+    ('\U00001bb0', '\U00001bb9'),
+    ('\U00001c40', '\U00001c49'),
+    ('\U00001c50', '\U00001c59'),
+    ('\U0000a620', '\U0000a629'),
+    ('\U0000a8d0', '\U0000a8d9'),
+    ('\U0000a900', '\U0000a909'),
+    ('\U0000a9d0', '\U0000a9d9'),
+    ('\U0000aa50', '\U0000aa59'),
+    ('\U0000abf0', '\U0000abf9'),
+    ('\U0000ff10', '\U0000ff19'),
+    ('\U000104a0', '\U000104a9'),
+    ('\U00011066', '\U0001106f'),
+    ('\U000110f0', '\U000110f9'),
+    ('\U00011136', '\U0001113f'),
+    ('\U000111d0', '\U000111d9'),
+    ('\U000116c0', '\U000116c9'),
+    ('\U0001d7ce', '\U0001d7ff')
+];
+
+pub static PERLS: Class = &[
+    ('\U00000009', '\U0000000a'),
+    ('\U0000000c', '\U0000000d'),
+    ('\U00000020', '\U00000020'),
+    ('\U000000a0', '\U000000a0'),
+    ('\U00001680', '\U00001680'),
+    ('\U00002000', '\U0000200a'),
+    ('\U00002028', '\U00002029'),
+    ('\U0000202f', '\U0000202f'),
+    ('\U0000205f', '\U0000205f'),
+    ('\U00003000', '\U00003000')
+];
+
+pub static PERLW: Class = &[
+    ('\U00000030', '\U00000039'),
+    ('\U00000041', '\U0000005a'),
+    ('\U0000005f', '\U0000005f'),
+    ('\U00000061', '\U0000007a'),
+    ('\U000000aa', '\U000000aa'),
+    ('\U000000b5', '\U000000b5'),
+    ('\U000000ba', '\U000000ba'),
+    ('\U000000c0', '\U000000d6'),
+    ('\U000000d8', '\U000000f6'),
+    ('\U000000f8', '\U000002c1'),
+    ('\U000002c6', '\U000002d1'),
+    ('\U000002e0', '\U000002e4'),
+    ('\U000002ec', '\U000002ec'),
+    ('\U000002ee', '\U000002ee'),
+    ('\U00000370', '\U00000374'),
+    ('\U00000376', '\U00000377'),
+    ('\U0000037a', '\U0000037d'),
+    ('\U00000386', '\U00000386'),
+    ('\U00000388', '\U0000038a'),
+    ('\U0000038c', '\U0000038c'),
+    ('\U0000038e', '\U000003a1'),
+    ('\U000003a3', '\U000003f5'),
+    ('\U000003f7', '\U00000481'),
+    ('\U0000048a', '\U00000527'),
+    ('\U00000531', '\U00000556'),
+    ('\U00000559', '\U00000559'),
+    ('\U00000561', '\U00000587'),
+    ('\U000005d0', '\U000005ea'),
+    ('\U000005f0', '\U000005f2'),
+    ('\U00000620', '\U0000064a'),
+    ('\U0000066e', '\U0000066f'),
+    ('\U00000671', '\U000006d3'),
+    ('\U000006d5', '\U000006d5'),
+    ('\U000006e5', '\U000006e6'),
+    ('\U000006ee', '\U000006ef'),
+    ('\U000006fa', '\U000006fc'),
+    ('\U000006ff', '\U000006ff'),
+    ('\U00000710', '\U00000710'),
+    ('\U00000712', '\U0000072f'),
+    ('\U0000074d', '\U000007a5'),
+    ('\U000007b1', '\U000007b1'),
+    ('\U000007ca', '\U000007ea'),
+    ('\U000007f4', '\U000007f5'),
+    ('\U000007fa', '\U000007fa'),
+    ('\U00000800', '\U00000815'),
+    ('\U0000081a', '\U0000081a'),
+    ('\U00000824', '\U00000824'),
+    ('\U00000828', '\U00000828'),
+    ('\U00000840', '\U00000858'),
+    ('\U000008a0', '\U000008a0'),
+    ('\U000008a2', '\U000008ac'),
+    ('\U00000904', '\U00000939'),
+    ('\U0000093d', '\U0000093d'),
+    ('\U00000950', '\U00000950'),
+    ('\U00000958', '\U00000961'),
+    ('\U00000971', '\U00000977'),
+    ('\U00000979', '\U0000097f'),
+    ('\U00000985', '\U0000098c'),
+    ('\U0000098f', '\U00000990'),
+    ('\U00000993', '\U000009a8'),
+    ('\U000009aa', '\U000009b0'),
+    ('\U000009b2', '\U000009b2'),
+    ('\U000009b6', '\U000009b9'),
+    ('\U000009bd', '\U000009bd'),
+    ('\U000009ce', '\U000009ce'),
+    ('\U000009dc', '\U000009dd'),
+    ('\U000009df', '\U000009e1'),
+    ('\U000009f0', '\U000009f1'),
+    ('\U00000a05', '\U00000a0a'),
+    ('\U00000a0f', '\U00000a10'),
+    ('\U00000a13', '\U00000a28'),
+    ('\U00000a2a', '\U00000a30'),
+    ('\U00000a32', '\U00000a33'),
+    ('\U00000a35', '\U00000a36'),
+    ('\U00000a38', '\U00000a39'),
+    ('\U00000a59', '\U00000a5c'),
+    ('\U00000a5e', '\U00000a5e'),
+    ('\U00000a72', '\U00000a74'),
+    ('\U00000a85', '\U00000a8d'),
+    ('\U00000a8f', '\U00000a91'),
+    ('\U00000a93', '\U00000aa8'),
+    ('\U00000aaa', '\U00000ab0'),
+    ('\U00000ab2', '\U00000ab3'),
+    ('\U00000ab5', '\U00000ab9'),
+    ('\U00000abd', '\U00000abd'),
+    ('\U00000ad0', '\U00000ad0'),
+    ('\U00000ae0', '\U00000ae1'),
+    ('\U00000b05', '\U00000b0c'),
+    ('\U00000b0f', '\U00000b10'),
+    ('\U00000b13', '\U00000b28'),
+    ('\U00000b2a', '\U00000b30'),
+    ('\U00000b32', '\U00000b33'),
+    ('\U00000b35', '\U00000b39'),
+    ('\U00000b3d', '\U00000b3d'),
+    ('\U00000b5c', '\U00000b5d'),
+    ('\U00000b5f', '\U00000b61'),
+    ('\U00000b71', '\U00000b71'),
+    ('\U00000b83', '\U00000b83'),
+    ('\U00000b85', '\U00000b8a'),
+    ('\U00000b8e', '\U00000b90'),
+    ('\U00000b92', '\U00000b95'),
+    ('\U00000b99', '\U00000b9a'),
+    ('\U00000b9c', '\U00000b9c'),
+    ('\U00000b9e', '\U00000b9f'),
+    ('\U00000ba3', '\U00000ba4'),
+    ('\U00000ba8', '\U00000baa'),
+    ('\U00000bae', '\U00000bb9'),
+    ('\U00000bd0', '\U00000bd0'),
+    ('\U00000c05', '\U00000c0c'),
+    ('\U00000c0e', '\U00000c10'),
+    ('\U00000c12', '\U00000c28'),
+    ('\U00000c2a', '\U00000c33'),
+    ('\U00000c35', '\U00000c39'),
+    ('\U00000c3d', '\U00000c3d'),
+    ('\U00000c58', '\U00000c59'),
+    ('\U00000c60', '\U00000c61'),
+    ('\U00000c85', '\U00000c8c'),
+    ('\U00000c8e', '\U00000c90'),
+    ('\U00000c92', '\U00000ca8'),
+    ('\U00000caa', '\U00000cb3'),
+    ('\U00000cb5', '\U00000cb9'),
+    ('\U00000cbd', '\U00000cbd'),
+    ('\U00000cde', '\U00000cde'),
+    ('\U00000ce0', '\U00000ce1'),
+    ('\U00000cf1', '\U00000cf2'),
+    ('\U00000d05', '\U00000d0c'),
+    ('\U00000d0e', '\U00000d10'),
+    ('\U00000d12', '\U00000d3a'),
+    ('\U00000d3d', '\U00000d3d'),
+    ('\U00000d4e', '\U00000d4e'),
+    ('\U00000d60', '\U00000d61'),
+    ('\U00000d7a', '\U00000d7f'),
+    ('\U00000d85', '\U00000d96'),
+    ('\U00000d9a', '\U00000db1'),
+    ('\U00000db3', '\U00000dbb'),
+    ('\U00000dbd', '\U00000dbd'),
+    ('\U00000dc0', '\U00000dc6'),
+    ('\U00000e01', '\U00000e30'),
+    ('\U00000e32', '\U00000e33'),
+    ('\U00000e40', '\U00000e46'),
+    ('\U00000e81', '\U00000e82'),
+    ('\U00000e84', '\U00000e84'),
+    ('\U00000e87', '\U00000e88'),
+    ('\U00000e8a', '\U00000e8a'),
+    ('\U00000e8d', '\U00000e8d'),
+    ('\U00000e94', '\U00000e97'),
+    ('\U00000e99', '\U00000e9f'),
+    ('\U00000ea1', '\U00000ea3'),
+    ('\U00000ea5', '\U00000ea5'),
+    ('\U00000ea7', '\U00000ea7'),
+    ('\U00000eaa', '\U00000eab'),
+    ('\U00000ead', '\U00000eb0'),
+    ('\U00000eb2', '\U00000eb3'),
+    ('\U00000ebd', '\U00000ebd'),
+    ('\U00000ec0', '\U00000ec4'),
+    ('\U00000ec6', '\U00000ec6'),
+    ('\U00000edc', '\U00000edf'),
+    ('\U00000f00', '\U00000f00'),
+    ('\U00000f40', '\U00000f47'),
+    ('\U00000f49', '\U00000f6c'),
+    ('\U00000f88', '\U00000f8c'),
+    ('\U00001000', '\U0000102a'),
+    ('\U0000103f', '\U0000103f'),
+    ('\U00001050', '\U00001055'),
+    ('\U0000105a', '\U0000105d'),
+    ('\U00001061', '\U00001061'),
+    ('\U00001065', '\U00001066'),
+    ('\U0000106e', '\U00001070'),
+    ('\U00001075', '\U00001081'),
+    ('\U0000108e', '\U0000108e'),
+    ('\U000010a0', '\U000010c5'),
+    ('\U000010c7', '\U000010c7'),
+    ('\U000010cd', '\U000010cd'),
+    ('\U000010d0', '\U000010fa'),
+    ('\U000010fc', '\U00001248'),
+    ('\U0000124a', '\U0000124d'),
+    ('\U00001250', '\U00001256'),
+    ('\U00001258', '\U00001258'),
+    ('\U0000125a', '\U0000125d'),
+    ('\U00001260', '\U00001288'),
+    ('\U0000128a', '\U0000128d'),
+    ('\U00001290', '\U000012b0'),
+    ('\U000012b2', '\U000012b5'),
+    ('\U000012b8', '\U000012be'),
+    ('\U000012c0', '\U000012c0'),
+    ('\U000012c2', '\U000012c5'),
+    ('\U000012c8', '\U000012d6'),
+    ('\U000012d8', '\U00001310'),
+    ('\U00001312', '\U00001315'),
+    ('\U00001318', '\U0000135a'),
+    ('\U00001380', '\U0000138f'),
+    ('\U000013a0', '\U000013f4'),
+    ('\U00001401', '\U0000166c'),
+    ('\U0000166f', '\U0000167f'),
+    ('\U00001681', '\U0000169a'),
+    ('\U000016a0', '\U000016ea'),
+    ('\U00001700', '\U0000170c'),
+    ('\U0000170e', '\U00001711'),
+    ('\U00001720', '\U00001731'),
+    ('\U00001740', '\U00001751'),
+    ('\U00001760', '\U0000176c'),
+    ('\U0000176e', '\U00001770'),
+    ('\U00001780', '\U000017b3'),
+    ('\U000017d7', '\U000017d7'),
+    ('\U000017dc', '\U000017dc'),
+    ('\U00001820', '\U00001877'),
+    ('\U00001880', '\U000018a8'),
+    ('\U000018aa', '\U000018aa'),
+    ('\U000018b0', '\U000018f5'),
+    ('\U00001900', '\U0000191c'),
+    ('\U00001950', '\U0000196d'),
+    ('\U00001970', '\U00001974'),
+    ('\U00001980', '\U000019ab'),
+    ('\U000019c1', '\U000019c7'),
+    ('\U00001a00', '\U00001a16'),
+    ('\U00001a20', '\U00001a54'),
+    ('\U00001aa7', '\U00001aa7'),
+    ('\U00001b05', '\U00001b33'),
+    ('\U00001b45', '\U00001b4b'),
+    ('\U00001b83', '\U00001ba0'),
+    ('\U00001bae', '\U00001baf'),
+    ('\U00001bba', '\U00001be5'),
+    ('\U00001c00', '\U00001c23'),
+    ('\U00001c4d', '\U00001c4f'),
+    ('\U00001c5a', '\U00001c7d'),
+    ('\U00001ce9', '\U00001cec'),
+    ('\U00001cee', '\U00001cf1'),
+    ('\U00001cf5', '\U00001cf6'),
+    ('\U00001d00', '\U00001dbf'),
+    ('\U00001e00', '\U00001f15'),
+    ('\U00001f18', '\U00001f1d'),
+    ('\U00001f20', '\U00001f45'),
+    ('\U00001f48', '\U00001f4d'),
+    ('\U00001f50', '\U00001f57'),
+    ('\U00001f59', '\U00001f59'),
+    ('\U00001f5b', '\U00001f5b'),
+    ('\U00001f5d', '\U00001f5d'),
+    ('\U00001f5f', '\U00001f7d'),
+    ('\U00001f80', '\U00001fb4'),
+    ('\U00001fb6', '\U00001fbc'),
+    ('\U00001fbe', '\U00001fbe'),
+    ('\U00001fc2', '\U00001fc4'),
+    ('\U00001fc6', '\U00001fcc'),
+    ('\U00001fd0', '\U00001fd3'),
+    ('\U00001fd6', '\U00001fdb'),
+    ('\U00001fe0', '\U00001fec'),
+    ('\U00001ff2', '\U00001ff4'),
+    ('\U00001ff6', '\U00001ffc'),
+    ('\U00002071', '\U00002071'),
+    ('\U0000207f', '\U0000207f'),
+    ('\U00002090', '\U0000209c'),
+    ('\U00002102', '\U00002102'),
+    ('\U00002107', '\U00002107'),
+    ('\U0000210a', '\U00002113'),
+    ('\U00002115', '\U00002115'),
+    ('\U00002119', '\U0000211d'),
+    ('\U00002124', '\U00002124'),
+    ('\U00002126', '\U00002126'),
+    ('\U00002128', '\U00002128'),
+    ('\U0000212a', '\U0000212d'),
+    ('\U0000212f', '\U00002139'),
+    ('\U0000213c', '\U0000213f'),
+    ('\U00002145', '\U00002149'),
+    ('\U0000214e', '\U0000214e'),
+    ('\U00002183', '\U00002184'),
+    ('\U00002c00', '\U00002c2e'),
+    ('\U00002c30', '\U00002c5e'),
+    ('\U00002c60', '\U00002ce4'),
+    ('\U00002ceb', '\U00002cee'),
+    ('\U00002cf2', '\U00002cf3'),
+    ('\U00002d00', '\U00002d25'),
+    ('\U00002d27', '\U00002d27'),
+    ('\U00002d2d', '\U00002d2d'),
+    ('\U00002d30', '\U00002d67'),
+    ('\U00002d6f', '\U00002d6f'),
+    ('\U00002d80', '\U00002d96'),
+    ('\U00002da0', '\U00002da6'),
+    ('\U00002da8', '\U00002dae'),
+    ('\U00002db0', '\U00002db6'),
+    ('\U00002db8', '\U00002dbe'),
+    ('\U00002dc0', '\U00002dc6'),
+    ('\U00002dc8', '\U00002dce'),
+    ('\U00002dd0', '\U00002dd6'),
+    ('\U00002dd8', '\U00002dde'),
+    ('\U00002e2f', '\U00002e2f'),
+    ('\U00003005', '\U00003006'),
+    ('\U00003031', '\U00003035'),
+    ('\U0000303b', '\U0000303c'),
+    ('\U00003041', '\U00003096'),
+    ('\U0000309d', '\U0000309f'),
+    ('\U000030a1', '\U000030fa'),
+    ('\U000030fc', '\U000030ff'),
+    ('\U00003105', '\U0000312d'),
+    ('\U00003131', '\U0000318e'),
+    ('\U000031a0', '\U000031ba'),
+    ('\U000031f0', '\U000031ff'),
+    ('\U00003400', '\U00003400'),
+    ('\U00004db5', '\U00004db5'),
+    ('\U00004e00', '\U00004e00'),
+    ('\U00009fcc', '\U00009fcc'),
+    ('\U0000a000', '\U0000a48c'),
+    ('\U0000a4d0', '\U0000a4fd'),
+    ('\U0000a500', '\U0000a60c'),
+    ('\U0000a610', '\U0000a61f'),
+    ('\U0000a62a', '\U0000a62b'),
+    ('\U0000a640', '\U0000a66e'),
+    ('\U0000a67f', '\U0000a697'),
+    ('\U0000a6a0', '\U0000a6e5'),
+    ('\U0000a717', '\U0000a71f'),
+    ('\U0000a722', '\U0000a788'),
+    ('\U0000a78b', '\U0000a78e'),
+    ('\U0000a790', '\U0000a793'),
+    ('\U0000a7a0', '\U0000a7aa'),
+    ('\U0000a7f8', '\U0000a801'),
+    ('\U0000a803', '\U0000a805'),
+    ('\U0000a807', '\U0000a80a'),
+    ('\U0000a80c', '\U0000a822'),
+    ('\U0000a840', '\U0000a873'),
+    ('\U0000a882', '\U0000a8b3'),
+    ('\U0000a8f2', '\U0000a8f7'),
+    ('\U0000a8fb', '\U0000a8fb'),
+    ('\U0000a90a', '\U0000a925'),
+    ('\U0000a930', '\U0000a946'),
+    ('\U0000a960', '\U0000a97c'),
+    ('\U0000a984', '\U0000a9b2'),
+    ('\U0000a9cf', '\U0000a9cf'),
+    ('\U0000aa00', '\U0000aa28'),
+    ('\U0000aa40', '\U0000aa42'),
+    ('\U0000aa44', '\U0000aa4b'),
+    ('\U0000aa60', '\U0000aa76'),
+    ('\U0000aa7a', '\U0000aa7a'),
+    ('\U0000aa80', '\U0000aaaf'),
+    ('\U0000aab1', '\U0000aab1'),
+    ('\U0000aab5', '\U0000aab6'),
+    ('\U0000aab9', '\U0000aabd'),
+    ('\U0000aac0', '\U0000aac0'),
+    ('\U0000aac2', '\U0000aac2'),
+    ('\U0000aadb', '\U0000aadd'),
+    ('\U0000aae0', '\U0000aaea'),
+    ('\U0000aaf2', '\U0000aaf4'),
+    ('\U0000ab01', '\U0000ab06'),
+    ('\U0000ab09', '\U0000ab0e'),
+    ('\U0000ab11', '\U0000ab16'),
+    ('\U0000ab20', '\U0000ab26'),
+    ('\U0000ab28', '\U0000ab2e'),
+    ('\U0000abc0', '\U0000abe2'),
+    ('\U0000ac00', '\U0000ac00'),
+    ('\U0000d7a3', '\U0000d7a3'),
+    ('\U0000d7b0', '\U0000d7c6'),
+    ('\U0000d7cb', '\U0000d7fb'),
+    ('\U0000f900', '\U0000fa6d'),
+    ('\U0000fa70', '\U0000fad9'),
+    ('\U0000fb00', '\U0000fb06'),
+    ('\U0000fb13', '\U0000fb17'),
+    ('\U0000fb1d', '\U0000fb1d'),
+    ('\U0000fb1f', '\U0000fb28'),
+    ('\U0000fb2a', '\U0000fb36'),
+    ('\U0000fb38', '\U0000fb3c'),
+    ('\U0000fb3e', '\U0000fb3e'),
+    ('\U0000fb40', '\U0000fb41'),
+    ('\U0000fb43', '\U0000fb44'),
+    ('\U0000fb46', '\U0000fbb1'),
+    ('\U0000fbd3', '\U0000fd3d'),
+    ('\U0000fd50', '\U0000fd8f'),
+    ('\U0000fd92', '\U0000fdc7'),
+    ('\U0000fdf0', '\U0000fdfb'),
+    ('\U0000fe70', '\U0000fe74'),
+    ('\U0000fe76', '\U0000fefc'),
+    ('\U0000ff21', '\U0000ff3a'),
+    ('\U0000ff41', '\U0000ff5a'),
+    ('\U0000ff66', '\U0000ffbe'),
+    ('\U0000ffc2', '\U0000ffc7'),
+    ('\U0000ffca', '\U0000ffcf'),
+    ('\U0000ffd2', '\U0000ffd7'),
+    ('\U0000ffda', '\U0000ffdc'),
+    ('\U00010000', '\U0001000b'),
+    ('\U0001000d', '\U00010026'),
+    ('\U00010028', '\U0001003a'),
+    ('\U0001003c', '\U0001003d'),
+    ('\U0001003f', '\U0001004d'),
+    ('\U00010050', '\U0001005d'),
+    ('\U00010080', '\U000100fa'),
+    ('\U00010280', '\U0001029c'),
+    ('\U000102a0', '\U000102d0'),
+    ('\U00010300', '\U0001031e'),
+    ('\U00010330', '\U00010340'),
+    ('\U00010342', '\U00010349'),
+    ('\U00010380', '\U0001039d'),
+    ('\U000103a0', '\U000103c3'),
+    ('\U000103c8', '\U000103cf'),
+    ('\U00010400', '\U0001049d'),
+    ('\U00010800', '\U00010805'),
+    ('\U00010808', '\U00010808'),
+    ('\U0001080a', '\U00010835'),
+    ('\U00010837', '\U00010838'),
+    ('\U0001083c', '\U0001083c'),
+    ('\U0001083f', '\U00010855'),
+    ('\U00010900', '\U00010915'),
+    ('\U00010920', '\U00010939'),
+    ('\U00010980', '\U000109b7'),
+    ('\U000109be', '\U000109bf'),
+    ('\U00010a00', '\U00010a00'),
+    ('\U00010a10', '\U00010a13'),
+    ('\U00010a15', '\U00010a17'),
+    ('\U00010a19', '\U00010a33'),
+    ('\U00010a60', '\U00010a7c'),
+    ('\U00010b00', '\U00010b35'),
+    ('\U00010b40', '\U00010b55'),
+    ('\U00010b60', '\U00010b72'),
+    ('\U00010c00', '\U00010c48'),
+    ('\U00011003', '\U00011037'),
+    ('\U00011083', '\U000110af'),
+    ('\U000110d0', '\U000110e8'),
+    ('\U00011103', '\U00011126'),
+    ('\U00011183', '\U000111b2'),
+    ('\U000111c1', '\U000111c4'),
+    ('\U00011680', '\U000116aa'),
+    ('\U00012000', '\U0001236e'),
+    ('\U00013000', '\U0001342e'),
+    ('\U00016800', '\U00016a38'),
+    ('\U00016f00', '\U00016f44'),
+    ('\U00016f50', '\U00016f50'),
+    ('\U00016f93', '\U00016f9f'),
+    ('\U0001b000', '\U0001b001'),
+    ('\U0001d400', '\U0001d454'),
+    ('\U0001d456', '\U0001d49c'),
+    ('\U0001d49e', '\U0001d49f'),
+    ('\U0001d4a2', '\U0001d4a2'),
+    ('\U0001d4a5', '\U0001d4a6'),
+    ('\U0001d4a9', '\U0001d4ac'),
+    ('\U0001d4ae', '\U0001d4b9'),
+    ('\U0001d4bb', '\U0001d4bb'),
+    ('\U0001d4bd', '\U0001d4c3'),
+    ('\U0001d4c5', '\U0001d505'),
+    ('\U0001d507', '\U0001d50a'),
+    ('\U0001d50d', '\U0001d514'),
+    ('\U0001d516', '\U0001d51c'),
+    ('\U0001d51e', '\U0001d539'),
+    ('\U0001d53b', '\U0001d53e'),
+    ('\U0001d540', '\U0001d544'),
+    ('\U0001d546', '\U0001d546'),
+    ('\U0001d54a', '\U0001d550'),
+    ('\U0001d552', '\U0001d6a5'),
+    ('\U0001d6a8', '\U0001d6c0'),
+    ('\U0001d6c2', '\U0001d6da'),
+    ('\U0001d6dc', '\U0001d6fa'),
+    ('\U0001d6fc', '\U0001d714'),
+    ('\U0001d716', '\U0001d734'),
+    ('\U0001d736', '\U0001d74e'),
+    ('\U0001d750', '\U0001d76e'),
+    ('\U0001d770', '\U0001d788'),
+    ('\U0001d78a', '\U0001d7a8'),
+    ('\U0001d7aa', '\U0001d7c2'),
+    ('\U0001d7c4', '\U0001d7cb'),
+    ('\U0001ee00', '\U0001ee03'),
+    ('\U0001ee05', '\U0001ee1f'),
+    ('\U0001ee21', '\U0001ee22'),
+    ('\U0001ee24', '\U0001ee24'),
+    ('\U0001ee27', '\U0001ee27'),
+    ('\U0001ee29', '\U0001ee32'),
+    ('\U0001ee34', '\U0001ee37'),
+    ('\U0001ee39', '\U0001ee39'),
+    ('\U0001ee3b', '\U0001ee3b'),
+    ('\U0001ee42', '\U0001ee42'),
+    ('\U0001ee47', '\U0001ee47'),
+    ('\U0001ee49', '\U0001ee49'),
+    ('\U0001ee4b', '\U0001ee4b'),
+    ('\U0001ee4d', '\U0001ee4f'),
+    ('\U0001ee51', '\U0001ee52'),
+    ('\U0001ee54', '\U0001ee54'),
+    ('\U0001ee57', '\U0001ee57'),
+    ('\U0001ee59', '\U0001ee59'),
+    ('\U0001ee5b', '\U0001ee5b'),
+    ('\U0001ee5d', '\U0001ee5d'),
+    ('\U0001ee5f', '\U0001ee5f'),
+    ('\U0001ee61', '\U0001ee62'),
+    ('\U0001ee64', '\U0001ee64'),
+    ('\U0001ee67', '\U0001ee6a'),
+    ('\U0001ee6c', '\U0001ee72'),
+    ('\U0001ee74', '\U0001ee77'),
+    ('\U0001ee79', '\U0001ee7c'),
+    ('\U0001ee7e', '\U0001ee7e'),
+    ('\U0001ee80', '\U0001ee89'),
+    ('\U0001ee8b', '\U0001ee9b'),
+    ('\U0001eea1', '\U0001eea3'),
+    ('\U0001eea5', '\U0001eea9'),
+    ('\U0001eeab', '\U0001eebb'),
+    ('\U00020000', '\U00020000'),
+    ('\U0002a6d6', '\U0002a6d6'),
+    ('\U0002a700', '\U0002a700'),
+    ('\U0002b734', '\U0002b734'),
+    ('\U0002b740', '\U0002b740'),
+    ('\U0002b81d', '\U0002b81d'),
+    ('\U0002f800', '\U0002fa1d')
+];
+
diff --git a/src/libregex/vm.rs b/src/libregex/vm.rs
new file mode 100644 (file)
index 0000000..6058ba6
--- /dev/null
@@ -0,0 +1,587 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// FIXME: Currently, the VM simulates an NFA. It would be nice to have another
+// VM that simulates a DFA.
+//
+// According to Russ Cox[1], a DFA performs better than an NFA, principally
+// because it reuses states previously computed by the machine *and* doesn't
+// keep track of capture groups. The drawback of a DFA (aside from its
+// complexity) is that it can't accurately return the locations of submatches.
+// The NFA *can* do that. (This is my understanding anyway.)
+//
+// Cox suggests that a DFA ought to be used to answer "does this match" and
+// "where does it match" questions. (In the latter, the starting position of
+// the match is computed by executing the regex backwards.) Cox also suggests
+// that a DFA should be run when asking "where are the submatches", which can
+// 1) quickly answer "no" is there's no match and 2) discover the substring
+// that matches, which means running the NFA on smaller input.
+//
+// Currently, the NFA simulation implemented below does some dirty tricks to
+// avoid tracking capture groups when they aren't needed (which only works
+// for 'is_match', not 'find'). This is a half-measure, but does provide some
+// perf improvement.
+//
+// AFAIK, the DFA/NFA approach is implemented in RE2/C++ but *not* in RE2/Go.
+//
+// [1] - http://swtch.com/~rsc/regex/regex3.html
+
+use std::cmp;
+use std::mem;
+use std::slice::MutableVector;
+use compile::{
+    Program,
+    Match, OneChar, CharClass, Any, EmptyBegin, EmptyEnd, EmptyWordBoundary,
+    Save, Jump, Split,
+};
+use parse::{FLAG_NOCASE, FLAG_MULTI, FLAG_DOTNL, FLAG_NEGATED};
+use parse::unicode::PERLW;
+
+pub type CaptureLocs = Vec<Option<uint>>;
+
+/// Indicates the type of match to be performed by the VM.
+pub enum MatchKind {
+    /// Only checks if a match exists or not. Does not return location.
+    Exists,
+    /// Returns the start and end indices of the entire match in the input
+    /// given.
+    Location,
+    /// Returns the start and end indices of each submatch in the input given.
+    Submatches,
+}
+
+/// Runs an NFA simulation on the compiled expression given on the search text
+/// `input`. The search begins at byte index `start` and ends at byte index
+/// `end`. (The range is specified here so that zero-width assertions will work
+/// correctly when searching for successive non-overlapping matches.)
+///
+/// The `which` parameter indicates what kind of capture information the caller
+/// wants. There are three choices: match existence only, the location of the
+/// entire match or the locations of the entire match in addition to the
+/// locations of each submatch.
+pub fn run<'r, 't>(which: MatchKind, prog: &'r Program, input: &'t str,
+                   start: uint, end: uint) -> CaptureLocs {
+    Nfa {
+        which: which,
+        prog: prog,
+        input: input,
+        start: start,
+        end: end,
+        ic: 0,
+        chars: CharReader::new(input),
+    }.run()
+}
+
+struct Nfa<'r, 't> {
+    which: MatchKind,
+    prog: &'r Program,
+    input: &'t str,
+    start: uint,
+    end: uint,
+    ic: uint,
+    chars: CharReader<'t>,
+}
+
+/// Indicates the next action to take after a single non-empty instruction
+/// is processed.
+pub enum StepState {
+    /// This is returned if and only if a Match instruction is reached and
+    /// we only care about the existence of a match. It instructs the VM to
+    /// quit early.
+    StepMatchEarlyReturn,
+    /// Indicates that a match was found. Thus, the rest of the states in the
+    /// *current* queue should be dropped (i.e., leftmost-first semantics).
+    /// States in the "next" queue can still be processed.
+    StepMatch,
+    /// No match was found. Continue with the next state in the queue.
+    StepContinue,
+}
+
+impl<'r, 't> Nfa<'r, 't> {
+    fn run(&mut self) -> CaptureLocs {
+        let ncaps = match self.which {
+            Exists => 0,
+            Location => 1,
+            Submatches => self.prog.num_captures(),
+        };
+        let mut matched = false;
+        let ninsts = self.prog.insts.len();
+        let mut clist = &mut Threads::new(self.which, ninsts, ncaps);
+        let mut nlist = &mut Threads::new(self.which, ninsts, ncaps);
+
+        let mut groups = Vec::from_elem(ncaps * 2, None);
+
+        // Determine if the expression starts with a '^' so we can avoid
+        // simulating .*?
+        // Make sure multi-line mode isn't enabled for it, otherwise we can't
+        // drop the initial .*?
+        let prefix_anchor =
+            match *self.prog.insts.get(1) {
+                EmptyBegin(flags) if flags & FLAG_MULTI == 0 => true,
+                _ => false,
+            };
+
+        self.ic = self.start;
+        let mut next_ic = self.chars.set(self.start);
+        while self.ic <= self.end {
+            if clist.size == 0 {
+                // We have a match and we're done exploring alternatives.
+                // Time to quit.
+                if matched {
+                    break
+                }
+
+                // If there are no threads to try, then we'll have to start
+                // over at the beginning of the regex.
+                // BUT, if there's a literal prefix for the program, try to
+                // jump ahead quickly. If it can't be found, then we can bail
+                // out early.
+                if self.prog.prefix.len() > 0 && clist.size == 0 {
+                    let needle = self.prog.prefix.as_slice().as_bytes();
+                    let haystack = self.input.as_bytes().slice_from(self.ic);
+                    match find_prefix(needle, haystack) {
+                        None => break,
+                        Some(i) => {
+                            self.ic += i;
+                            next_ic = self.chars.set(self.ic);
+                        }
+                    }
+                }
+            }
+
+            // This simulates a preceding '.*?' for every regex by adding
+            // a state starting at the current position in the input for the
+            // beginning of the program only if we don't already have a match.
+            if clist.size == 0 || (!prefix_anchor && !matched) {
+                self.add(clist, 0, groups.as_mut_slice())
+            }
+
+            // Now we try to read the next character.
+            // As a result, the 'step' method will look at the previous
+            // character.
+            self.ic = next_ic;
+            next_ic = self.chars.advance();
+
+            let mut i = 0;
+            while i < clist.size {
+                let pc = clist.pc(i);
+                let step_state = self.step(groups.as_mut_slice(), nlist,
+                                           clist.groups(i), pc);
+                match step_state {
+                    StepMatchEarlyReturn => return vec![Some(0), Some(0)],
+                    StepMatch => { matched = true; clist.empty() },
+                    StepContinue => {},
+                }
+                i += 1;
+            }
+            mem::swap(&mut clist, &mut nlist);
+            nlist.empty();
+        }
+        match self.which {
+            Exists if matched     => vec![Some(0), Some(0)],
+            Exists                => vec![None, None],
+            Location | Submatches => groups,
+        }
+    }
+
+    fn step(&self, groups: &mut [Option<uint>], nlist: &mut Threads,
+            caps: &mut [Option<uint>], pc: uint)
+           -> StepState {
+        match *self.prog.insts.get(pc) {
+            Match => {
+                match self.which {
+                    Exists => {
+                        return StepMatchEarlyReturn
+                    }
+                    Location => {
+                        groups[0] = caps[0];
+                        groups[1] = caps[1];
+                        return StepMatch
+                    }
+                    Submatches => {
+                        for (slot, val) in groups.mut_iter().zip(caps.iter()) {
+                            *slot = *val;
+                        }
+                        return StepMatch
+                    }
+                }
+            }
+            OneChar(c, flags) => {
+                if self.char_eq(flags & FLAG_NOCASE > 0, self.chars.prev, c) {
+                    self.add(nlist, pc+1, caps);
+                }
+            }
+            CharClass(ref ranges, flags) => {
+                if self.chars.prev.is_some() {
+                    let c = self.chars.prev.unwrap();
+                    let negate = flags & FLAG_NEGATED > 0;
+                    let casei = flags & FLAG_NOCASE > 0;
+                    let found = ranges.as_slice();
+                    let found = found.bsearch(|&rc| class_cmp(casei, c, rc));
+                    let found = found.is_some();
+                    if (found && !negate) || (!found && negate) {
+                        self.add(nlist, pc+1, caps);
+                    }
+                }
+            }
+            Any(flags) => {
+                if flags & FLAG_DOTNL > 0
+                   || !self.char_eq(false, self.chars.prev, '\n') {
+                    self.add(nlist, pc+1, caps)
+                }
+            }
+            EmptyBegin(_) | EmptyEnd(_) | EmptyWordBoundary(_)
+            | Save(_) | Jump(_) | Split(_, _) => {},
+        }
+        StepContinue
+    }
+
+    fn add(&self, nlist: &mut Threads, pc: uint, groups: &mut [Option<uint>]) {
+        if nlist.contains(pc) {
+            return
+        }
+        // We have to add states to the threads list even if their empty.
+        // TL;DR - It prevents cycles.
+        // If we didn't care about cycles, we'd *only* add threads that
+        // correspond to non-jumping instructions (OneChar, Any, Match, etc.).
+        // But, it's possible for valid regexs (like '(a*)*') to result in
+        // a cycle in the instruction list. e.g., We'll keep chasing the Split
+        // instructions forever.
+        // So we add these instructions to our thread queue, but in the main
+        // VM loop, we look for them but simply ignore them.
+        // Adding them to the queue prevents them from being revisited so we
+        // can avoid cycles (and the inevitable stack overflow).
+        //
+        // We make a minor optimization by indicating that the state is "empty"
+        // so that its capture groups are not filled in.
+        match *self.prog.insts.get(pc) {
+            EmptyBegin(flags) => {
+                let multi = flags & FLAG_MULTI > 0;
+                nlist.add(pc, groups, true);
+                if self.chars.is_begin()
+                   || (multi && self.char_is(self.chars.prev, '\n')) {
+                    self.add(nlist, pc + 1, groups)
+                }
+            }
+            EmptyEnd(flags) => {
+                let multi = flags & FLAG_MULTI > 0;
+                nlist.add(pc, groups, true);
+                if self.chars.is_end()
+                   || (multi && self.char_is(self.chars.cur, '\n')) {
+                    self.add(nlist, pc + 1, groups)
+                }
+            }
+            EmptyWordBoundary(flags) => {
+                nlist.add(pc, groups, true);
+                if self.chars.is_word_boundary() == !(flags & FLAG_NEGATED > 0) {
+                    self.add(nlist, pc + 1, groups)
+                }
+            }
+            Save(slot) => {
+                nlist.add(pc, groups, true);
+                match self.which {
+                    Location if slot <= 1 => {
+                        let old = groups[slot];
+                        groups[slot] = Some(self.ic);
+                        self.add(nlist, pc + 1, groups);
+                        groups[slot] = old;
+                    }
+                    Submatches => {
+                        let old = groups[slot];
+                        groups[slot] = Some(self.ic);
+                        self.add(nlist, pc + 1, groups);
+                        groups[slot] = old;
+                    }
+                    Exists | Location => self.add(nlist, pc + 1, groups),
+                }
+            }
+            Jump(to) => {
+                nlist.add(pc, groups, true);
+                self.add(nlist, to, groups)
+            }
+            Split(x, y) => {
+                nlist.add(pc, groups, true);
+                self.add(nlist, x, groups);
+                self.add(nlist, y, groups);
+            }
+            Match | OneChar(_, _) | CharClass(_, _) | Any(_) => {
+                nlist.add(pc, groups, false);
+            }
+        }
+    }
+
+    // FIXME: For case insensitive comparisons, it uses the uppercase
+    // character and tests for equality. IIUC, this does not generalize to
+    // all of Unicode. I believe we need to check the entire fold for each
+    // character. This will be easy to add if and when it gets added to Rust's
+    // standard library.
+    #[inline]
+    fn char_eq(&self, casei: bool, textc: Option<char>, regc: char) -> bool {
+        match textc {
+            None => false,
+            Some(textc) => {
+                regc == textc
+                    || (casei && regc.to_uppercase() == textc.to_uppercase())
+            }
+        }
+    }
+
+    #[inline]
+    fn char_is(&self, textc: Option<char>, regc: char) -> bool {
+        textc == Some(regc)
+    }
+}
+
+/// CharReader is responsible for maintaining a "previous" and a "current"
+/// character. This one-character lookahead is necessary for assertions that
+/// look one character before or after the current position.
+pub struct CharReader<'t> {
+    /// The previous character read. It is None only when processing the first
+    /// character of the input.
+    pub prev: Option<char>,
+    /// The current character.
+    pub cur: Option<char>,
+    input: &'t str,
+    next: uint,
+}
+
+impl<'t> CharReader<'t> {
+    /// Returns a new CharReader that advances through the input given.
+    /// Note that a CharReader has no knowledge of the range in which to search
+    /// the input.
+    pub fn new(input: &'t str) -> CharReader<'t> {
+        CharReader {
+            prev: None,
+            cur: None,
+            input: input,
+            next: 0,
+       }
+    }
+
+    /// Sets the previous and current character given any arbitrary byte
+    /// index (at a unicode codepoint boundary).
+    #[inline]
+    pub fn set(&mut self, ic: uint) -> uint {
+        self.prev = None;
+        self.cur = None;
+        self.next = 0;
+
+        if self.input.len() == 0 {
+            return 1
+        }
+        if ic > 0 {
+            let i = cmp::min(ic, self.input.len());
+            let prev = self.input.char_range_at_reverse(i);
+            self.prev = Some(prev.ch);
+        }
+        if ic < self.input.len() {
+            let cur = self.input.char_range_at(ic);
+            self.cur = Some(cur.ch);
+            self.next = cur.next;
+            self.next
+        } else {
+            self.input.len() + 1
+        }
+    }
+
+    /// Does the same as `set`, except it always advances to the next
+    /// character in the input (and therefore does half as many UTF8 decodings).
+    #[inline]
+    pub fn advance(&mut self) -> uint {
+        self.prev = self.cur;
+        if self.next < self.input.len() {
+            let cur = self.input.char_range_at(self.next);
+            self.cur = Some(cur.ch);
+            self.next = cur.next;
+        } else {
+            self.cur = None;
+            self.next = self.input.len() + 1;
+        }
+        self.next
+    }
+
+    /// Returns true if and only if this is the beginning of the input
+    /// (ignoring the range of the input to search).
+    #[inline]
+    pub fn is_begin(&self) -> bool { self.prev.is_none() }
+
+    /// Returns true if and only if this is the end of the input
+    /// (ignoring the range of the input to search).
+    #[inline]
+    pub fn is_end(&self) -> bool { self.cur.is_none() }
+
+    /// Returns true if and only if the current position is a word boundary.
+    /// (Ignoring the range of the input to search.)
+    pub fn is_word_boundary(&self) -> bool {
+        if self.is_begin() {
+            return is_word(self.cur)
+        }
+        if self.is_end() {
+            return is_word(self.prev)
+        }
+        (is_word(self.cur) && !is_word(self.prev))
+        || (is_word(self.prev) && !is_word(self.cur))
+    }
+}
+
+struct Thread {
+    pc: uint,
+    groups: Vec<Option<uint>>,
+}
+
+struct Threads {
+    which: MatchKind,
+    queue: Vec<Thread>,
+    sparse: Vec<uint>,
+    size: uint,
+}
+
+impl Threads {
+    // This is using a wicked neat trick to provide constant time lookup
+    // for threads in the queue using a sparse set. A queue of threads is
+    // allocated once with maximal size when the VM initializes and is reused
+    // throughout execution. That is, there should be zero allocation during
+    // the execution of a VM.
+    //
+    // See http://research.swtch.com/sparse for the deets.
+    fn new(which: MatchKind, num_insts: uint, ncaps: uint) -> Threads {
+        Threads {
+            which: which,
+            queue: Vec::from_fn(num_insts, |_| {
+                Thread { pc: 0, groups: Vec::from_elem(ncaps * 2, None) }
+            }),
+            sparse: Vec::from_elem(num_insts, 0u),
+            size: 0,
+        }
+    }
+
+    fn add(&mut self, pc: uint, groups: &[Option<uint>], empty: bool) {
+        let t = self.queue.get_mut(self.size);
+        t.pc = pc;
+        match (empty, self.which) {
+            (_, Exists) | (true, _) => {},
+            (false, Location) => {
+                *t.groups.get_mut(0) = groups[0];
+                *t.groups.get_mut(1) = groups[1];
+            }
+            (false, Submatches) => {
+                for (slot, val) in t.groups.mut_iter().zip(groups.iter()) {
+                    *slot = *val;
+                }
+            }
+        }
+        *self.sparse.get_mut(pc) = self.size;
+        self.size += 1;
+    }
+
+    #[inline]
+    fn contains(&self, pc: uint) -> bool {
+        let s = *self.sparse.get(pc);
+        s < self.size && self.queue.get(s).pc == pc
+    }
+
+    #[inline]
+    fn empty(&mut self) {
+        self.size = 0;
+    }
+
+    #[inline]
+    fn pc(&self, i: uint) -> uint {
+        self.queue.get(i).pc
+    }
+
+    #[inline]
+    fn groups<'r>(&'r mut self, i: uint) -> &'r mut [Option<uint>] {
+        self.queue.get_mut(i).groups.as_mut_slice()
+    }
+}
+
+/// Returns true if the character is a word character, according to the
+/// (Unicode friendly) Perl character class '\w'.
+/// Note that this is only use for testing word boundaries. The actual '\w'
+/// is encoded as a CharClass instruction.
+pub fn is_word(c: Option<char>) -> bool {
+    let c = match c {
+        None => return false,
+        Some(c) => c,
+    };
+    // Try the common ASCII case before invoking binary search.
+    match c {
+        '_' | '0' .. '9' | 'a' .. 'z' | 'A' .. 'Z' => true,
+        _ => PERLW.bsearch(|&(start, end)| {
+            if c >= start && c <= end {
+                Equal
+            } else if start > c {
+                Greater
+            } else {
+                Less
+            }
+        }).is_some()
+    }
+}
+
+/// Given a character and a single character class range, return an ordering
+/// indicating whether the character is less than the start of the range,
+/// in the range (inclusive) or greater than the end of the range.
+///
+/// If `casei` is `true`, then this ordering is computed case insensitively.
+///
+/// This function is meant to be used with a binary search.
+#[inline]
+fn class_cmp(casei: bool, mut textc: char,
+             (mut start, mut end): (char, char)) -> Ordering {
+    if casei {
+        // FIXME: This is pretty ridiculous. All of this case conversion
+        // can be moved outside this function:
+        // 1) textc should be uppercased outside the bsearch.
+        // 2) the character class itself should be uppercased either in the
+        //    parser or the compiler.
+        // FIXME: This is too simplistic for correct Unicode support.
+        //        See also: char_eq
+        textc = textc.to_uppercase();
+        start = start.to_uppercase();
+        end = end.to_uppercase();
+    }
+    if textc >= start && textc <= end {
+        Equal
+    } else if start > textc {
+        Greater
+    } else {
+        Less
+    }
+}
+
+/// Returns the starting location of `needle` in `haystack`.
+/// If `needle` is not in `haystack`, then `None` is returned.
+///
+/// Note that this is using a naive substring algorithm.
+#[inline]
+pub fn find_prefix(needle: &[u8], haystack: &[u8]) -> Option<uint> {
+    let (hlen, nlen) = (haystack.len(), needle.len());
+    if nlen > hlen || nlen == 0 {
+        return None
+    }
+    let mut hayi = 0u;
+    'HAYSTACK: loop {
+        if hayi > hlen - nlen {
+            break
+        }
+        let mut nedi = 0;
+        while nedi < nlen {
+            if haystack[hayi+nedi] != needle[nedi] {
+                hayi += 1;
+                continue 'HAYSTACK
+            }
+            nedi += 1;
+        }
+        return Some(hayi)
+    }
+    None
+}
diff --git a/src/libregex_macros/lib.rs b/src/libregex_macros/lib.rs
new file mode 100644 (file)
index 0000000..72e00de
--- /dev/null
@@ -0,0 +1,684 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This crate provides the `regex!` macro. Its use is documented in the
+//! `regex` crate.
+
+#![crate_id = "regex_macros#0.11-pre"]
+#![crate_type = "dylib"]
+#![experimental]
+#![license = "MIT/ASL2"]
+#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+       html_root_url = "http://static.rust-lang.org/doc/master")]
+
+#![feature(macro_registrar, managed_boxes, quote)]
+
+extern crate regex;
+extern crate syntax;
+
+use syntax::ast;
+use syntax::codemap;
+use syntax::ext::base::{
+    SyntaxExtension, ExtCtxt, MacResult, MacExpr, DummyResult,
+    NormalTT, BasicMacroExpander,
+};
+use syntax::parse;
+use syntax::parse::token;
+use syntax::print::pprust;
+
+use regex::Regex;
+use regex::native::{
+    OneChar, CharClass, Any, Save, Jump, Split,
+    Match, EmptyBegin, EmptyEnd, EmptyWordBoundary,
+    Program, Dynamic, Native,
+    FLAG_NOCASE, FLAG_MULTI, FLAG_DOTNL, FLAG_NEGATED,
+};
+
+/// For the `regex!` syntax extension. Do not use.
+#[macro_registrar]
+#[doc(hidden)]
+pub fn macro_registrar(register: |ast::Name, SyntaxExtension|) {
+    let expander = ~BasicMacroExpander { expander: native, span: None };
+    register(token::intern("regex"), NormalTT(expander, None))
+}
+
+/// Generates specialized code for the Pike VM for a particular regular
+/// expression.
+///
+/// There are two primary differences between the code generated here and the
+/// general code in vm.rs.
+///
+/// 1. All heap allocation is removed. Sized vector types are used instead.
+///    Care must be taken to make sure that these vectors are not copied
+///    gratuitously. (If you're not sure, run the benchmarks. They will yell
+///    at you if you do.)
+/// 2. The main `match instruction { ... }` expressions are replaced with more
+///    direct `match pc { ... }`. The generators can be found in
+///    `step_insts` and `add_insts`.
+///
+/// Other more minor changes include eliding code when possible (although this
+/// isn't completely thorough at the moment), and translating character class
+/// matching from using a binary search to a simple `match` expression (see
+/// `match_class`).
+///
+/// It is strongly recommended to read the dynamic implementation in vm.rs
+/// first before trying to understand the code generator. The implementation
+/// strategy is identical and vm.rs has comments and will be easier to follow.
+fn native(cx: &mut ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree])
+         -> ~MacResult {
+    let regex = match parse(cx, tts) {
+        Some(r) => r,
+        // error is logged in 'parse' with cx.span_err
+        None => return DummyResult::any(sp),
+    };
+    let re = match Regex::new(regex.to_owned()) {
+        Ok(re) => re,
+        Err(err) => {
+            cx.span_err(sp, err.to_str());
+            return DummyResult::any(sp)
+        }
+    };
+    let prog = match re.p {
+        Dynamic(ref prog) => prog.clone(),
+        Native(_) => unreachable!(),
+    };
+
+    let mut gen = NfaGen {
+        cx: &*cx, sp: sp, prog: prog,
+        names: re.names.clone(), original: re.original.clone(),
+    };
+    MacExpr::new(gen.code())
+}
+
+struct NfaGen<'a> {
+    cx: &'a ExtCtxt<'a>,
+    sp: codemap::Span,
+    prog: Program,
+    names: ~[Option<~str>],
+    original: ~str,
+}
+
+impl<'a> NfaGen<'a> {
+    fn code(&mut self) -> @ast::Expr {
+        // Most or all of the following things are used in the quasiquoted
+        // expression returned.
+        let num_cap_locs = 2 * self.prog.num_captures();
+        let num_insts = self.prog.insts.len();
+        let cap_names = self.vec_expr(self.names,
+            |cx, name| match name {
+                &Some(ref name) => {
+                    let name = name.as_slice();
+                    quote_expr!(cx, Some(~$name))
+                }
+                &None => quote_expr!(cx, None),
+            }
+        );
+        let prefix_anchor =
+            match self.prog.insts.as_slice()[1] {
+                EmptyBegin(flags) if flags & FLAG_MULTI == 0 => true,
+                _ => false,
+            };
+        let init_groups = self.vec_from_fn(num_cap_locs,
+                                           |cx| quote_expr!(cx, None));
+        let prefix_bytes = self.vec_expr(self.prog.prefix.as_slice().as_bytes(),
+                                         |cx, b| quote_expr!(cx, $b));
+        let check_prefix = self.check_prefix();
+        let step_insts = self.step_insts();
+        let add_insts = self.add_insts();
+        let regex = self.original.as_slice();
+
+        quote_expr!(self.cx, {
+fn exec<'t>(which: ::regex::native::MatchKind, input: &'t str,
+            start: uint, end: uint) -> Vec<Option<uint>> {
+    #![allow(unused_imports)]
+    use regex::native::{
+        MatchKind, Exists, Location, Submatches,
+        StepState, StepMatchEarlyReturn, StepMatch, StepContinue,
+        CharReader, find_prefix,
+    };
+
+    return Nfa {
+        which: which,
+        input: input,
+        ic: 0,
+        chars: CharReader::new(input),
+    }.run(start, end);
+
+    type Captures = [Option<uint>, ..$num_cap_locs];
+
+    struct Nfa<'t> {
+        which: MatchKind,
+        input: &'t str,
+        ic: uint,
+        chars: CharReader<'t>,
+    }
+
+    impl<'t> Nfa<'t> {
+        #[allow(unused_variable)]
+        fn run(&mut self, start: uint, end: uint) -> Vec<Option<uint>> {
+            let mut matched = false;
+            let prefix_bytes: &[u8] = &$prefix_bytes;
+            let mut clist = &mut Threads::new(self.which);
+            let mut nlist = &mut Threads::new(self.which);
+
+            let mut groups = $init_groups;
+
+            self.ic = start;
+            let mut next_ic = self.chars.set(start);
+            while self.ic <= end {
+                if clist.size == 0 {
+                    if matched {
+                        break
+                    }
+                    $check_prefix
+                }
+                if clist.size == 0 || (!$prefix_anchor && !matched) {
+                    self.add(clist, 0, &mut groups)
+                }
+
+                self.ic = next_ic;
+                next_ic = self.chars.advance();
+
+                let mut i = 0;
+                while i < clist.size {
+                    let pc = clist.pc(i);
+                    let step_state = self.step(&mut groups, nlist,
+                                               clist.groups(i), pc);
+                    match step_state {
+                        StepMatchEarlyReturn =>
+                            return vec![Some(0u), Some(0u)],
+                        StepMatch => { matched = true; clist.empty() },
+                        StepContinue => {},
+                    }
+                    i += 1;
+                }
+                ::std::mem::swap(&mut clist, &mut nlist);
+                nlist.empty();
+            }
+            match self.which {
+                Exists if matched     => vec![Some(0u), Some(0u)],
+                Exists                => vec![None, None],
+                Location | Submatches => groups.iter().map(|x| *x).collect(),
+            }
+        }
+
+        // Sometimes `nlist` is never used (for empty regexes).
+        #[allow(unused_variable)]
+        #[inline]
+        fn step(&self, groups: &mut Captures, nlist: &mut Threads,
+                caps: &mut Captures, pc: uint) -> StepState {
+            $step_insts
+            StepContinue
+        }
+
+        fn add(&self, nlist: &mut Threads, pc: uint,
+               groups: &mut Captures) {
+            if nlist.contains(pc) {
+                return
+            }
+            $add_insts
+        }
+    }
+
+    struct Thread {
+        pc: uint,
+        groups: Captures,
+    }
+
+    struct Threads {
+        which: MatchKind,
+        queue: [Thread, ..$num_insts],
+        sparse: [uint, ..$num_insts],
+        size: uint,
+    }
+
+    impl Threads {
+        fn new(which: MatchKind) -> Threads {
+            Threads {
+                which: which,
+                // These unsafe blocks are used for performance reasons, as it
+                // gives us a zero-cost initialization of a sparse set. The
+                // trick is described in more detail here:
+                // http://research.swtch.com/sparse
+                // The idea here is to avoid initializing threads that never
+                // need to be initialized, particularly for larger regexs with
+                // a lot of instructions.
+                queue: unsafe { ::std::mem::uninit() },
+                sparse: unsafe { ::std::mem::uninit() },
+                size: 0,
+            }
+        }
+
+        #[inline]
+        fn add(&mut self, pc: uint, groups: &Captures) {
+            let t = &mut self.queue[self.size];
+            t.pc = pc;
+            match self.which {
+                Exists => {},
+                Location => {
+                    t.groups[0] = groups[0];
+                    t.groups[1] = groups[1];
+                }
+                Submatches => {
+                    for (slot, val) in t.groups.mut_iter().zip(groups.iter()) {
+                        *slot = *val;
+                    }
+                }
+            }
+            self.sparse[pc] = self.size;
+            self.size += 1;
+        }
+
+        #[inline]
+        fn add_empty(&mut self, pc: uint) {
+            self.queue[self.size].pc = pc;
+            self.sparse[pc] = self.size;
+            self.size += 1;
+        }
+
+        #[inline]
+        fn contains(&self, pc: uint) -> bool {
+            let s = self.sparse[pc];
+            s < self.size && self.queue[s].pc == pc
+        }
+
+        #[inline]
+        fn empty(&mut self) {
+            self.size = 0;
+        }
+
+        #[inline]
+        fn pc(&self, i: uint) -> uint {
+            self.queue[i].pc
+        }
+
+        #[inline]
+        fn groups<'r>(&'r mut self, i: uint) -> &'r mut Captures {
+            &'r mut self.queue[i].groups
+        }
+    }
+}
+
+::regex::Regex {
+    original: ~$regex,
+    names: ~$cap_names,
+    p: ::regex::native::Native(exec),
+}
+        })
+    }
+
+    // Generates code for the `add` method, which is responsible for adding
+    // zero-width states to the next queue of states to visit.
+    fn add_insts(&self) -> @ast::Expr {
+        let arms = self.prog.insts.iter().enumerate().map(|(pc, inst)| {
+            let nextpc = pc + 1;
+            let body = match *inst {
+                EmptyBegin(flags) => {
+                    let nl = '\n';
+                    let cond =
+                        if flags & FLAG_MULTI > 0 {
+                            quote_expr!(self.cx,
+                                self.chars.is_begin()
+                                || self.chars.prev == Some($nl)
+                            )
+                        } else {
+                            quote_expr!(self.cx, self.chars.is_begin())
+                        };
+                    quote_expr!(self.cx, {
+                        nlist.add_empty($pc);
+                        if $cond { self.add(nlist, $nextpc, &mut *groups) }
+                    })
+                }
+                EmptyEnd(flags) => {
+                    let nl = '\n';
+                    let cond =
+                        if flags & FLAG_MULTI > 0 {
+                            quote_expr!(self.cx,
+                                self.chars.is_end()
+                                || self.chars.cur == Some($nl)
+                            )
+                        } else {
+                            quote_expr!(self.cx, self.chars.is_end())
+                        };
+                    quote_expr!(self.cx, {
+                        nlist.add_empty($pc);
+                        if $cond { self.add(nlist, $nextpc, &mut *groups) }
+                    })
+                }
+                EmptyWordBoundary(flags) => {
+                    let cond =
+                        if flags & FLAG_NEGATED > 0 {
+                            quote_expr!(self.cx, !self.chars.is_word_boundary())
+                        } else {
+                            quote_expr!(self.cx, self.chars.is_word_boundary())
+                        };
+                    quote_expr!(self.cx, {
+                        nlist.add_empty($pc);
+                        if $cond { self.add(nlist, $nextpc, &mut *groups) }
+                    })
+                }
+                Save(slot) => {
+                    let save = quote_expr!(self.cx, {
+                        let old = groups[$slot];
+                        groups[$slot] = Some(self.ic);
+                        self.add(nlist, $nextpc, &mut *groups);
+                        groups[$slot] = old;
+                    });
+                    let add = quote_expr!(self.cx, {
+                        self.add(nlist, $nextpc, &mut *groups);
+                    });
+                    // If this is saving a submatch location but we request
+                    // existence or only full match location, then we can skip
+                    // right over it every time.
+                    if slot > 1 {
+                        quote_expr!(self.cx, {
+                            nlist.add_empty($pc);
+                            match self.which {
+                                Submatches => $save,
+                                Exists | Location => $add,
+                            }
+                        })
+                    } else {
+                        quote_expr!(self.cx, {
+                            nlist.add_empty($pc);
+                            match self.which {
+                                Submatches | Location => $save,
+                                Exists => $add,
+                            }
+                        })
+                    }
+                }
+                Jump(to) => {
+                    quote_expr!(self.cx, {
+                        nlist.add_empty($pc);
+                        self.add(nlist, $to, &mut *groups);
+                    })
+                }
+                Split(x, y) => {
+                    quote_expr!(self.cx, {
+                        nlist.add_empty($pc);
+                        self.add(nlist, $x, &mut *groups);
+                        self.add(nlist, $y, &mut *groups);
+                    })
+                }
+                // For Match, OneChar, CharClass, Any
+                _ => quote_expr!(self.cx, nlist.add($pc, &*groups)),
+            };
+            self.arm_inst(pc, body)
+        }).collect::<Vec<ast::Arm>>();
+
+        self.match_insts(arms)
+    }
+
+    // Generates the code for the `step` method, which processes all states
+    // in the current queue that consume a single character.
+    fn step_insts(&self) -> @ast::Expr {
+        let arms = self.prog.insts.iter().enumerate().map(|(pc, inst)| {
+            let nextpc = pc + 1;
+            let body = match *inst {
+                Match => {
+                    quote_expr!(self.cx, {
+                        match self.which {
+                            Exists => {
+                                return StepMatchEarlyReturn
+                            }
+                            Location => {
+                                groups[0] = caps[0];
+                                groups[1] = caps[1];
+                                return StepMatch
+                            }
+                            Submatches => {
+                                for (slot, val) in groups.mut_iter().zip(caps.iter()) {
+                                    *slot = *val;
+                                }
+                                return StepMatch
+                            }
+                        }
+                    })
+                }
+                OneChar(c, flags) => {
+                    if flags & FLAG_NOCASE > 0 {
+                        let upc = c.to_uppercase();
+                        quote_expr!(self.cx, {
+                            let upc = self.chars.prev.map(|c| c.to_uppercase());
+                            if upc == Some($upc) {
+                                self.add(nlist, $nextpc, caps);
+                            }
+                        })
+                    } else {
+                        quote_expr!(self.cx, {
+                            if self.chars.prev == Some($c) {
+                                self.add(nlist, $nextpc, caps);
+                            }
+                        })
+                    }
+                }
+                CharClass(ref ranges, flags) => {
+                    let negate = flags & FLAG_NEGATED > 0;
+                    let casei = flags & FLAG_NOCASE > 0;
+                    let get_char =
+                        if casei {
+                            quote_expr!(self.cx, self.chars.prev.unwrap().to_uppercase())
+                        } else {
+                            quote_expr!(self.cx, self.chars.prev.unwrap())
+                        };
+                    let negcond =
+                        if negate {
+                            quote_expr!(self.cx, !found)
+                        } else {
+                            quote_expr!(self.cx, found)
+                        };
+                    let mranges = self.match_class(casei, ranges.as_slice());
+                    quote_expr!(self.cx, {
+                        if self.chars.prev.is_some() {
+                            let c = $get_char;
+                            let found = $mranges;
+                            if $negcond {
+                                self.add(nlist, $nextpc, caps);
+                            }
+                        }
+                    })
+                }
+                Any(flags) => {
+                    if flags & FLAG_DOTNL > 0 {
+                        quote_expr!(self.cx, self.add(nlist, $nextpc, caps))
+                    } else {
+                        let nl = '\n'; // no char lits allowed? wtf?
+                        quote_expr!(self.cx, {
+                            if self.chars.prev != Some($nl) {
+                                self.add(nlist, $nextpc, caps)
+                            }
+                        })
+                    }
+                }
+                // EmptyBegin, EmptyEnd, EmptyWordBoundary, Save, Jump, Split
+                _ => quote_expr!(self.cx, {}),
+            };
+            self.arm_inst(pc, body)
+        }).collect::<Vec<ast::Arm>>();
+
+        self.match_insts(arms)
+    }
+
+    // Translates a character class into a match expression.
+    // This avoids a binary search (and is hopefully replaced by a jump
+    // table).
+    fn match_class(&self, casei: bool, ranges: &[(char, char)]) -> @ast::Expr {
+        let mut arms = ranges.iter().map(|&(mut start, mut end)| {
+            if casei {
+                start = start.to_uppercase();
+                end = end.to_uppercase();
+            }
+            ast::Arm {
+                attrs: vec!(),
+                pats: vec!(@ast::Pat{
+                    id: ast::DUMMY_NODE_ID,
+                    span: self.sp,
+                    node: ast::PatRange(quote_expr!(self.cx, $start),
+                                        quote_expr!(self.cx, $end)),
+                }),
+                guard: None,
+                body: quote_expr!(self.cx, true),
+            }
+        }).collect::<Vec<ast::Arm>>();
+
+        arms.push(self.wild_arm_expr(quote_expr!(self.cx, false)));
+
+        let match_on = quote_expr!(self.cx, c);
+        self.dummy_expr(ast::ExprMatch(match_on, arms))
+    }
+
+    // Generates code for checking a literal prefix of the search string.
+    // The code is only generated if the regex *has* a literal prefix.
+    // Otherwise, a no-op is returned.
+    fn check_prefix(&self) -> @ast::Expr {
+        if self.prog.prefix.len() == 0 {
+            quote_expr!(self.cx, {})
+        } else {
+            quote_expr!(self.cx,
+                if clist.size == 0 {
+                    let haystack = self.input.as_bytes().slice_from(self.ic);
+                    match find_prefix(prefix_bytes, haystack) {
+                        None => break,
+                        Some(i) => {
+                            self.ic += i;
+                            next_ic = self.chars.set(self.ic);
+                        }
+                    }
+                }
+            )
+        }
+    }
+
+    // Builds a `match pc { ... }` expression from a list of arms, specifically
+    // for matching the current program counter with an instruction.
+    // A wild-card arm is automatically added that executes a no-op. It will
+    // never be used, but is added to satisfy the compiler complaining about
+    // non-exhaustive patterns.
+    fn match_insts(&self, mut arms: Vec<ast::Arm>) -> @ast::Expr {
+        let mat_pc = quote_expr!(self.cx, pc);
+        arms.push(self.wild_arm_expr(quote_expr!(self.cx, {})));
+        self.dummy_expr(ast::ExprMatch(mat_pc, arms))
+    }
+
+    // Creates a match arm for the instruction at `pc` with the expression
+    // `body`.
+    fn arm_inst(&self, pc: uint, body: @ast::Expr) -> ast::Arm {
+        ast::Arm {
+            attrs: vec!(),
+            pats: vec!(@ast::Pat{
+                id: ast::DUMMY_NODE_ID,
+                span: self.sp,
+                node: ast::PatLit(quote_expr!(self.cx, $pc)),
+            }),
+            guard: None,
+            body: body,
+        }
+    }
+
+    // Creates a wild-card match arm with the expression `body`.
+    fn wild_arm_expr(&self, body: @ast::Expr) -> ast::Arm {
+        ast::Arm {
+            attrs: vec!(),
+            pats: vec!(@ast::Pat{
+                id: ast::DUMMY_NODE_ID,
+                span: self.sp,
+                node: ast::PatWild,
+            }),
+            guard: None,
+            body: body,
+        }
+    }
+
+    // Builds a `[a, b, .., len]` expression where each element is the result
+    // of executing `to_expr`.
+    fn vec_from_fn(&self, len: uint, to_expr: |&ExtCtxt| -> @ast::Expr)
+                  -> @ast::Expr {
+        self.vec_expr(Vec::from_elem(len, ()).as_slice(),
+                      |cx, _| to_expr(cx))
+    }
+
+    // Converts `xs` to a `[x1, x2, .., xN]` expression by calling `to_expr`
+    // on each element in `xs`.
+    fn vec_expr<T>(&self, xs: &[T], to_expr: |&ExtCtxt, &T| -> @ast::Expr)
+                  -> @ast::Expr {
+        let mut exprs = vec!();
+        for x in xs.iter() {
+            exprs.push(to_expr(self.cx, x))
+        }
+        let vec_exprs = self.dummy_expr(ast::ExprVec(exprs));
+        quote_expr!(self.cx, $vec_exprs)
+    }
+
+    // Creates an expression with a dummy node ID given an underlying
+    // `ast::Expr_`.
+    fn dummy_expr(&self, e: ast::Expr_) -> @ast::Expr {
+        @ast::Expr {
+            id: ast::DUMMY_NODE_ID,
+            node: e,
+            span: self.sp,
+        }
+    }
+}
+
+// This trait is defined in the quote module in the syntax crate, but I
+// don't think it's exported.
+// Interestingly, quote_expr! only requires that a 'to_tokens' method be
+// defined rather than satisfying a particular trait.
+#[doc(hidden)]
+trait ToTokens {
+    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<ast::TokenTree>;
+}
+
+impl ToTokens for char {
+    fn to_tokens(&self, _: &ExtCtxt) -> Vec<ast::TokenTree> {
+        vec!(ast::TTTok(codemap::DUMMY_SP, token::LIT_CHAR((*self) as u32)))
+    }
+}
+
+impl ToTokens for bool {
+    fn to_tokens(&self, _: &ExtCtxt) -> Vec<ast::TokenTree> {
+        let ident = token::IDENT(token::str_to_ident(self.to_str()), false);
+        vec!(ast::TTTok(codemap::DUMMY_SP, ident))
+    }
+}
+
+/// Looks for a single string literal and returns it.
+/// Otherwise, logs an error with cx.span_err and returns None.
+fn parse(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Option<~str> {
+    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
+                                                Vec::from_slice(tts));
+    let entry = cx.expand_expr(parser.parse_expr());
+    let regex = match entry.node {
+        ast::ExprLit(lit) => {
+            match lit.node {
+                ast::LitStr(ref s, _) => s.to_str(),
+                _ => {
+                    cx.span_err(entry.span, format!(
+                        "expected string literal but got `{}`",
+                        pprust::lit_to_str(lit)));
+                    return None
+                }
+            }
+        }
+        _ => {
+            cx.span_err(entry.span, format!(
+                "expected string literal but got `{}`",
+                pprust::expr_to_str(entry)));
+            return None
+        }
+    };
+    if !parser.eat(&token::EOF) {
+        cx.span_err(parser.span, "only one string literal allowed");
+        return None;
+    }
+    Some(regex)
+}
diff --git a/src/test/bench/shootout-regex-dna.rs b/src/test/bench/shootout-regex-dna.rs
new file mode 100644 (file)
index 0000000..69c6c73
--- /dev/null
@@ -0,0 +1,94 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-stage1
+// ignore-cross-compile #12102
+
+#![feature(macro_rules, phase)]
+
+extern crate regex;
+#[phase(syntax)]extern crate regex_macros;
+extern crate sync;
+
+use std::io;
+use regex::{NoExpand, Regex};
+use sync::Arc;
+
+fn count_matches(seq: &str, variant: &Regex) -> int {
+    let mut n = 0;
+    for _ in variant.find_iter(seq) {
+        n += 1;
+    }
+    n
+}
+
+fn main() {
+    let mut rdr = if std::os::getenv("RUST_BENCH").is_some() {
+        let fd = io::File::open(&Path::new("shootout-k-nucleotide.data"));
+        ~io::BufferedReader::new(fd) as ~io::Reader
+    } else {
+        ~io::stdin() as ~io::Reader
+    };
+    let mut seq = StrBuf::from_str(rdr.read_to_str().unwrap());
+    let ilen = seq.len();
+
+    seq = regex!(">[^\n]*\n|\n").replace_all(seq.as_slice(), NoExpand(""));
+    let seq_arc = Arc::new(seq.clone()); // copy before it moves
+    let clen = seq.len();
+
+    let mut seqlen = sync::Future::spawn(proc() {
+        let substs = ~[
+            (regex!("B"), "(c|g|t)"),
+            (regex!("D"), "(a|g|t)"),
+            (regex!("H"), "(a|c|t)"),
+            (regex!("K"), "(g|t)"),
+            (regex!("M"), "(a|c)"),
+            (regex!("N"), "(a|c|g|t)"),
+            (regex!("R"), "(a|g)"),
+            (regex!("S"), "(c|g)"),
+            (regex!("V"), "(a|c|g)"),
+            (regex!("W"), "(a|t)"),
+            (regex!("Y"), "(c|t)"),
+        ];
+        let mut seq = seq;
+        for (re, replacement) in substs.move_iter() {
+            seq = re.replace_all(seq.as_slice(), NoExpand(replacement));
+        }
+        seq.len()
+    });
+
+    let variants = ~[
+        regex!("agggtaaa|tttaccct"),
+        regex!("[cgt]gggtaaa|tttaccc[acg]"),
+        regex!("a[act]ggtaaa|tttacc[agt]t"),
+        regex!("ag[act]gtaaa|tttac[agt]ct"),
+        regex!("agg[act]taaa|ttta[agt]cct"),
+        regex!("aggg[acg]aaa|ttt[cgt]ccct"),
+        regex!("agggt[cgt]aa|tt[acg]accct"),
+        regex!("agggta[cgt]a|t[acg]taccct"),
+        regex!("agggtaa[cgt]|[acg]ttaccct"),
+    ];
+    let (mut variant_strs, mut counts) = (vec!(), vec!());
+    for variant in variants.move_iter() {
+        let seq_arc_copy = seq_arc.clone();
+        variant_strs.push(variant.to_str().to_owned());
+        counts.push(sync::Future::spawn(proc() {
+            count_matches(seq_arc_copy.as_slice(), &variant)
+        }));
+    }
+
+    for (i, variant) in variant_strs.iter().enumerate() {
+        println!("{} {}", variant, counts.get_mut(i).get());
+    }
+    println!("");
+    println!("{}", ilen);
+    println!("{}", clen);
+    println!("{}", seqlen.get());
+}
diff --git a/src/test/compile-fail/syntax-extension-regex-invalid.rs b/src/test/compile-fail/syntax-extension-regex-invalid.rs
new file mode 100644 (file)
index 0000000..dd60756
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-stage1
+
+#![feature(phase)]
+
+extern crate regex;
+#[phase(syntax)] extern crate regex_macros;
+
+// Tests to make sure that `regex!` will produce a compile error when given
+// an invalid regular expression.
+// More exhaustive failure tests for the parser are done with the traditional
+// unit testing infrastructure, since both dynamic and native regexes use the
+// same parser.
+
+fn main() {
+    let _ = regex!("("); //~ ERROR Regex syntax error
+}