function negative_regex(ss, classExtra, isStart) {
    let chars = {};
    let end = true;
    for (let s of ss) {
        if (s.length > 1) {
            end = false;
        }
        let char = s.charCodeAt(0);
        if (!(char in chars)) {
            chars[char] = [];
        }
        chars[char].push(s);
    }
    let ranges = [['a'.charCodeAt(0), 'z'.charCodeAt(0)]];
    if (!isStart) {
        ranges.splice(0, 0, ['0'.charCodeAt(0), '9'.charCodeAt(0)]);
    }
    for (let char in chars) {
        for (let i = 0; i < ranges.length; i++) {
            let range = ranges[i];
            if (range[1] < char) continue;
            if (range[1] != char && range[0] != char) {
                ranges.splice(i, 1, [range[0], char - 1], [+char + 1, range[1]]);
            } else if(range[1] == char && range[0] == char) {
                ranges.splice(i, 1);
            } else if (range[1] == char) {
                range[1]--;
            } else {
                range[0]++;
            }
            break;
        }
    }
    let alphabet = ranges.map(x => {
        if (x[0] >= 97) { // is letter
            if (x[0] == x[1]) {
                return String.fromCharCode(x[0]) + String.fromCharCode(x[0]).toUpperCase();
            } else {
                return String.fromCharCode(x[0]) + '-' + String.fromCharCode(x[1]) + String.fromCharCode(x[0]).toUpperCase() + '-' + String.fromCharCode(x[1]).toUpperCase();
            }
        } else {
            if (x[0] == x[1]) {
                return String.fromCharCode(x[0]);
            } else {
                return String.fromCharCode(x[0]) + '-' + String.fromCharCode(x[1]);
            }
        }
    }).join('');
    let output = '([' + alphabet + (isStart ? '' : classExtra) + '][a-zA-Z' + classExtra + ']*';
    if (!end) {
        for (let char in chars) {
            output += '|' + String.fromCharCode(char);
            let new_ss = chars[char].map(x => x.substring(1)).filter(x => x.length != 0)
            if (new_ss.length > 0) {
                output += '|' + String.fromCharCode(char) + negative_regex(new_ss, classExtra, false);
            } else {
                output += '[a-zA-Z' + classExtra + ']+';
            }
        }
    } else {
        output += '|[' + Object.keys(chars).map(x => String.fromCharCode(x)).join('') + '][a-zA-Z' + classExtra + ']+';
    }
    output += ')';
    return output;
}
// characters specified in `classExtra`, but that is NOT part of the list of strings `ss`.
characters specified in `classExtra`, but that is NOT part of the list of strings `ss`.
characters specified in ` classExtra ` but that is NOT part of the list of strings ` ss ` .
function negative_regex(ss, classExtra, isStart) {
    let chars = {};
    let end = true;
    for (let s of ss) {
        if (s.length > 1) {
            end = false;
        }
        let char = s.charCodeAt(0);
        if (!(char in chars)) {
            chars[char] = [];
        }
        chars[char].push(s);
    }
    let ranges = [['a'.charCodeAt(0), 'z'.charCodeAt(0)]];
    if (!isStart) {
        ranges.splice(0, 0, ['0'.charCodeAt(0), '9'.charCodeAt(0)]);
    }
    for (let char in chars) {
        for (let i = 0; i < ranges.length; i++) {
            let range = ranges[i];
            if (range[1] < char) continue;
            if (range[1] != char && range[0] != char) {
                ranges.splice(i, 1, [range[0], char - 1], [+char + 1, range[1]]);
            } else if(range[1] == char && range[0] == char) {
                ranges.splice(i, 1);
            } else if (range[1] == char) {
                range[1]--;
            } else {
                range[0]++;
            }
            break;
        }
    }
    let alphabet = ranges.map(x => {
        if (x[0] >= 97) { 
            if (x[0] == x[1]) {
                return String.fromCharCode(x[0]) + String.fromCharCode(x[0]).toUpperCase();
            } else {
                return String.fromCharCode(x[0]) + '-' + String.fromCharCode(x[1]) + String.fromCharCode(x[0]).toUpperCase() + '-' + String.fromCharCode(x[1]).toUpperCase();
            }
        } else {
            if (x[0] == x[1]) {
                return String.fromCharCode(x[0]);
            } else {
                return String.fromCharCode(x[0]) + '-' + String.fromCharCode(x[1]);
            }
        }
    }).join('');
    let output = '([' + alphabet + (isStart ? '' : classExtra) + '][a-zA-Z' + classExtra + ']*';
    if (!end) {
        for (let char in chars) {
            output += '|' + String.fromCharCode(char);
            let new_ss = chars[char].map(x => x.substring(1)).filter(x => x.length != 0)
            if (new_ss.length > 0) {
                output += '|' + String.fromCharCode(char) + negative_regex(new_ss, classExtra, false);
            } else {
                output += '[a-zA-Z' + classExtra + ']+';
            }
        }
    } else {
        output += '|[' + Object.keys(chars).map(x => String.fromCharCode(x)).join('') + '][a-zA-Z' + classExtra + ']+';
    }
    output += ')';
    return output;
}
function negative_regex ( ss , classExtra , isStart ) { let chars = { } ; let end = true ; for ( let s of ss ) { if ( s . length > 1 ) { end = false ; } let char = s . charCodeAt ( 0 ) ; if ( ! ( char in chars ) ) { chars [ char ] = [ ] ; } chars [ char ] . push ( s ) ; } let ranges = [ [ 'a' . charCodeAt ( 0 ) , 'z' . charCodeAt ( 0 ) ] ] ; if ( ! isStart ) { ranges . splice ( 0 , 0 , [ '0' . charCodeAt ( 0 ) , '9' . charCodeAt ( 0 ) ] ) ; } for ( let char in chars ) { for ( let i = 0 ; i < ranges . length ; i ++ ) { let range = ranges [ i ] ; if ( range [ 1 ] < char ) continue ; if ( range [ 1 ] != char && range [ 0 ] != char ) { ranges . splice ( i , 1 , [ range [ 0 ] , char - 1 ] , [ + char + 1 , range [ 1 ] ] ) ; } else if ( range [ 1 ] == char && range [ 0 ] == char ) { ranges . splice ( i , 1 ) ; } else if ( range [ 1 ] == char ) { range [ 1 ] -- ; } else { range [ 0 ] ++ ; } break ; } } let alphabet = ranges . map ( x => { if ( x [ 0 ] >= 97 ) { if ( x [ 0 ] == x [ 1 ] ) { return String . fromCharCode ( x [ 0 ] ) + String . fromCharCode ( x [ 0 ] ) . toUpperCase ( ) ; } else { return String . fromCharCode ( x [ 0 ] ) + '-' + String . fromCharCode ( x [ 1 ] ) + String . fromCharCode ( x [ 0 ] ) . toUpperCase ( ) + '-' + String . fromCharCode ( x [ 1 ] ) . toUpperCase ( ) ; } } else { if ( x [ 0 ] == x [ 1 ] ) { return String . fromCharCode ( x [ 0 ] ) ; } else { return String . fromCharCode ( x [ 0 ] ) + '-' + String . fromCharCode ( x [ 1 ] ) ; } } } ) . join ( '' ) ; let output = '([' + alphabet + ( isStart ? '' : classExtra ) + '][a-zA-Z' + classExtra + ']*' ; if ( ! end ) { for ( let char in chars ) { output += '|' + String . fromCharCode ( char ) ; let new_ss = chars [ char ] . map ( x => x . substring ( 1 ) ) . filter ( x => x . length != 0 ) if ( new_ss . length > 0 ) { output += '|' + String . fromCharCode ( char ) + negative_regex ( new_ss , classExtra , false ) ; } else { output += '[a-zA-Z' + classExtra + ']+' ; } } } else { output += '|[' + Object . keys ( chars ) . map ( x => String . fromCharCode ( x ) ) . join ( '' ) + '][a-zA-Z' + classExtra + ']+' ; } output += ')' ; return output ; }
characters specified in `classExtra`, but that is NOT part of the list of strings `ss`.
characters specified in ` classExtra ` but that is NOT part of the list of strings ` ss ` .
// is letter