Julia
Julia

Reputation: 33

Split a string into a String[] of a specific size

Assuming my delimiter is ',' (comma), I'm looking for a function split that will guarantee that the returned String[] array is a certain size (no more, no less):

String[] split(String str, int limit);

split("hello", 2);               => ["hello", ""]
split("hello,", 2);              => ["hello", ""]
split(",hello", 2);              => ["", "hello"]
split("hello,world", 2);         => ["hello", "world"]
split("hello,world,goodbye", 2); => ["hello", "world,goodbye"]

See how the array size is always 2? I can get some of this behavior with Pattern.split, but not for every case... How can I do this?

Upvotes: 3

Views: 3001

Answers (7)

13Tazer31
13Tazer31

Reputation: 181

Simply getting the position of the delimiter and using substrings gets you there pretty easily:

public static String[] split(String str, int limit){

           String[] arr = new String[limit];

           for(int i = 0; i < limit-1; i++){
               int position = str.indexOf(',');
               int length = str.length();

               if(position == -1){
                   arr[i]= str.substring(0,length);
                   str = str.substring(length, length);
               }
               else{
                   arr[i] = str.substring(0, position);
                   str = str.substring(position+1, length);
               }
            }

            arr[limit-1] = str;

            return arr;
       }

Upvotes: 0

Wesley
Wesley

Reputation: 10852

It seems that it would be easy enough to pad out a new array with empty strings. Here is a utility method you could use to perform this split.

public static String[] split(Pattern pattern, CharSequence input, int limit) {
    // perform the split
    tokens = pattern.split(input, limit);

    int tokenCount = tokens.length();
    if (tokenCount == limit) {
        // if no padding is necessary, return the result of pattern.split
        return tokens;
    } else {
        // create a new array, copy tokens into array, pad with empty string
        String[] padded = Arrays.copyOf(tokens, limit);
        for (int i = tokenCount; i < limit; i++) {
            padded[i] = "";
        }
        return padded;
    }
}

Edit: Updated to shamelessly steal [Arrays.copyOf][1] from unholysampler's answer.

[1]: http://download.oracle.com/javase/6/docs/api/java/util/Arrays.html#copyOf(T[], int)

Upvotes: 0

unholysampler
unholysampler

Reputation: 17321

You can use Arrays.copyOf() to return a padded array. However, the padding will be null instead of an empty string.

String[] parts = Arrays.copyOf("hello,".split(",", 2), 2);
String[] parts1 = Arrays.copyOf(",hello".split(",", 2), 2);
String[] parts2 = Arrays.copyOf("hello,world".split(",", 2), 2);
String[] parts3 = Arrays.copyOf("hello,world,goodbye".split(",", 2), 2);
String[] parts4 = Arrays.copyOf("hello,".split(",", 2), 4); //null padding

Upvotes: 3

Machinarius
Machinarius

Reputation: 3731

You could do it with a loop that scans the string searching for the delimiter, then put whatever is not ahead of the delimiter in the array, then re-do it until it hits the top array size, that way it just return whatever was ahead as the last entry in the array:

public string[] mySplit(String Split, char Delimiter, int Top)
 {
  string[] returned = new string[Top];
  for(int i = 0; i < Top; i++){
    if(i==Top)
    {
     returned[i] = Split; return;
    }
    else
    {
     int compPlace = 0;
     char comp = Split.toCharArray()[compPlace];
     while(comp != Delimiter)
     {
      compPlace++;
      comp = Split.toCharArray()[compPlace];
      }
    returned[i] = Split.SubString(0,compPlace);
    Split = Split.SubString(compPlace);
    }
  }
  return returned;
}

Im sure youll have to tweak this as i have a little headache as of now :)

Upvotes: 0

Jules
Jules

Reputation: 1371

Well, if I understood you correctly you just want to stop splitting as soon as you have a reached the count provided via argument and move the remaining bit wholly into the last field, right? In addition, the limit-parameter should always ensure the fieldcount?

Wrap a method around the Pattern.split() method which just adds fields until your limit/threshold/minimum is reached.

for(i=0;i<limit;++i){
 //add empty fields to array until limit is reached
}

Upvotes: 0

Bozho
Bozho

Reputation: 597116

StringUtils.split(string, separator, max) is very close to what you need.

Then you can use ArrayUtils.addAll(result, emptyArray), where emptyArray is an array of size max - result.length.

The functionality you want is too specific, so I doubt there will be anything ready-to-use.

Upvotes: 1

cslavoie
cslavoie

Reputation: 216

I don’t remember all the syntax by heart, but your are looking at something like this:

Pattern p = new Pattern("[^,]+");
String[] strings = new String[limit];
int offset = 0;
int i = 0;
for (; i < limit; i++) {
    Match m = str.match(p, offset);
    if (m == null) break;
    offset += m.string.length + 1;
    strings[i] = m.string;
}
for (; i < limit; i++) {
    strings[i] = "";
}

Again, this is not valid Java

Upvotes: 0

Related Questions