1. Overview

In Java, there are many situations where we need to extract a substring that appears after the last occurrence of a specific pattern in a given String. This can be particularly useful when dealing with file paths, URLs, or any structured text.

In this quick tutorial, we’ll explore various methods to achieve this.

2. Introduction to the Problem

For example, let’s say we have the following String:

static final String INPUT1 = "a,   b,   c,   I need this value";

Given “,   ” (a comma followed by three spaces) as the pattern, we want to find the substring that appears immediately after the last occurrence of the pattern:

static final String EXPECTED1 = "I need this value";

Of course, there are some edge cases. For example, if the input String doesn’t contain the pattern at all or there is nothing after the last occurrence of the pattern, we’d like to have an empty String as the result:

static final String INPUT2 = "no-pattern-found";
static final String EXPECTED2 = "";
 
static final String INPUT3 = "a,   b,   c,   ";
static final String EXPECTED3 = "";

Next, let’s explore different ways to solve this problem.

3. Using String.lastIndexOf()

If we can find the last index of the pattern in the input String, we can extract the result using substring():

inputString.substring(lastIndexOfThePattern + pattern.length())

The String.lastIndexOf() method returns the last occurrence of a pattern. If the input doesn’t contain the pattern, it returns -1. So, let’s create a method to extract the required text and convert different scenarios:

String afterTheLastPatternBySubstring(String input, String pattern) {
    int index = input.lastIndexOf(pattern);
    return index >= 0 ? input.substring(index + pattern.length()) : "";
}

Next, let’s verify if the method works as expected:

String pattern = ",   ";
 
String result1 = afterTheLastPatternBySubstring(INPUT1, pattern);
assertEquals(EXPECTED1, result1);
 
String result2 = afterTheLastPatternBySubstring(INPUT2, pattern);
assertEquals(EXPECTED2, result2);
 
String result3 = afterTheLastPatternBySubstring(INPUT3, pattern);
assertEquals(EXPECTED3, result3);

The test passes. But, lastIndexOf() only supports literal text patterns. Next, let’s see other approaches that support regex patterns.

4. Using String.split()

Alternatively, we can use String.split() to obtain a String array by using a regex pattern as the separator. Then, the last array element will be the result. We’ll use the regex “, {3}” as the pattern.

Of course, this is only the basic idea. We need to consider a few adjustments to cover all edge cases.

For example, we should use a negative limit parameter when we split() the input. This is because the default limit (0) discards all trailing empty Strings. But a negative limit doesn’t. An example shows why this is required:

String pattern = ", {3}";
 
String[] array1 = INPUT3.split(pattern);
assertArrayEquals(new String[] { "a", "b", "c", }, array1);
 
String[] array2 = INPUT3.split(pattern, -1);
assertArrayEquals(new String[] { "a", "b", "c", "" }, array2);

Also, we should handle cases where the input doesn’t contain the pattern. In this case, the split() result has length <2:

String afterTheLastPatternBySplit(String input, String pattern) {
    String[] arr = input.split(pattern, -1);
    return (arr.length >= 2)? arr[arr.length - 1] : "";
}

Next, let’s test it:

String pattern = ", {3}";
 
String result1 = afterTheLastPatternBySplit(INPUT1, pattern);
assertEquals(EXPECTED1, result1);
 
String result2 = afterTheLastPatternBySplit(INPUT2, pattern);
assertEquals(EXPECTED2, result2);
 
String result3 = afterTheLastPatternBySplit(INPUT3, pattern);
assertEquals(EXPECTED3, result3);

As we can see, this approach produces the expected results for our three inputs.

5. Using String.replaceAll()

We can look at the problem from a different angle: If we remove from the beginning of the input until the last pattern occurrence, then the text left is what we want. In our example, the regex pattern will be “*.*, {3}*“.

Therefore, we can leverage String.replaceAll() to solve the problem:

String afterTheLastPatternByReplaceAll(String input, String pattern) {
    String result = input.replaceAll(pattern, "");
    return result.equals(input) ? "" : result;
}

In the example, we determine if the input contains the pattern by comparing the replaced result and the input.

Finally, let’s test this approach:

String pattern = ".*, {3}";
 
String result1 = afterTheLastPatternByReplaceAll(INPUT1, pattern);
assertEquals(EXPECTED1, result1);
 
String result2 = afterTheLastPatternByReplaceAll(INPUT2, pattern);
assertEquals(EXPECTED2, result2);
 
String result3 = afterTheLastPatternByReplaceAll(INPUT3, pattern);
assertEquals(EXPECTED3, result3);

It turns out the replaceAll() approach does the job.

6. Conclusion

In this article, we’ve explored different ways to find the substring after the last occurrence of a specific pattern. By understanding and applying these techniques, we can handle various text processing efficiently.

As always, the complete source code for the examples is available over on GitHub.