How to find first character after second dot java

Viewed 2921

Do you have any ideas how could I get first character after second dot of the string.

String str1 = "test.1231.asdasd.cccc.2.a.2";
String str2 = "aaa.1.22224.sadsada";

In first case I should get a and in second 2. I thought about dividing string with dot, and extracting first character of third element. But it seems to complicated and I think there is better way.

7 Answers

How about a regex for this?

Pattern p = Pattern.compile(".+?\\..+?\\.(\\w)");
Matcher m = p.matcher(str1);

if (m.find()) {
     System.out.println(m.group(1));
}

The regex says: find anything one or more times in a non-greedy fashion (.+?), that must be followed by a dot (\\.), than again anything one or more times in a non-greedy fashion (.+?) followed by a dot (\\.). After this was matched take the first word character in the first group ((\\w)).

Without using pattern, you can use subString and charAt method of String class to achieve this

// You can return String instead of char
public static char returnSecondChar(String strParam) {
    String tmpSubString = "";
   // First check if . exists in the string.
    if (strParam.indexOf('.') != -1) {
        // If yes, then extract substring starting from .+1  
        tmpSubString = strParam.substring(strParam.indexOf('.') + 1);
        System.out.println(tmpSubString);

       // Check if second '.' exists
        if (tmpSubString.indexOf('.') != -1) {

            // If it exists, get the char at index of . + 1  
            return tmpSubString.charAt(tmpSubString.indexOf('.') + 1);
        }
    }
    // If 2 '.' don't exists in the string, return '-'. Here you can return any thing
    return '-';
}

Usually regex will do an excellent work here. Still if you are looking for something more customizable then consider the following implementation:

private static int positionOf(String source, String target, int match) {
    if (match < 1) {
        return -1;
    }
    int result = -1;

    do {
        result = source.indexOf(target, result + target.length());
    } while (--match > 0 && result > 0);

    return result;
}

and then the test is done with:

String str1 = "test..1231.asdasd.cccc..2.a.2.";

System.out.println(positionOf(str1, ".", 3)); -> // prints 10
System.out.println(positionOf(str1, "c", 4)); -> // prints 21
System.out.println(positionOf(str1, "c", 5)); -> // prints -1
System.out.println(positionOf(str1, "..", 2)); -> // prints 22 -> just have in mind that the first symbol after the match is at position 22 + target.length() and also there might be none element with such index in the char array.

You could do it by splitting the String like this:

public static void main(String[] args) {
    String str1 = "test.1231.asdasd.cccc.2.a.2";
    String str2 = "aaa.1.22224.sadsada";

    System.out.println(getCharAfterSecondDot(str1));
    System.out.println(getCharAfterSecondDot(str2));
}

public static char getCharAfterSecondDot(String s) {
    String[] split = s.split("\\.");
    // TODO check if there are values in the array!
    return split[2].charAt(0);
}

I don't think it is too complicated, but using a directly matching regex is a very good (maybe better) solution anyway.

Please note that there might be the case of a String input with less than two dots, which would have to be handled (see TODO comment in the code).

You can use Java Stream API since Java 8:

String string = "test.1231.asdasd.cccc.2.a.2";
Arrays.stream(string.split("\\."))                 // Split by dot
      .skip(2).limit(1)                            // Skip 2 initial parts and limit to one
      .map(i -> i.substring(0, 1))                 // Map to the first character
      .findFirst().ifPresent(System.out::println); // Get first and print if exists

However, I recommend you to stick with Regex, which is safer and a correct way to do so:


Here is the Regex you need (demo available at Regex101):

.*?\..*?\.(.).*

Don't forget to escape the special characters with double-slash \\.

String[] array = new String[3];
array[0] = "test.1231.asdasd.cccc.2.a.2";
array[1] = "aaa.1.22224.sadsada";
array[2] = "test";

Pattern p = Pattern.compile(".*?\\..*?\\.(.).*");
for (int i=0; i<array.length; i++) {
    Matcher m = p.matcher(array[i]);
    if (m.find()) {
         System.out.println(m.group(1));
    }
}

This code prints two results on each line: a, 2 and an empty lane because on the 3rd String, there is no match.

A plain solution using String.indexOf:

public static Character getCharAfterSecondDot(String s) {
    int indexOfFirstDot = s.indexOf('.');
    if (!isValidIndex(indexOfFirstDot, s)) {
        return null;
    }

    int indexOfSecondDot = s.indexOf('.', indexOfFirstDot + 1);
    return isValidIndex(indexOfSecondDot, s) ?
            s.charAt(indexOfSecondDot + 1) :
            null;
}

protected static boolean isValidIndex(int index, String s) {
    return index != -1 && index < s.length() - 1;
}

Using indexOf(int ch) and indexOf(int ch, int fromIndex) needs only to examine all characters in worst case.

And a second version implementing the same logic using indexOf with Optional:

public static Character getCharAfterSecondDot(String s) {
    return Optional.of(s.indexOf('.'))
            .filter(i -> isValidIndex(i, s))
            .map(i -> s.indexOf('.', i + 1))
            .filter(i -> isValidIndex(i, s))
            .map(i -> s.charAt(i + 1))
            .orElse(null);
}

Just another approach, not a one-liner code but simple.

public class Test{
    public static void main (String[] args){
        for(String str:new String[]{"test.1231.asdasd.cccc.2.a.2","aaa.1.22224.sadsada"}){
            int n = 0;
            for(char c : str.toCharArray()){
                if(2 == n){
                    System.out.printf("found char: %c%n",c);
                    break;
                }
                if('.' == c){
                    n ++;   
                }
            }
        }
    }
}

found char: a
found char: 2

Related