tags:

views:

113

answers:

8

This is a common task I'm facing: splitting a space separated list into a head element and an array containing the tail elements. For example, given this string:

the quick brown fox

We want:

"the"
["quick","brown","fox"]

.. in two different variables. The first variable should be a string, and the second an array. I'm looking for an elegant way to do this (preferably in Java).

A: 

Use StringTokenizer and a while loop to step through each element. Inside the loop, you can get the first element and put the rest into an array.

Edit: Oh, I guess StringTokenizer is a "legacy" class (though it still works).

The recommended way is now to use String.split(). That will give you a String[] containing your elements. From there it should be trivial to get the first element and also create an array out of the remaining elements.

Jeff
Hmm. Problem is, you can't really know how many tokens there are other than calling nextToken until there's no more tokens. So you can't really allocate an array and put it in?
Wram
That's correct, since arrays are immutable, you'd have to use System.arraycopy. But it's a moot point since it'd be better to use split() as others described.
Jeff
A: 
str= "the quick brown fox"
  pqr = str.split(" ")
Salil
+7  A: 

For certain values of elegant:

String input = "The quick brown fox";
String[] elements = input.split(" ");
String first = elements[0];
String[] trailing = Arrays.copyOfRange(elements,1,elements.length);

I can't think of a way to do it with less code...

Alterscape
`Arrays.copyOfRange()` - wow, thanks, I learn something new every day from other peoples' answers!
Carl Smotricz
If the user intends to "pop" one item out of the String[] array, then Lists would be better, right? (I'm thinking after they get the above solution working, they might realize that).
Warren P
+1  A: 

Well, you get most of what you want with

String[] pieces = "how now brown cow".split("\\s") 

or so. Your result will be an array of Strings.

If you really, really want the first item separate from the rest, you can then do something like:

String head = pieces[0];
String[] tail = new String[pieces.length - 1];
System.arraycopy(pieces, 1, tail, 0, tail.length);

...done.

Carl Smotricz
+1  A: 

You could make use of String#split() taking a limit as 2nd argument.

String text = "the quick brown fox";
String[] parts = text.split(" ", 2);
String headPart = parts[0];
String[] bodyParts = parts[1].split(" ");

System.out.println(headPart); // the
System.out.println(Arrays.toString(bodyParts)); // [quick, brown, fox]
BalusC
+3  A: 

The most elegant is probably to use String.split to get a String[], then using Arrays.asList to turn it into a List<String>. If you really need a separate list minus the head, just use List.subList.

    String text = "the quick brown fox";
    List<String> tokens = Arrays.asList(text.split("\\s+"));

    String head = tokens.get(0);
    List<String> body = tokens.subList(1, tokens.size());

    System.out.println(head); // "the"
    System.out.println(body); // "[quick, brown, fox]"

    System.out.println(body.contains("fox")); // "true"
    System.out.println(body.contains("chicken")); // "false"

Using a List allows you to take advantage of the rich features provided by Java Collections Framework.

See also

polygenelubricants
Even though this is slightly more code than my `Arrays.copyOfRange()` solution, I think yours probably wins on elegance, unless the asker needs blazing speed or is in a very low-memory environment (in which case why on earth is he/she using Java?)
Alterscape
+1  A: 
package playground;

import junit.framework.TestCase;

public class TokenizerTest extends TestCase {

    public void testTokenize() throws Exception {
        String s = "the quick brown fox";
        MyThing t = new MyThing(s);
        assertEquals("the", t.head);
        String[] rest = {"quick", "brown", "fox"};
        assertEqualArrays(rest, t.rest);
    }

    private static void assertEqualArrays(String[] a, String[] b) {
        assertEquals(a.length, b.length);
        for (int i = 0; i < a.length; i++) 
            assertEquals(a[i], b[i]);
    }

    private static class MyThing {
        private final String head;
        private final String[] rest;

        public MyThing(String s) {
            String[] array = s.split(" ");
            head = array[0];
            rest = new String[array.length - 1];
            System.arraycopy(array, 1, rest, 0, array.length - 1);
        }

    }
}
Carl Manaster
+1  A: 
public static void main(String[] args) {
        String s = "the quick brown fox";
        int indexOf = s.indexOf(' ');
        String head = s.substring(0, indexOf);
        String[] tail = s.substring(indexOf + 1).split(" +");
        System.out.println(head + " : " + Arrays.asList(tail));
    }

Would have been much easier in Haskell :)

Thorbjørn Ravn Andersen