Third stage : build the shortest negated character class regular expression
(a char class beginning with a ^, such as [^A-D] which comprises everything but characters A, B, C and D)
508314
function() 
	{
		// Build a list of characters used inside the string (as ranges)
		// characters not in the list can be
		//  - forbidden as tokens (LF, CR, ', ", -, \, 127) although these are allowed in the string too
		//  - used as compression tokens
		//  - neither used as compression tokens (if there are leftovers) nor in the string
		//    those can be included in the RegExp without affecting the output
		var details = '';
		var usedCharacters = [];
		var forbiddenCharacters = [];
		var firstInLine = -1;
		var availableCharactersCount = 0;
		for(i=1;i<128;++i) {
			var token = String.fromCharCode(i);
			if (this.input.indexOf(token)>-1) {
				if (firstInLine ==-1) {
					firstInLine = i;
				}
			} else {
				if (firstInLine >-1) {
					usedCharacters.push({first:firstInLine, last:i-1, size:Math.min(i-firstInLine,3)});
					firstInLine = -1;
				}
				if (this.isForbiddenCharacter(i)) {
					forbiddenCharacters.push(token);
				} else {
					++availableCharactersCount;
				}
			}
		}
		if (firstInLine >-1) {
			usedCharacters.push({first:firstInLine, last:i-1, size:Math.min(i-firstInLine,3)});
		}
		
		// Issue #2 : unicode characters handling
		var inputContainsUnicode = false;
		for (i=0;i<this.input.length&&!inputContainsUnicode;++i) {
			inputContainsUnicode = inputContainsUnicode || (this.input.charCodeAt(i)>127);
		}
		if (inputContainsUnicode) {
			// non-ASCII as a whole block. Those characters are not allowed as tokens,
			// and the block can be merged later to save bytes
			usedCharacters.push({first:128, last:65535, size:3});
		}
		
		details = availableCharactersCount + " available tokens, "+this.tokenCount+" needed.\n"
		for (i in usedCharacters)
		{
			j=usedCharacters[i];
			details+=this.getPrintableString(j.first);
			if (j.size>2) details+='-';
			if (j.size>1) details+=this.getPrintableString(j.last);
		}
		details+="\n";
		
		
		// Now, shorten the regexp by sacrificing some characters that will not be used as tokens.
		// The second stage yielded the actual number of tokens required.
		// The initial regexp lists all characters present in the string to compress. Since it is
		// used with an initial negation ^, it will match on all other characters.
		// Characters are split into used by the strings, tokens, and unused
		// This step iterates on the RegExp, merging ranges to reduce its length.
		// Characters between the ranges are included, thus lost as tokens.
		// For instance, [A-K] is shorter than [A-CG-K] but loses D,E,F as potential tokens
		// The process is repeated while there are enough tokens left.
		var margin = availableCharactersCount - this.tokenCount;
		var regExpString = "";
		while (true) { // do not stop on margin==0, the next step may cost zero
			var bestBlockIndex=[];
			var bestGain = -999;
			var bestCost = 999;
			// gain may change at each step as we merge blocks, so qsort won't cut it
			for (i=0;i<usedCharacters.length-1;++i) {
				var currentBlock = usedCharacters[i];
				var nextBlock = usedCharacters[i+1];
				var cost = nextBlock.first - currentBlock.last - 1  - this.countForbiddenCharacters(currentBlock.last+1, nextBlock.first-1);
				var gain = currentBlock.size+nextBlock.size-3;
				// extra gain if the character absorbed in a block needs a multibyte representation (escaped or unicode)
				if (currentBlock.first != currentBlock.last) {
					gain+=this.printToRegexpCharClass(currentBlock.last).length-1;
				}
				if (nextBlock.first != nextBlock.last) {
					gain+=this.printToRegexpCharClass(nextBlock.first).length-1;
				}
				// we cannot use the ratio gain/cost as cost may be 0, if the interval is only made of one forbidden character
				if (cost<=margin && (gain*bestCost > bestGain*cost || (gain*bestCost == bestGain*cost && cost<bestCost))) {
					bestBlockIndex = [i];
					bestCost = cost;
					bestGain = gain;	// can be negative. Do not break yet, as the next one may be positive and offset the loss.
				}
				// attempt to merge three blocks in a row, to overcome a negative barrier
				// (costly first merge, but that unlocks a gain of 3 or more)
				// this helps getting rid of expensive characters such as ]
				if (i<usedCharacters.length-2) {
					var nextYetBlock = usedCharacters[i+2];
					cost += nextYetBlock.first - nextBlock.last - 1  - this.countForbiddenCharacters(nextBlock.last+1, nextYetBlock.first-1);
					gain += nextYetBlock.size;
					gain += (this.needsEscapingInCharClass(nextBlock.last)?1:0);
					if (nextYetBlock.first != nextYetBlock.last) {
						gain+=(this.needsEscapingInCharClass(nextYetBlock.first)?1:0);
					}
					if (cost<=margin && (gain*bestCost > bestGain*cost || (gain*bestCost == bestGain*cost && cost<bestCost))) {
						bestBlockIndex = [i+1, i];
						bestCost = cost;
						bestGain = gain;
					}
				}
			}
			if (bestBlockIndex.length==0) break; // no matching block (negative gain, or too long)

			for (i in bestBlockIndex) {
				var blockIndex = bestBlockIndex[i];
				var currentBlock = usedCharacters[blockIndex];	// accessed by reference of course
				var nextBlock = usedCharacters[blockIndex+1];
				currentBlock.last=nextBlock.last;
				currentBlock.size=3;
				usedCharacters.splice(1+blockIndex, 1);
			}
			margin -= bestCost;
			
			details +="gain "+bestGain+" for "+bestCost+", ";
			details +="margin = "+margin+", ";
			
			// build the regular expression for unpacking
			// character 93 "]" needs escaping to avoid closing the character class
			var currentCharClass = "";
			for (i in usedCharacters)
			{
				j=usedCharacters[i];
				currentCharClass+=this.printToRegexpCharClass(j.first);
				if (j.size>2) currentCharClass+='-';
				if (j.size>1) currentCharClass+=this.printToRegexpCharClass(j.last);
			}
			details +=currentCharClass+"\n";
			// keep the shortest RegExp - this may not be the last one if going through a negative gain streak
			if (regExpString.length==0 || regExpString.length>currentCharClass.length) {
				regExpString = currentCharClass;
			}
		}
		
		regExpString = "^"+regExpString;		
		usedCharacters.push({first:128, last:128});	// upper boundary for the loop, increase to use multibyte characters as tokens
		var tokenString = "";
		var charIndex = 1;
		for (var i=0;i<usedCharacters.length;++i)
		{
			while (charIndex<usedCharacters[i].first) {
				if (!this.isForbiddenCharacter(charIndex)) {
					tokenString+=String.fromCharCode(charIndex);
				}
				++charIndex;
			}
			charIndex = 1+usedCharacters[i].last;
		}
		details+= "tokens = "+tokenString+" ("+tokenString.length+")\n";
		
		// use the same matches order as in the second stage
		this.matchesLookup.sort(function(a,b) {return a.newOrder-b.newOrder; });
		var thirdStageOutput = this.input;
		// and perform the replacement using the token string as listed above
		for (var i=0;i<this.tokenCount;++i)
		{
			var matchedString = this.matchesLookup[i].originalString;
			var token = tokenString[i];

			details+=token.charCodeAt(0)+"("+token+"), str = "+matchedString+"\n";
			thirdStageOutput = matchedString+token+thirdStageOutput.split(matchedString).join(token);
		}
		
		// add the unpacking code to the compressed string
		var checkedString = thirdStageOutput;
		c=thirdStageOutput.split('"').length<thirdStageOutput.split("'").length?(B='"',/"/g):(B="'",/'/g);
		thirdStageOutput='for(_='+B+thirdStageOutput.replace(c,'\\'+B)+B;
		thirdStageOutput+=';g=/['+regExpString+']/.exec(_);)with(_.split(g))_=join(shift());'+this.environment+'eval(_)';
		
		var resultSize = this.getByteLength(thirdStageOutput);
		
		details+="------------------------\nFinal check : ";
		var regToken = new RegExp("["+regExpString+"]","");
		for(var token="" ; token = regToken.exec(checkedString) ; ) {
			var k = checkedString.split(token);
			checkedString = k.join(k.shift());
		}
		var success = (checkedString == this.input);
		details+=(success ? "passed" : "failed")+".\n";
		

		return [resultSize, thirdStageOutput, details];
	}
1263524
protected function createInitialDefinition()
    {
        return [
            /*
             * Match against non-special characters. To explain the components of this:
             *
             * [^\\\\*\[?]+(?:\\\\.[^\\\\*\[?]*)*
             *  - This matches non-special (\*[?) characters. If it matches one, it'll permit it to be an escape
             *    (i.e. \) if a character exists after it (which may be "special"). This then returns to the previous
             *    matching pattern, repeating the same rules until a non-escaped "special" character is hit.
             *
             * (?:\\\\.[^\\\\*\[?]*)+
             *  - This immediately looks for escape characters, as the previous component of this regex requires for the
             *    initial character to be non-special. This then returns to the standard rules the previous regex.
             */
            '[^\\\\*\[?]+(?:\\\\.[^\\\\*\[?]*)*|(?:\\\\.[^\\\\*\[?]*)+' => self::T_WORD,
            // Simple match of "*"
            '\*' => self::T_WILDCARD_MULTI,
            // Simple match of "?"
            '\?' => self::T_WILDCARD_SINGLE,
            /*
             * Matches against [. This also optionally matches "!" or "^" as the first character to provide negation
             * context. The positive lookahead provides a means to check for "]" as the first character. This is a
             * slightly nasty hack to deal with a rule that "]" can be permitted as a standard character in a character,
             * grouping so long as it's the first character. Once we move into the IN_GROUP state we have no such
             * context, so it must be checked at this level. To achieve this we lookahead for the character, and ensure
             * it's captured by adding a capturing group inside (regex lookarounds do not capture).
             */
            '\[([!^]?)(?=(\])?)' => function (Stateful $lexer, $matches) {
                // Determine the state to enter (depending on whether the lookahead succeeded, i.e. "]" is the first
                // character of the grouping)
                $state = isset($matches[2])
                    ? 'IN_GROUP_SPECIAL_FIRST'
                    : 'IN_GROUP';

                $lexer->pushState($state);

                // Negated grouping if the first character is "!"
                return $matches[1] !== ''
                    ? self::T_GROUP_BEGIN_NEGATED
                    : self::T_GROUP_BEGIN;
            }
        ];
    }
1157172
static Matcher convertSingleCharClassToSeq(Matcher matcher) {
    if (matcher instanceof CharClassMatcher) {
      Optional<Character> opt = matcher.<CharClassMatcher>as().set().character();
      if (opt.isPresent()) {
        return new CharSeqMatcher(opt.get());
      }
    }
    return matcher;
  }
1296481
public Regex not() {
      if (this.pattern.length() > 0) {
         if (this.pattern.charAt(0) == '[' && this.pattern.length() > 1) {
            return re("[^" + this.pattern.substring(1));
         }
         return re("^" + this.pattern);
      }
      return this;
   }
1080907
def _is_punctuation(char):
    """"""
    cp = ord(char)
    # We treat all non-letter/number ASCII as punctuation.
    # Characters such as "^", "$", and "`" are not in the Unicode
    # Punctuation class but we treat them as punctuation anyways, for
    # consistency.
    if ((cp >= 33 and cp <= 47) or (cp >= 58 and cp <= 64) or
            (cp >= 91 and cp <= 96) or (cp >= 123 and cp <= 126)):
        return True
    cat = unicodedata.category(char)
    if cat.startswith("P"):
        return True
    return False
1258311
def _skip_char_around(self, string, char='\n'):
        
        starts, ends = '', ''
        n = len(char)
        if string.startswith(char):
            starts = string[:n]
            string = string[n:]
        if string.endswith(char):
            ends = string[-n:]
            string = string[:-n]
        string = self._base_compile(string)
        if starts:
            string = starts + string
        if ends:
            string = string + ends
        return string
1181343
protected void checkConsecutiveAlpha() {

        Pattern symbolsPatter = Pattern.compile(REGEX_ALPHA_UC + "+");
        Matcher matcher = symbolsPatter.matcher(this.password);
        int met = 0;
        while (matcher.find()) {
            int start = matcher.start();
            int end = matcher.end();
            if (start == end) {
                continue;
            }
            int diff = end - start;
            if (diff >= 3) {
                met += diff;
            }

        }

        this.result.negative(met * CONSECUTIVE_ALPHA_WEIGHT);

        // alpha lower case

        symbolsPatter = Pattern.compile(REGEX_ALPHA_LC + "+");
        matcher = symbolsPatter.matcher(this.password);
        met = 0;
        while (matcher.find()) {
            int start = matcher.start();
            int end = matcher.end();
            if (start == end) {
                continue;
            }
            int diff = end - start;
            if (diff >= 3) {
                met += diff;
            }

        }

        this.result.negative(met * CONSECUTIVE_ALPHA_WEIGHT);
    }
910498
public static String unAccent(String input) {
        if (MAP_NORM == null || MAP_NORM.size() == 0) {
            MAP_NORM = new HashMap<Character, Character>();
            MAP_NORM.put('À', 'A');
            MAP_NORM.put('Á', 'A');
            MAP_NORM.put('Â', 'A');
            MAP_NORM.put('Ã', 'A');
            MAP_NORM.put('Ä', 'A');
            MAP_NORM.put('È', 'E');
            MAP_NORM.put('É', 'E');
            MAP_NORM.put('Ê', 'E');
            MAP_NORM.put('Ë', 'E');
            MAP_NORM.put('Í', 'I');
            MAP_NORM.put('Ì', 'I');
            MAP_NORM.put('Î', 'I');
            MAP_NORM.put('Ï', 'I');
            MAP_NORM.put('Ù', 'U');
            MAP_NORM.put('Ú', 'U');
            MAP_NORM.put('Û', 'U');
            MAP_NORM.put('Ü', 'U');
            MAP_NORM.put('Ò', 'O');
            MAP_NORM.put('Ó', 'O');
            MAP_NORM.put('Ô', 'O');
            MAP_NORM.put('Õ', 'O');
            MAP_NORM.put('Ö', 'O');
            MAP_NORM.put('Ñ', 'N');
            MAP_NORM.put('Ç', 'C');
            MAP_NORM.put('ª', 'A');
            MAP_NORM.put('º', 'O');
            MAP_NORM.put('§', 'S');
            MAP_NORM.put('³', '3');
            MAP_NORM.put('²', '2');
            MAP_NORM.put('¹', '1');
            MAP_NORM.put('à', 'a');
            MAP_NORM.put('á', 'a');
            MAP_NORM.put('â', 'a');
            MAP_NORM.put('ã', 'a');
            MAP_NORM.put('ä', 'a');
            MAP_NORM.put('è', 'e');
            MAP_NORM.put('é', 'e');
            MAP_NORM.put('ê', 'e');
            MAP_NORM.put('ë', 'e');
            MAP_NORM.put('í', 'i');
            MAP_NORM.put('ì', 'i');
            MAP_NORM.put('î', 'i');
            MAP_NORM.put('ï', 'i');
            MAP_NORM.put('ù', 'u');
            MAP_NORM.put('ú', 'u');
            MAP_NORM.put('û', 'u');
            MAP_NORM.put('ü', 'u');
            MAP_NORM.put('ò', 'o');
            MAP_NORM.put('ó', 'o');
            MAP_NORM.put('ô', 'o');
            MAP_NORM.put('õ', 'o');
            MAP_NORM.put('ö', 'o');
            MAP_NORM.put('ñ', 'n');
            MAP_NORM.put('ç', 'c');
        }

        if (input == null) {
            return "";
        }

        StringBuilder sb = new StringBuilder(input);

        for (int i = 0; i < input.length(); i++) {
            Character c = MAP_NORM.get(sb.charAt(i));
            if (c != null) {
                sb.setCharAt(i, c.charValue());
            }
        }

        return sb.toString();

    }
734188
public static String restrictHTML (String src, String[] regexes)
    {
        if (StringUtil.isBlank(src)) {
            return src;
        }

        ArrayList<String> list = new ArrayList<String>();
        list.add(src);
        for (String regexe : regexes) {
            Pattern p = Pattern.compile(regexe, Pattern.CASE_INSENSITIVE);
            for (int jj=0; jj < list.size(); jj += 2) {
                String piece = list.get(jj);
                Matcher m = p.matcher(piece);
                if (m.find()) {
                    list.set(jj, piece.substring(0, m.start()));
                    list.add(jj + 1, piece.substring(m.start(), m.end()));
                    list.add(jj + 2, piece.substring(m.end()));
                }
            }
        }

        // now, the even elements of list contain untrusted text, the
        // odd elements contain stuff that matched a regex
        StringBuilder buf = new StringBuilder();
        for (int jj=0, nn = list.size(); jj < nn; jj++) {
            String s = list.get(jj);
            if (jj % 2 == 0) {
                s = s.replace("<", "&lt;");
                s = s.replace(">", "&gt;");
            }
            buf.append(s);
        }
        return buf.toString();
    }
702972
def char2range(d, is_bytes=False, invert=True):
    """"""

    fmt = bytesformat if is_bytes else uniformat
    maxrange = MAXASCII if is_bytes else MAXUNICODE

    for k1 in sorted(d.keys()):
        v1 = d[k1]
        if not isinstance(v1, list):
            char2range(v1, is_bytes=is_bytes, invert=invert)
        else:
            inverted = k1.startswith('^')
            v1.sort()
            last = None
            first = None
            ilast = None
            ifirst = None
            v2 = []
            iv2 = []
            if v1 and v1[0] != 0:
                ifirst = 0
            for i in v1:
                if first is None:
                    first = i
                    last = i
                elif i == last + 1:
                    last = i
                elif first is not None:
                    if first == last:
                        v2.append(fmt(first))
                    else:
                        v2.append("%s-%s" % (fmt(first), fmt(last)))
                    if invert and ifirst is not None:
                        ilast = first - 1
                        if ifirst == ilast:
                            iv2.append(fmt(ifirst))
                        else:
                            iv2.append("%s-%s" % (fmt(ifirst), fmt(ilast)))
                    ifirst = last + 1
                    first = i
                    last = i

            if not v1:
                iv2 = ["%s-%s" % (fmt(0), fmt(maxrange))]
            elif first is not None:
                if first == last:
                    v2.append(fmt(first))
                else:
                    v2.append("%s-%s" % (fmt(first), fmt(last)))
                if invert and ifirst is not None:
                    ilast = first - 1
                    if ifirst == ilast:
                        iv2.append(fmt(ifirst))
                    else:
                        iv2.append("%s-%s" % (fmt(ifirst), fmt(ilast)))
                ifirst = last + 1
                if invert and ifirst <= maxrange:
                    ilast = maxrange
                    if ifirst == ilast:
                        iv2.append(fmt(ifirst))
                    else:
                        iv2.append("%s-%s" % (fmt(ifirst), fmt(ilast)))
            d[k1] = ''.join(v2)
            if invert:
                d[k1[1:] if inverted else '^' + k1] = ''.join(iv2)
266333
def tokenize_regex(input):
    
    # Regular expression for tokenizing other regular expressions.
    p = re.compile(r'''^(
        \(\?P\<[a-zA-Z0-9_-]+\>  | # Start of named group.
        \(\?#[^)]*\)             | # Comment
        \(\?=                    | # Start of lookahead assertion
        \(\?!                    | # Start of negative lookahead assertion
        \(\?<=                   | # If preceded by.
        \(\?<                    | # If not preceded by.
        \(?:                     | # Start of group. (non capturing.)
        \(                       | # Start of group.
        \(?[iLmsux]              | # Flags.
        \(?P=[a-zA-Z]+\)         | # Back reference to named group
        \)                       | # End of group.
        \{[^{}]*\}               | # Repetition
        \*\? | \+\? | \?\?\      | # Non greedy repetition.
        \* | \+ | \?             | # Repetition
        \#.*\n                   | # Comment
        \\. |

        # Character group.
        \[
            ( [^\]\\]  |  \\.)*
        \]                  |

        [^(){}]             |
        .
    )''', re.VERBOSE)

    tokens = []

    while input:
        m = p.match(input)
        if m:
            token, input = input[:m.end()], input[m.end():]
            if not token.isspace():
                tokens.append(token)
        else:
            raise Exception('Could not tokenize input regex.')

    return tokens
828140
function(skip){
    skip = skip || 0;
    var start = this.input[skip];
    assert(start === '(' || start === '{' || start === '[',
           'The start character should be "(", "{" or "["');
    var end = characterParser.BRACKETS[start];
    var range;
    try {
      range = characterParser.parseUntil(this.input, end, {start: skip + 1});
    } catch (ex) {
      if (ex.index !== undefined) {
        var idx = ex.index;
        // starting from this.input[skip]
        var tmp = this.input.substr(skip).indexOf('\n');
        // starting from this.input[0]
        var nextNewline = tmp + skip;
        var ptr = 0;
        while (idx > nextNewline && tmp !== -1) {
          this.incrementLine(1);
          idx -= nextNewline + 1;
          ptr += nextNewline + 1;
          tmp = nextNewline = this.input.substr(ptr).indexOf('\n');
        };

        this.incrementColumn(idx);
      }
      if (ex.code === 'CHARACTER_PARSER:END_OF_STRING_REACHED') {
        this.error('NO_END_BRACKET', 'The end of the string reached with no closing bracket ' + end + ' found.');
      } else if (ex.code === 'CHARACTER_PARSER:MISMATCHED_BRACKET') {
        this.error('BRACKET_MISMATCH', ex.message);
      }
      throw ex;
    }
    return range;
  }
461616
function base32DecodeNextCharacter(chunk, characterIndex, buffer, index) {
    const byteIndex = Math.floor(index + (characterIndex * 5) / 8);
    const offset = characterIndex % 8;
    switch (offset) {
        case 0:
            buffer[byteIndex] |= chunk << 3;
            break;
        case 1:
            buffer[byteIndex] |= chunk >>> 2;
            buffer[byteIndex + 1] |= chunk << 6;
            break;
        case 2:
            buffer[byteIndex] |= chunk << 1;
            break;
        case 3:
            buffer[byteIndex] |= chunk >>> 4;
            buffer[byteIndex + 1] |= chunk << 4;
            break;
        case 4:
            buffer[byteIndex] |= chunk >>> 1;
            buffer[byteIndex + 1] |= chunk << 7;
            break;
        case 5:
            buffer[byteIndex] |= chunk << 2;
            break;
        case 6:
            buffer[byteIndex] |= chunk >>> 3;
            buffer[byteIndex + 1] |= chunk << 5;
            break;
        case 7:
            buffer[byteIndex] |= chunk;
            break;
    }
}
1030524
private String replacePosixClasses(String input) {
        return input
            .replace(":alnum:", "\\p{Alnum}")
            .replace(":alpha:", "\\p{L}")
            .replace(":ascii:", "\\p{ASCII}")
            .replace(":digit:", "\\p{Digit}")
            .replace(":xdigit:", "\\p{XDigit}");
    }
679116
private boolean buildRegexpParser() {

    // Convert wildcard string mask to regular expression
    String regexp = convertWildcardExpressionToRegularExpression(mStringMask);

    if (regexp == null) {
      out.println(DebugUtil.getPrefixErrorMessage(this)
                  + "irregularity in regexp conversion - now not able to parse any strings, all strings will be rejected!");
      return false;
    }

    // Instantiate a regular expression parser
    try {
      mRegexpParser = Pattern.compile(regexp);
    }
    catch (PatternSyntaxException e) {
      if (mDebugging) {
        out.println(DebugUtil.getPrefixErrorMessage(this) + "RESyntaxException \"" + e.getMessage()
                    + "\" caught - now not able to parse any strings, all strings will be rejected!");
      }
      if (mDebugging) {
        e.printStackTrace(System.err);
      }
      return false;
    }
    if (mDebugging) {
      out.println(DebugUtil.getPrefixDebugMessage(this) + "regular expression parser from regular expression " + regexp
                  + " extracted from wildcard string mask " + mStringMask + ".");
    }
    return true;
  }
297640
def _build_regexes():
    
    # Define a regex that matches ASCII text.
    encoding_regexes = {'ascii': re.compile('^[\x00-\x7f]*$')}

    for encoding in CHARMAP_ENCODINGS:
        # Make a sequence of characters that bytes \x80 to \xFF decode to
        # in each encoding, as well as byte \x1A, which is used to represent
        # the replacement character � in the sloppy-* encodings.
        byte_range = bytes(list(range(0x80, 0x100)) + [0x1a])
        charlist = byte_range.decode(encoding)

        # The rest of the ASCII bytes -- bytes \x00 to \x19 and \x1B
        # to \x7F -- will decode as those ASCII characters in any encoding we
        # support, so we can just include them as ranges. This also lets us
        # not worry about escaping regex special characters, because all of
        # them are in the \x1B to \x7F range.
        regex = '^[\x00-\x19\x1b-\x7f{0}]*$'.format(charlist)
        encoding_regexes[encoding] = re.compile(regex)
    return encoding_regexes
1219534
def _py_pattern_from_bracket_expression(bracket_expression, path_name):
    
    """
    single_chars = set()
    multi_chars = set()
    ranges = set()
    matching, items = _read_bracket_expression(bracket_expression)
    for item in items:
        if _is_be_range(item):
            start_seq, end_seq = _read_be_range(item)
            if len(start_seq) != 1 or len(end_seq) != 1:
                raise ValueError(u'Ranges are only supported between single-char collating elems')
            ranges.add((start_seq, end_seq))
        elif _is_be_character_class(item):
            # TODO: handle character classes...
            # Idea: (?:[single r-an-ge-!]|multi1|multi2|[class1]|[class2])
            raise ValueError(u'Character classes are not supported')
        else:
            if _is_be_collating_element(item):
                sequence = _read_be_collating_element(item)
            elif _is_be_equivalence_class(item):
                sequence = _read_be_equivalence_class(item)
            else:
                raise ValueError(u'Unexpected item {}'.format(item))

            if len(sequence) == 0:
                raise ValueError(u'Empty string is not a valid collating element')
            elif len(sequence) == 1:
                single_chars.add(sequence)
            else:
                multi_chars.add(sequence)

    if path_name:  # bracket expression cannot match /
        if not matching:
            single_chars.add(_SLASH)  # Pretty easy!
        else:  # Remove slash from single_chars and ranges (we do not check multi_chars)
            if _SLASH in single_chars:
                single_chars.remove(_SLASH)

            slash_code_point = ord(_SLASH)
            cleared_ranges = set()
            for be_range in ranges:
                start_seq, end_seq = be_range
                if len(start_seq) != 1 or len(end_seq) != 1:
                    raise ValueError(u'Only ranges between single characters are supported in '
                                     u'bracket expression with the path_name flag')
                start_code_point = ord(start_seq)
                end_code_point = ord(end_seq)
                if start_code_point > end_code_point:
                    raise ValueError(u'Invalid range, wrong order of bounds: {}'.format(be_range))
                if slash_code_point < start_code_point or slash_code_point > end_code_point:
                    cleared_ranges.add(be_range)
                else:
                    if start_seq == slash_code_point:
                        if end_code_point == slash_code_point:  # /-/
                            continue
                        else:  # start = slash < end
                            start_seq = unichr(start_code_point + 1)
                            cleared_ranges.add((start_seq, end_seq))
                    else:
                        if end_code_point == slash_code_point:  # start < slash = end
                            end_seq = unichr(end_code_point - 1)
                            cleared_ranges.add((start_seq, end_seq))
                        else:  # start < slash < end
                            before_slash = unichr(slash_code_point - 1)
                            after_slash = unichr(slash_code_point + 1)
                            cleared_ranges.add((start_seq, before_slash))
                            cleared_ranges.add((after_slash, end_seq))
            ranges = cleared_ranges

    if len(single_chars) > 0 or len(ranges) > 0:
        primary_pattern = [u'['] if matching else [u'[^']

        for char in single_chars:
            primary_pattern.append(_escape_bracket_expression_character(char))

        for start, end in ranges:
            primary_pattern.append(_escape_bracket_expression_character(start))
            primary_pattern.append(u'-')
            primary_pattern.append(_escape_bracket_expression_character(end))

        primary_pattern.append(u']')
        primary_pattern = u''.join(primary_pattern)
    else:
        primary_pattern = None

    if len(multi_chars) > 0:
        if not matching:
            raise ValueError(u'Cannot perform negative match on bracket expression containing '
                             u'multi-character collating elements')
        alternate_pattern = u'|'.join(re.escape(seq) for seq in multi_chars)
    else:
        alternate_pattern = None

    if alternate_pattern is None:
        if primary_pattern is None:  # Can happen when removing characters
            return _PY_IMPOSSIBLE_MATCH
        else:
            return primary_pattern
    else:
        if primary_pattern is not None:
            alternate_pattern = primary_pattern + u'|' + alternate_pattern
        return u'(?:{})'.format(alternate_pattern)