Java negative indexOf (counting from the end [length()] )
Asked Answered
H

3

25

Is there any way in Java to found indexOf of a char starting from the end and having length() as a reference as other languages do?

   new String("abcd").reverseIndexOf("d"(,[4 or -0]))
or new String("abcd").indexOf("d",-0) // Should return a (-)1

...instead of the obvious

   new String("abcd").indexOf("d") - newString("abcd").length()     

Thanks!

Hygiene answered 18/5, 2012 at 15:35 Comment(1)
What would you expect to be returned for "dabcd".indexOf("d",-0)? (FYI, you don't need to declare a new String each time; you can call String methods directly on a String literal)Mahala
M
31

lastIndexOf(int ch) will start from the end and search backwards, returning the absolute index of the last occurrence. Then you could subtract that number from the length of the String and negate it, if that's what you really want.

You can also use lastIndexOf(int ch, int fromIndex)if you want to search backwards from a particular index.

To answer your question about what happens when you pass a negative number, you can dig into the source code for the String class. As it turns out, the indexOf implementation that is ultimately called resets a negative fromIndex value to zero:

static int indexOf(char[] source, int sourceOffset, int sourceCount,
                   char[] target, int targetOffset, int targetCount,
                   int fromIndex) {
if (fromIndex >= sourceCount) {
        return (targetCount == 0 ? sourceCount : -1);
}
    if (fromIndex < 0) {
        fromIndex = 0;
    }
    ...

Getting back to your second example:

"abcd".indexOf("d",-0)

...implementing a generic indexOf which accepts a negative index and returns the appropriate negative index (if there is one) is more complicated because Java does not distinguish between int 0 and int -0 (both will be represented as 0), and because String.indexOf normally returns -1 if the search string is not found. However, you can get close to what you want. Note there are a few caveats:

  1. String.indexOf normally returns -1 if the search string is not found. But because -1 is a valid index in our new implementation, we need to define a new contract. Integer.MIN_VALUE is now returned if the search string is not found.
  2. Because we cannot test for int -0, we cannot refer to the index of the last character as -0. For that reason, we use -1 to refer to the index of the last character, and continue counting backwards from there.
  3. For consistency with item 2, negative return values also start counting down starting with -1 as the index of the last character.

The code could be simplified, but I've intentionally made it verbose so you can easily step through it in a debugger.

package com.example.string;

public class StringExample {

    public static int indexOf(String str, String search, int fromIndex) {
        if (fromIndex < 0) {
            fromIndex = str.length() + fromIndex; // convert the negative index to a positive index, treating the negative index -1 as the index of the last character
            int index = str.lastIndexOf(search, fromIndex);
            if (index == -1) {
                index = Integer.MIN_VALUE; // String.indexOf normally returns -1 if the character is not found, but we need to define a new contract since -1 is a valid index for our new implementation
            }
            else {
                index = -(str.length() - index); // convert the result to a negative index--again, -1 is the index of the last character 
            }
            return index;
        }
        else {
            return str.indexOf(str, fromIndex);
        }
    }

    public static void main(String[] args) {
        System.out.println(indexOf("abcd", "d", -1)); // returns -1
        System.out.println(indexOf("adbcd", "d", -2)); // returns -4
    }
}
Mahala answered 18/5, 2012 at 21:49 Comment(0)
N
5

Just use String.lastIndexOf() method:

String s = "abcd";
int rindex = s.lastIndexof('d');
System.out.println(rindex); // print 0
Newsome answered 18/5, 2012 at 15:41 Comment(1)
Thank you, I looked into the API but I thought that maybe I was missing something and the JavaDoc does not explain how behaves with negative numbersHygiene
N
1

You could easily reverse the string by the way :

String s="abcd";
StringBuilder reverseS = new StringBuilder(s).reverse();
System.out.println(reverseS.indexOf("d")); //print 0
System.out.println(reverseS.indexOf("a")); //print 3
System.out.println(reverseS.indexOf("d",1)); //print -1
Nephoscope answered 18/5, 2012 at 16:8 Comment(6)
Great approach! The only problem is you would loose the parsing of length because in my example if you could make a .reverseIndex('.',5) you would get a -1 for any string.length()<5. But thats a minor thingHygiene
I don't understand what you mean by "loose the parsing of length". I understand that your method return -1 when you use an index out of bound in your reverse method but the problem can't append in my method. What do you want my method to do?Nephoscope
I mean the good thing about a reverseIndex would be that you could take always an absolute position backwards, so if it does not exist I get a -1, but here it never happens. I cannot say "I want the letter 3 places before the char 14 as long as it exists". But I like your way and I think it´s the ultimate resort.Hygiene
Seems to me like a big waste, to create a StringBuffer instead of simple subtraction.Strangulation
@user1352530 If you use ew StringBuffer(s).reverse().indexOf("d",1) it will return -1. I think you can add the precision you want here.Nephoscope
@BinyaminSharet You're right, it's not the cheaper solution for memory usage. I put this answer for the logic ; instead of use reversedIndex, use reverse string. But also with my method you can create the reversed string one time whereas you have to make the substraction everytime you used the "reverseIndex" method. I don't know if perfomance are really affected. Also I think my method is maybe more readable.Nephoscope

© 2022 - 2024 — McMap. All rights reserved.