简体   繁体   中英

Why does my negative lookbehind not work in Java?

I am attempting to use negative lookbehind to do some matching on strings that will get sent into the system from another system that ours talks to. I have searched for similar questions and I have not been able to solve this based on any previously posted questions.

This works as expected

Pattern pattern = Pattern.compile ("^(?<!SyCs-)([A-Za-z\\s\\d]+)$");
String s = "SyCs-a";

Assert.assertEquals (false, pattern.matcher (s).matches ());

Here's the problem: with the current regex, the following also returns false which makes sense because the '-' (dash) is not part of the allowed values ([A-Za-z\\s\\d]+) .

s = "TyCs-a";

Assert.assertEquals (false, pattern.matcher (s).matches ());

However, I need that to return true but when I add the dash to allowed values, the first String returns true as well.

No dash

Pattern pattern = Pattern.compile ("^(?<!SyCs-)([A-Za-z\\s\\d]+)$");
String s = "SyCs-a";

Assert.assertEquals (false, pattern.matcher (s).matches ());

s = "TyCs-a";

Assert.assertEquals (false, pattern.matcher (s).matches ());

With dash

Pattern pattern = Pattern.compile ("^(?<!SyCs-)([A-Za-z\\s\\d-]+)$");
String s = "SyCs-a";

Assert.assertEquals (true, pattern.matcher (s).matches ());

s = "TyCs-a";

Assert.assertEquals (true, pattern.matcher (s).matches ());

I've tried to make the + not greedy +? but that doesn't change the outcomes at all.

Any suggestions?

Here's the whole set of tests that I am using to verify the regex

@Test
public void testNegativeLookBehind () {
    Pattern pattern = Pattern.compile ("^(?<!SyCs-)([A-Za-z\\s\\d]+)$");
    String s = "SyCs-a";

    Assert.assertEquals (false, pattern.matcher (s).matches ());

    s = "SyCs-b";

    Assert.assertEquals (false, pattern.matcher (s).matches ());

    s = "SyCs-ab";

    Assert.assertEquals (false, pattern.matcher (s).matches ());

    s = "SyCs-ab1";

    Assert.assertEquals (false, pattern.matcher (s).matches ());

    s = "SyCs-abZ";

    Assert.assertEquals (false, pattern.matcher (s).matches ());

    s = "SyCs- abZ";

    Assert.assertEquals (false, pattern.matcher (s).matches ());

    s = "SyCs ab1";

    Assert.assertEquals (true, pattern.matcher (s).matches ());

    /*s = "TyCs-a";

    Assert.assertEquals (true, pattern.matcher (s).matches ());

    s = "SyCr-a";

    Assert.assertEquals (true, pattern.matcher (s).matches ());
    */
    s = "ab";

    Assert.assertEquals (true, pattern.matcher (s).matches ());

    s = "sab";

    Assert.assertEquals (true, pattern.matcher (s).matches ());

    s = "Csab";

    Assert.assertEquals (true, pattern.matcher (s).matches ());

    s = "yCsab";

    Assert.assertEquals (true, pattern.matcher (s).matches ());

    s = "SyCsab";

    Assert.assertEquals (true, pattern.matcher (s).matches ());
}

The (?<!SyCs-) is a negative lookbehind that fails the match if there is CyCs- immediately to the left of the current location. Since the current location is the start of string ( ^ ) the lookbehind always returns true and is just useless.

You need to use a lookahead here, not a lookbehind:

String pat = "^(?!SyCs-)[A-Za-z\\s\\d-]+$";
               ^^^^^^^^^

See the regex demo .

The ^(?!SyCs-) will check if the string starts with SyCs- and if it does, the match will be failed.

Note that if you use the pattern with .matches() method, you may omit ^ and $ anchors in the pattern as that method requires a full string match.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM