How to match forward slashes or periods at end of String but Not Capture Using Java Regular Expression

Viewed 198

I am having problems understand how regular expression can match text but not include the matched text that is found. Perhaps I need to be working with groups which I'm not doing because I usually see the term non-capturing groups being used.

The goal is say I have ticket in a log file as follows:

TICKET/A/ADMIN/05MAR2020// to return only A/ADMIN/05MAR2020
or if
TICKET/A/ENGINEERING/05MAR2020. to return only A/ENGINEERING/05MAR02020
where the "//" or "." has been removed

Lastly to ignore lines like:

TICKET HAS BEEN COMPLETED

using regex = "(?<=^TICKET\\s{0,2}/).*(?://|\\.)?

So telling parser look for TICKET at start of string followed by a forward slash, but don't return TICKET. And look for either a double forward slash "//" or "." a period at the end of string but make this optional.

My Java 1.8.x code follows:

// used in the import statement: import java.util.regex.Matcher;
//                               import java.util.regex.Pattern;
private static void testRegex() {
    String ticket1 = "TICKET/A/ITSUPPORT/05MAR2020//";
    String ticket2 = "TICKET /B/ADMIN/06MAR2020.";
    String ticket3 = "TICKET/C/GENERAL/07MAR2020";

    //https://www.regular-expressions.info/brackets.html

    String regex = "(?<=^TICKET\\s{0,2}/).*(?://|\\.)?";
    Pattern pat = Pattern.compile(regex);
    Matcher mat = pat.matcher(ticket1);

    if (mat.find()) {
        String myticket = ticket1.substring(mat.start(), mat.end());
        System.out.println(myticket+ ", Expect 'A/ITSUPPORT/05MAR2020'");
    }
    mat = pat.matcher(ticket2);
    if (mat.find()) {
        String myticket = ticket2.substring(mat.start(), mat.end());
        System.out.println(myticket+", Expect 'B/ADMIN/06MAR2020'");
    }

    mat = pat.matcher(ticket3);
    if (mat.find()) {
        String myticket = ticket3.substring(mat.start(), mat.end());
        System.out.println(myticket+", Expect 'C/GENERAL/07MAR2020'");
    }
    regex = "(//|\\.)";
    pat = Pattern.compile(regex);
    mat = pat.matcher(ticket1);
    if (mat.find()) {
        String myticket = ticket1.substring(mat.start(), mat.end());
        System.out.println(myticket+", "+mat.start() + ", " + mat.end() + ", " + mat.groupCount());
    }
}

My actual results follow:

A/ITSUPPORT/05MAR2020//, Expect 'A/ITSUPPORT/05MAR2020
B/ADMIN/06MAR2020., Expect 'B/ADMIN/06MAR2020
C/GENERAL/07MAR2020, Expect 'C/GENERAL/07MAR2020


//, 28, 30, 1

Any suggestion would be appreciate. Please note, been learning from StackOverflow long-time but first entry, hope question is asked appropriately. Thank you.

1 Answers

You could use a positive lookahead at the end of the pattern instead of a match.

The lookahead asserts what is at the end of the string is an optional // or .

As the dot and the double forward slash are optional, you have to make the .*? non greedy.

(?<=^TICKET\s{0,2}/).*?(?=(?://|\.)?$)

In parts

  • (?<= Positive lookbehind, assert what is on the left is
    • ^ Start of the string
    • TICKET\s{0,2}/ Match TICKET and 0-2 whitespace chars followed by /
  • ) Close lookbehind
  • .*? Match any char except a newline 0+ times, as least as possible (non greedy)
  • (?= Positive lookahead, assert what is on the the right is
    • (?: Non capture group for the alternation | because both can be followed by $
      • // Match 2 forward slashes
      • | Or
      • \. Match a dot
    • )? Close the non capture group and make it optional
    • $ Assert the end of the string
  • ) Close the positive lookahead

In Java

String regex = "(?<=^TICKET\\s{0,2}/).*?(?=(?://|\\.)?$)";

Regex demo 1 | Java demo

1. The regex demo has Javascript selected for the demo only


Output of the updated pattern with your code:

A/ITSUPPORT/05MAR2020, Expect 'A/ITSUPPORT/05MAR2020'
B/ADMIN/06MAR2020, Expect 'B/ADMIN/06MAR2020'
C/GENERAL/07MAR2020, Expect 'C/GENERAL/07MAR2020'
//, 28, 30, 1
Related