partial regex tester

by TexasBrawler

HTML

<p>
    Test against <span class="regex">foo bar</span>:<br/>
    <input type="text" id="input_0" />
    <span class="results empty">No text yet</span>
</p>
<p>
    Test against <span class="regex">^foo bar$</span>:<br/>
    <input type="text" id="input_1" />
    <span class="results empty">No text yet</span>
</p>
<p>
    Test against <span class="regex">^fo+(\s*b\S[rz])+$</span> (e.g., "foo bar", "foo baz", "foo bar baz"):<br/>
    <input type="text" id="input_2" />
    <span class="results empty">No text yet</span>
</p>
<p>
    Test against <span class="regex">^\d{3}-\d{3}-\d{4}$</span>:<br/>
    <input type="text" id="input_3" />
    <span class="results empty">No text yet</span>
</p>

CSS

.empty {
    background-color: #eeeeee;
}
.matches {
    background-color: #ccffcc;
    font-weight: bold;
}
.stillhope {
    background-color: #ccffff;
}
.mismatch {
    background-color: #ffcccc;
    font-weight: bold;
}
.regex {
    border-top:1px solid #999;
    border-bottom:1px solid #999;
    font-family: Courier New, monospace;
    background-color: #eee;
    color: #666;
}

JavaScript

var strings = {
    matches: "Matches!",
    stillhope: "There's still hope...",
    mismatch: "Does not match",
    empty: "No text yet"
};

// Object to handle watching for partial matches
function PartialRegexMonitor(regex, input_id) {
    var self = this;
    this.relen = regex.length;
    $('body').on('keyup', '#'+input_id, function() {
         self.update_test_results(regex, input_id);
    });
}

PartialRegexMonitor.prototype.update_test_results = function(regex, input_id) {
    var input = $('#'+input_id).val(),
        matches = find_partial_matches(regex, input),
        span = $('#'+input_id).siblings('.results');
    span.removeClass('match');
    span.removeClass('stillhope');
    span.removeClass('mismatch');
    span.removeClass('empty');
    span.addClass(matches.type)
        .html(strings[matches.type]);
}

// Test a partial regex against a string
function partial_match_tester(regex_part, str) {
    var matched = false;
    try {
        var re = new RegExp(regex_part, 'g'),
            matches = str.match(re),
            match_count = matches.length,
            temp_re;
        for(var i = 0; i < match_count; i++) {
            temp_re = new RegExp(regex_part+'$'); // make sure this partial match ends in a piece that could still match the entire regex
            matched = temp_re.test(str);
            if(matched) break;
        }
    }
    catch(e) {
    }
    return matched;
}

// Find the longest matching partial regex
function find_partial_matches(regex, str) {
    var relen = regex.length,
        matched = false,
        matches = {type: 'mismatch',
                   len: 0},
        regex_part = '';
    if(str.length == 0) {
        matches.type = 'empty';
        return matches;
    }
    
    for(var i=relen; i>=1; i--) {
        if(i==1 && str[0] == '^') { // don't allow matching against only '^'
            continue;
        }
        regex_part = regex.substr(0,i);
        // replace {\d}$ with {0,\d} for testing
       ...