Exclusive Or in Regular Expression

后端 未结 13 1707
小鲜肉
小鲜肉 2020-12-05 10:06

Looking for a bit of regex help. I\'d like to design an expression that matches a string with \"foo\" OR \"bar\", but not both \"foo\" AND \"b

相关标签:
13条回答
  • 2020-12-05 10:34

    Using the word boundaries, you can get the single word...

    me@home ~  
    $ echo "Where is my bar of soap?" | egrep "\bfoo\b|\bbar\b"  
    Where is my bar of soap?  
    
    me@home ~  
    $ echo "What the foo happened here?" | egrep "\bfoo\b|\bbar\b"  
    What the foo happened here?  
    
    me@home ~  
    $ echo "Boy, that sure is foobar\!" | egrep "\bfoo\b|\bbar\b"  
    
    0 讨论(0)
  • 2020-12-05 10:35

    I know this is a late entry, but just to help others who may be looking:

    (/b(?:(?:(?!foo)bar)|(?:(?!bar)foo))/b)
    
    0 讨论(0)
  • 2020-12-05 10:37

    You can do this with a single regex but I suggest for the sake of readability you do something like...

    (/foo/ and not /bar/) || (/bar/ and not /foo/)
    
    0 讨论(0)
  • 2020-12-05 10:37

    If you want a true exclusive or, I'd just do that in code instead of in the regex. In Perl:

    /foo/ xor /bar/
    

    But your comment:

    Matches: "foo", "bar" nonmatches: "foofoo" "barfoo" "foobarfoo" "barbar" "barfoofoo"

    indicates that you're not really looking for exclusive or. You actually mean "Does /foo|bar/ match exactly once?"

    my $matches = 0;
    while (/foo|bar/g) {
      last if ++$matches > 1;
    }
    
    my $ok = ($matches == 1)
    
    0 讨论(0)
  • 2020-12-05 10:50

    This is what I use:

    /^(foo|bar){1}$/
    

    See: http://www.regular-expressions.info/quickstart.html under repetition

    0 讨论(0)
  • 2020-12-05 10:50

    You haven't specified behaviour regarding content other than "foo" and "bar" or repetitions of one in the absence of the other. e.g., Should "food" or "barbarian" match?

    Assuming that you want to match strings which contain only one instance of either "foo" or "bar", but not both and not multiple instances of the same one, without regard for anything else in the string (i.e., "food" matches and "barbarian" does not match), then you could use a regex which returns the number of matches found and only consider it successful if exactly one match is found. e.g., in Perl:

    @matches = ($value =~ /(foo|bar)/g)  # @matches now hold all foos or bars present
    if (scalar @matches == 1) {          # exactly one match found
      ...
    }
    

    If multiple repetitions of that same target are allowed (i.e., "barbarian" matches), then this same general approach could be used by then walking the list of matches to see whether the matches are all repeats of the same text or if the other option is also present.

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