Is there a Java equivalent to Python's Easy String Splicing?

Question:

Ok, what I want to know is is there a way with Java to do what Python can do below…

string_sample = "hello world"

string_sample[:-1]
>>> "hello world"

string_sample[-1]
>>> "d"

string_sample[3]
>>> "l"

Because it seems to me that Java make you work for the same result (I’m particularly getting at having to use 2 numbers every time and the lack of a -1 to indicate last character)

String string_sample = "hello world";

string_sample.substring(0,string_sample.length()-1);
>>> "hello world"

string_sample.substringstring_sample.length()];
>>> "d"

string_sample.(3,4);
>>> "l"

I haven’t gotten on to arrays/lists yet in Java so really hoping Java has something easier than this

Edit: Ammended ‘i’ to ‘l’ for string_sample[3]. Well spotted Maroun!

Asked By: rory

||

Answers:

I think there is no such Java string library providing exactly the same thing provided by python. Probably the best you can do is to build a new class which provides the functions you need. Since the String in java is a final class which you cannot have a class extend from it, you need to use composition. For example:

public class PythonString {
  protected String value;
  public PythonString(String str) {
    value = new String(str);
  }

  public char charAt(int index) {
    if (index < 0) {
      return value.charAt(value.length() + index);
    }
    return value.charAt(index);
  }

  ....

}

Another alternative is to create a static string library.

Answered By: keelar

Sorry, Java’s substring is not as flexible as Python’s slice notation.

In particular:

  • You can give it just a begin, or a begin and end, but not just an end. (Also, no step, but you don’t miss that as much.)
  • Negative indices are an error, not a count from the end.

You can see the docs here.

However, it’s not hard at all to write this on your own:

public String slice_start(String s, int startIndex) {
    if (startIndex < 0) startIndex = s.length() + startIndex;
    return s.substring(startIndex);
}

public String slice_end(String s, int endIndex) {
    if (endIndex < 0) endIndex = s.length() + endIndex;
    return s.substring(0, endIndex);
}

public String slice_range(String s, int startIndex, int endIndex) {
    if (startIndex < 0) startIndex = s.length() + startIndex;
    if (endIndex < 0) endIndex = s.length() + endIndex;
    return s.substring(startIndex, endIndex);
}

Put those as static methods of some utility class.

Obviously this isn’t exactly the same as Python, but it probably handles all the cases you want, and very simple. If you want to handle other edge cases (including things like step and passing slices around and so on), you can add whatever additional code you want; none of it is particularly tricky.


Other sequences are basically the same, but there you’re going to want subSequence instead of substring. (You can also use subSequence on strings, because a String is a CharSequence.)

Arrays aren’t actually a type of sequence at all; you’ll need to write code that explicitly creates a new Array and copies the sub-array. But it’s still not much more complicated.


Note that you may want to look for a library that’s already done this for you. There are at least three linked in other answers on this page, which should make your search easy. 🙂 (You may still want to do it for yourself once, just to understand how those libraries work—but for production code, I’d rather use a library where someone else has figured out and tested all of the edge cases than to reimplement the wheel and deal with them as they get caught in unit tests, or errors in the field…)

Answered By: abarnert

Simple answer, no there isn’t. Strings are immutable in both languages. Strings are internally stored as character arrays so using substring and using the brackets in Python are essentially doing the same thing. Java doesn’t support operator overloading so there’s no way to give that functionality to the language. Using substring isn’t so bad. You shouldn’t have to do it too often. You could always write helper functions if you’re doing it very often to simplify your usage.

Answered By: minhaz1

You could easily write such a method, remember that negative indices are subtracted from the length of the string to get the correct index.

public String slice(String s, int start) {
   if (start < 0) start = s.length() + start; 

   return s.substring(start);
}
Answered By: Hunter McMillen

use substring:

class Main
{
  public static void main (String[] args) throws java.lang.Exception
  {
     String s = new String("hello world");
     System.out.println(s.substring(0, s.length()));
     System.out.println(s.substring(s.length() - 1, s.length()));
     System.out.println(s.substring(3, 4));
  }
}

or charAt:

System.out.println(s.charAt(s.length() - 1));
System.out.println(s.charAt(3));

Java is not python so negative index should be avoided to maintain constancy. However, you could make a simple conversion function.

Answered By: andre

Apache commons-lang has some support for this in StringUtils:

Gets a substring from the specified String avoiding exceptions.

A negative start position can be used to start n characters from the end of the String

You’ll still have to use an explicit start index though.

Answered By: millimoose

I have a created a simple library for that, called JavaSlice, which gives a uniform way to access slices of String, List or arrays in Java, in a similar manner as Python.

So your examples would be simply written as this:

    String sample = "hello world";

    System.out.println(slice(sample, 0, -1)); // "hello worl"
    System.out.println(slice(sample, -1)); // 'd'
    System.out.println(slice(sample, 3)); // 'l'
Answered By: Cyrille Ka

Java Boon Slice Notation allows all of that and with Strings, Lists, Sets, Maps, etc.

Many languages have slice notation (Ruby, Groovy and Python). Boon adds this to Java.

Boon has three slc operators: slc, slc (start only), and slcEnd.

With Boon you can slice strings, arrays (primitive and generic), lists, sets, tree sets, tree map’s and more.

Slice notations – a gentle introduction

The boon slice operators works like Python/Ruby slice notation:

Ruby slice notation

 arr = [1, 2, 3, 4, 5, 6]
 arr[2]    #=> 3
 arr[-3]   #=> 4
 arr[2, 3] #=> [3, 4, 5]
 arr[1..4] #=> [2, 3, 4, 5]

Python slice notation

string = "foo bar" 
string [0:3]  #'foo'
string [-3:7] #'bar'

What follows is derived from an excellent write up on Python’s slice notation:

The basics of slice notations are as follows:

Python Slice Notation

     a[ index ]       # index of item
     a[ start : end ] # items start through end-1
     a[ start : ]     # items start through the rest of the array
     a[ : end ]       # items from the beginning through end-1
     a[ : ]           # a copy of the whole array

Java Slice Notation using Boon:

      idx( index )         // index of item
      slc( a, start, end ) // items start through end-1
      slc( a, start )      // items start through the rest of the array
      slcEnd( a, end )     // items from the beginning through end-1
      copy( a )            // a copy of the whole array

slc stands for slice
idx stands for index
slcEnd stands for end slice.
copy stands for well, err, um copy of course

The key point to remember is that the end value represents the first value that is not in the selected slice. So, the difference between end and start is the number of elements selected.
The other feature is that start or end may be a negative number, which means it counts from the end of the array instead of the beginning.

Thus:

Python slice notation with negative index

         a[ -1 ]    # last item in the array
         a[ -2: ]   # last two items in the array
         a[ :-2 ]   # everything except the last two items

Java negative index

         idx   ( a, -1)     // last item in the array
         slc   ( -2 )       // last two items in the array
         slcEnd( -2 )       // everything except the last two items

Python and Boon are kind to the programmer if there are fewer items than you ask for: Python does not allow you to go out of bounds, if you do it returns at worse an empty list. Boon follows this tradition, but provides an option to get exception for out of bounds (described later). In Python and Boon, if you go to far, you get the length, if you try to go under 0 you get 0 (under 0 after calculation). Conversely, Ruby gives you a null pointer (Nil). Boon copies Python style as one of the goals of Boon is to avoid ever returning null (you get an exception, Option). (Boon has second operator called zlc which throws an out of bounds index exception, but most people should use slc.)

For example, if you ask for slcEnd(a, -2) (a[:-2]) and a only contains one element, you get an empty list instead of an error. Sometimes you would prefer the error, and with Boon you have that option.

More slicing

Here are some basic Java types, list, array, veggies, primitive char array, and a primitive byte array.

Declare variables to work with in Boon

//Boon works with lists, arrays, sets, maps, sorted maps, etc.
List<String> fruitList;
String [] fruitArray;
Set<String> veggiesSet;
char [] letters;
byte [] bytes;
NavigableMap <Integer, String> favoritesMap;
Map<String, Integer> map;

//In Java a TreeMap is a SortedMap and a NavigableMap by the way.

Boon comes with helper methods that allow you to easily create lists, sets, maps, concurrent maps, sorted maps, sorted sets, etc. The helper methods are safeList, list, set, sortedSet, safeSet, safeSortedSet, etc. The idea is to make Java feel more like list and maps are built in types.

Initialize set, list, array of strings, array of chars, and array of bytes

veggiesSet  =  set( "salad", "broccoli", "spinach");
fruitList   =  list( "apple", "oranges", "pineapple");
fruitArray  =  array( "apple", "oranges", "pineapple");
letters     =  array( 'a', 'b', 'c');
bytes       =  array( new byte[]{0x1, 0x2, 0x3, 0x4});

There are even methods to create maps and sorted maps called map, sortedMap, safeMap (concurrent) and sortedSafeMap(concurrent). These were mainly created because Java does not have literals for lists, maps, etc.

Java: Use map operator to generate a SortedMap and a Map

 favoritesMap = sortedMap(
      2, "pineapple",
      1, "oranges",
      3, "apple"
 );


 map =    map (
    "pineapple",  2,
    "oranges",    1,
    "apple",      3
 );

You can index maps, lists, arrays, etc. using the idx operator.

Java: Using the Boon Java idx operator to get the values at an index

 //Using idx to access a value.

 assert idx( veggiesSet, "b").equals("broccoli");

 assert idx( fruitList, 1 ).equals("oranges");

 assert idx( fruitArray, 1 ).equals("oranges");

 assert idx( letters, 1 ) == 'b';

 assert idx( bytes, 1 )      == 0x2;

 assert idx( favoritesMap, 2 ).equals("pineapple");

 assert idx( map, "pineapple" )  == 2;

The idx operators works with negative indexes as well.

Java: Using idx operator with negative values

         //Negative indexes

          assert idx( fruitList, -2 ).equals("oranges");

          assert idx( fruitArray, -2 ).equals("oranges");

          assert idx( letters, -2 ) == 'b';

          assert idx( bytes, -3 )   == 0x2;

Ruby, Groovy and Python have this feature. Now you can use this in Java as well! The Java version (Boon) works with primitive arrays so you get no auto-boxing.

Something that Ruby and Python don’t have is slice notation for SortedSets and SortedMaps.
You can use slice notation to search sorted maps and sorted sets in Java

Slice notations works with sorted maps and sorted sets.

Here is an example that puts a few concepts together.

          set = sortedSet("apple", "kiwi", "oranges", "pears", "pineapple")

          slcEnd( set, "o" )      //returns ("oranges", "pears", "pineapple")
          slc( set, "ap", "o" )   //returns ("apple", "kiwi"),
          slc( set, "o" )         //returns ("apple", "kiwi")

You are really doing with slicing of sorted maps and sorted sets is a between query of sorts.
What item comes after “pi”?

          after(set, "pi") //pineapple

And before pineapple?

          before(set, "pi")

Ok, let go through it step by step….

  NavigableSet<String> set =
          sortedSet("apple", "kiwi", "oranges", "pears", "pineapple");

  assertEquals(

          "oranges", idx(set, "ora")

  );

Remember: TreeSet implements NavigableSet and SortedSet.

This was derived from my blog….

http://rick-hightower.blogspot.com/2013/10/java-slice-notation-to-split-up-strings.html

More examples are there.

I derived some of the verbiage from this discussion on Python slicing.

Explain Python's slice notation

Here is the Boon project link:

https://github.com/RichardHightower/boon

Now let’s continue to SLICE!

We can look up the first fruit in the set that starts with ‘o’ using:

idx(set, "o")

Here is is with the set of fruit we created earlier (set is a TreeSet with “apple”, “kiwi”,
“oranges”, “pears”, “pineapple” in it).

      assertEquals(

          "oranges", idx(set, "o")

      );

We found oranges!

Here it is again but this time we are searching for fruits that start with “p”, i.e., idx(set, “p”).

      assertEquals(
          "pears",
          idx(set, "p")
      );

Yeah! We found pears!

How about fruits that start with a “pi” like “pineapple” – idx(set, “pi”)

  assertEquals(
          "pineapple",
          idx(set, "pi")
  );

You could also ask for the item that is after another item. What is after “pi”?
after(set, “pi”)

  assertEquals(

          "pineapple",
          after(set, "pi")

  );

The “pineapple” is after the item “pi”. after and idx are the same by the way. So why did I add an after? So I can have a before!!! 🙂
What if you want to know what is before “pi”?

before(set, “pi”)

  assertEquals(

          "pears",
          before(set, "pi")

  );

How about all fruits that are between “ap” and “o”? As I promised there is slice notation!

slc(set, “ap”, “o”)

  assertEquals(

          sortedSet("apple", "kiwi"),
          slc(set, "ap", "o")

  );

How about all fruits after “o”?

slc(set, “o”)

  assertEquals(

          sortedSet("apple", "kiwi"),
          slc(set, "o")

  );

So all fruits after “o” is “apple” and “kiwi”.

How about all fruits up to “o”? (slcEnd read it as I am slicing off the end.)

slcEnd(set, “o”)

  assertEquals(

          sortedSet("oranges", "pears", "pineapple"),
          slcEnd(set, "o")
  );

So all fruits up to and including “o” are “oranges”, “pears” and “pineapple”.

Safe slicing for list like things

These operators throw an exception if the index is out of bounds:

Java Slice Notation as follows using Boon:

      ix( index )         // index of item
      zlc( a, start, end ) // items start through end-1
      zlc( a, start )      // items start through the rest of the array
      zlcEnd( a, end )     // items from the beginning through end-1

zlc stands for zero tolerance slice
ix stands for zero tolerance index
zlcEnd stands for zero tolerance end slice.
copy stands for well, err, um copy of course

Boys and girls… remember to always perform safe slicing with objects you don’t know.

Works with Primitives too so no auto-boxing

Indexing primitives

 byte[] letters =
      array((byte)'a', (byte)'b', (byte)'c', (byte)'d');

 assertEquals(
      'a',
      idx(letters, 0)
 );


 assertEquals(
      'd',
      idx(letters, -1)
 );


 assertEquals(
      'd',
      idx(letters, letters.length - 1)
 );

 idx(letters, 1, (byte)'z');

 assertEquals(
      (byte)'z',
      idx(letters, 1)
 );

The method len and idx are universal operators and they work on lists, arrays, sets, maps, etc.

len give me the length of an array-like, list-like, map-like, thing.
idx give me the item at the location of an “index” in the array-like, list-like, map-like, thing.

HOME MC String Slice!

Here are some examples of Boon Java String Slicing

  String letters = "abcd";

  boolean worked = true;

  worked &=

          idx(letters, 0)  == 'a'
                  || die("0 index is equal to a");



  worked &=

          idx(letters, -1)  == 'd'
                  || die("-1 index is equal to a");

Another way to express idx(letters, -1) == ‘d’ is idx(letters, letters.length() – 1) == ‘d’!
I prefer the shorter way!

  worked &=

          idx(letters, letters.length() - 1) == 'd'
                   || die("another way to express what the -1 means");


  //We can modify too
  letters = idx(letters, 1, 'z');

  worked &=

          idx(letters, 1) == 'z'
                  || die("Set the 1 index of letters to 'z'");


  worked &= (
          in('a', letters) &&
          in('z', letters)
  ) || die("'z' is in letters and 'a' is in letters");

Slice Slice Baby!

  letters = "abcd";

  worked &=
          slc(letters, 0, 2).equals("ab")
              || die("index 0 through index 2 is equal to 'ab'");



  worked &=
          slc(letters, 1, -1).equals("bc")
                  || die("index 1 through index (length -1) is equal to 'bc'");


  worked &=
          slcEnd(letters, -2).equals("ab")
                  || die("Slice of the end of the string!");


  worked &=
          slcEnd(letters, 2).equals("ab")
                  || die("Vanilla Slice Slice baby!");

Rolling in my 5.0, got my rag top down so my hair can blow! Slice Slice Baby!!!

Answered By: RickHigh
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.