Regex - check if input still has chances to become matching

前端 未结 11 1403
天命终不由人
天命终不由人 2020-12-05 00:51

We\'ve got such regexp:

var regexp = /^one (two)+ three/;

So only string like \"one two three\" or \"one two three four\

相关标签:
11条回答
  • 2020-12-05 01:04

    Another interesting option that I have used before is to OR every character expected with the $ symbol. This may not work well for every case but for cases where you are looking at specific characters and need a partial match on each character, this works.

    For example (in Javascript):

    var reg = /^(o|$)(n|$)(e|$)(\s|$)$/;
    
    reg.test('')      -> true;
    reg.test('o')     -> true;
    reg.test('on')    -> true;
    reg.test('one')   -> true;
    reg.test('one ')  -> true;
    reg.test('one t') -> false;
    reg.test('x')     -> false;
    reg.test('n')     -> false;
    reg.test('e')     -> false;
    reg.test(' ')     -> false;
    

    While this isn't the prettiest regex, it is repeatable so if you need to generate it dynamically for some reason, you know the general pattern.

    The same pattern can be applied to whole words as well, which probably isn't as helpful because they couldn't type one-by-one to get to these points.

    var reg = /^(one|$)(\stwo|$)$/;
    
    reg.test('')        -> true;
    reg.test('one')     -> true;
    reg.test('one ')    -> false;
    reg.test('one two') -> true;
    
    0 讨论(0)
  • 2020-12-05 01:11

    Your original question was simply testing a string's placement within another, specifically, the start. The fastest way to do that would be to use substr on the match string, followed by indexOf. I've updated my original answer to reflect that:

    function check(str){
      return 'one two three'.substr(0, str.length) === str;
    };
    console.log(check('one'));           // true
    console.log(check('one two'));       // true
    console.log(check('one two three')); // true
    console.log(check('one three'));     // false
    

    If you need case-insensitivity, it's still fastest to simply toLowerCase the match & input strings. (If interested, here's a jsperf of substr, indexOf and RegExp testing for the start of a string, case-insensitively: http://jsperf.com/substr-vs-indexof-vs-regex )

    0 讨论(0)
  • 2020-12-05 01:12

    Basing on @Andacious answer, I've made my own, a little more advanced and it seems to work.

    I've made method that modifies regex making it accepting promising answers.

    It replaces any literal char with "(?:OLD_LETTER|$)" so k becomes (?:k|$) looking for matching letter or end of input.

    It also looks for parts not to replace like {1,2} and leave them as they are.

    I'm sure it's not complete, but its very easy to add new rules of checking and main trick with any_sign or end of input seems to work in any case as end of string match and dont continue so basically we need to make such modification to main regex, that any literal char or group of chars will have alternative |$ and every syntax (that sometimes seems to have literal chars too) can't be destroyed.

    RegExp.prototype.promising = function(){
        var source = this.source;
        var regexps = {
            replaceCandidates : /(\{[\d,]\})|(\[[\w-]+\])|((?:\\\w))|([\w\s-])/g,   //parts of regexp that may be replaced
            dontReplace : /\{[\d,]\}/g,     //dont replace those
        }
    
        source =  source.replace(regexps.replaceCandidates, function(n){ 
            if ( regexps.dontReplace.test(n) ) return n;
            return "(?:" + n + "|$)";
        });
    
    
        source = source.replace(/\s/g, function(s){
            return "(?:" + s + "|$)";
        });
    
        return new RegExp(source);
    
    }
    

    Test on jsFiddle

    0 讨论(0)
  • 2020-12-05 01:13

    Not sure if there is a way to do this with regex without making an extremely complicated pattern. But if you are just checking against a string then you can do something like this:

    function matchPartialFromBeginning(pattern, value) {
        if(pattern.length == value.length)
            return pattern == value;
        if(pattern.length > value.length)
            return pattern.substr(0, value.length) == value;
        return false;
    }
    
    0 讨论(0)
  • 2020-12-05 01:16

    I think there is no automatic "Apply to every Pattern"-Solution. However you can manually derive an "optional" pattern out of your regex, and check against both patterns:

    var fullPattern = /^one (two)+ three/;
    var optPattern = /^o?n?e? ?(t?w?o?)+ ?t?h?r?e?e?$/;
    
    //verbal
    if (fullPattern.matches()){
       //matched
    } else {
      if (optPattern.matches()){
         //looks promising
      }else{
         //no match.
      }
    }
    

    You could also implement your own optionalizePattern() method, that converts Regex Pattern into such an Optional derivate. (Will be a difficult task to cover ALL possible patterns. Dunno, if possible at all.)

    0 讨论(0)
  • 2020-12-05 01:20

    Still not 100% sure what you are asking for, but you can also nest them, like this:

    var regexp = /^(one)+((\s+two)+((\s+three)+((\s+four)+)?)?)?$/;
    

    Matches:

    • one
    • one two two
    • one two two three
    • one two two three three four

    Does not match:

    • one three
    0 讨论(0)
提交回复
热议问题