2

My method readDataFromFile() can read text files like:

Bird    Golden Eagle    Eddie
Mammal  Tiger   Tommy
Mammal  Lion    Leo
Bird    Parrot  Polly
Reptile Cobra   Colin

The first column is the 'Type' of animal, second column is 'Species' and third is 'Name'.

Current Output:

Bird  Golden Eagle  < (Golden and Eagle count as different substrings).
    Mammal  Tiger Tommy
    Mammal  Lion Leo
    Bird  Parrot Polly
    Reptile  Cobra Colin
  • How would I use the useDelimiter method to make 'Golden Eagle' count as one species?

Current Code:

while(scanner.hasNextLine())
       {
       String type = scanner.next();
       String species = scanner.next();
       String name = scanner.next();
       System.out.println(type + "  " + species + " " + name);
       scanner.nextLine();

       addAnimal( new Animal(species, name, this) );
       }

2 Answers2

2

the first line has 'Golden Eagle' both separated by a tab

That is not correct.

The source of your question shows that the columns are all separated by a tab character (\t aka \u0009), but Golden and Eagle are separated by a space character (\u0020).

Do not read your file using Scanner. It is very slow and not the appropriate tool for parsing your file. Instead, use a BufferedReader and the readline() method, then split() the line into columns.

Demo

try (BufferedReader in = Files.newBufferedReader(Paths.get("animals.txt"))) {
    for (String line; (line = in.readLine()) != null; ) {
        String[] values = line.split("\t");
        for (String value : values)
            System.out.printf("%-15s", value);
        System.out.println();
    }
}

Output

Bird           Golden Eagle   Eddie          
Mammal         Tiger          Tommy          
Mammal         Lion           Leo            
Bird           Parrot         Polly          
Reptile        Cobra          Colin          

As you can see, the Golden Eagle text did not get split.

Andreas
  • 138,167
  • 8
  • 112
  • 195
  • I tested the code and it works fine, however what if i had no choice but to use the useDelimiter method, as part of a project? how would i go about this? – Melissa Stewart Jul 13 '18 at 21:44
  • @MelissaStewart `useDelimiter("\t|\\R")`, i.e. split tokens on tabs and [line breaks](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html#lineending). However, it's a very bad idea, because a single bad line with incorrect number of columns would corrupt the reading of the rest of the file. Read *lines*, then parsing each line separately, would allow ignoring a single bad line while continuing to parse the rest without issue. – Andreas Jul 13 '18 at 21:54
0

All you need is just set correct column delimeter as regexp to the Scanner. In the following example I have set \t as column delimeter with \n as new line delimeter:

public static List<Animal> readAnimals(InputStream in) {
    try (Scanner scan = new Scanner(Foo.class.getResourceAsStream("./animals.txt"))) {
        scan.useDelimiter("[\\t|\\n]");

        List<Animal> animals = new LinkedList<>();

        while (scan.hasNext()) {
            animals.add(new Animal(scan.next(), scan.next(), scan.next()));
        }

        return animals;
    }
}
oleg.cherednik
  • 12,764
  • 2
  • 17
  • 25