How to use split() inside a Java loop?

Asked

Viewed 63 times

2

Good evening, I have been learning Java for a while and wanted to know how I could read a text file that has one or two numbers in a maximum of 10 lines. Something like the files below:

16x9_resolutions.dat

640 360
1280 720
1366 768
1600 900
1920 1080

dat ranking.

10000
9000
8900
8878
8803
7995
7967
7960
7906
7845

I managed to do that:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;

public class Files{

    private String vet[] = new String[10];

    public void read(String path) throws IOException {
        BufferedReader buffRead = new BufferedReader(new FileReader(path));
        String line = "";
        int i = 0;
        while (true) {
            line = buffRead.readLine();
            if (line != null) {
                this.vet[i] = line;
                i++;
            } else{
            break;
            }
            if(i == 10){
               break;
            }
        }
        buffRead.close();
    }

    public int getResolutions(int pos){
        return Integer.parseInt(this.vet[pos]);
    }

}

In the above class I can read only one number per line. I want the read() method to be able to read the two types of files I showed, in the case of two numbers per line it should put the second number in the next vector position and jump to the next line.

I saw some posts on the internet talking about split() but none showed how to use it within a loop. I wanted something like:

while (true) {
    line = buffRead.readLine();
    if (line != null) {
        if(line.split() == "2 numeros separados por espaço"){
            this.vet[i] = line.split("primeiro numero");
            i++;
            this.vet[i] = line.split("segundo numero"); 
            i++;
        }else{
            this.vet[i] = line;
              i++;
        }
    }else{
       break;
    }
    if(i == 10){
        break;
    }
}

2 answers

1


First, you need to define the problem well:

  • is to read only the first 10 lines of the file?
  • or is to read the file until you find 10 numbers, regardless of the number of lines?
  • or some other option?

For now, let’s keep it simple and assume that or the file has 10 lines (one number per line), or has 5 lines (with two numbers per line). That is, there will always be 10 numbers.

So you can read the line, do the split to see if you have one or two numbers, and then store them in the array. Remembering that split breaks a string into several parts, using a separator, and returns an array with these parts.

Another point is that if you want to read numbers, then why store everything in an array of String? If the idea is to have numbers, then convert them to the appropriate type (which in this case seems to be int, since your examples only have integers).

So a simplified solution would be:

public class LerArquivo {

    // se quer ler números, use um array de int (não de String)
    private int[] numeros = new int[10];

    public void read(String path) {
        try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
            int pos = 0;
            String linha;
            // já leio a linha e verifico se é null
            leitura: while ((linha = reader.readLine()) != null) {
                String partes[] = linha.split(" "); // separa a linha por espaços
                // percorre as partes do resultado do split, e converte para números
                for (String parte : partes) {
                    // converte para número
                    this.numeros[pos] = Integer.parseInt(parte);
                    pos++; // incrementa a posição do array
                    if (pos == this.numeros.length) { // se já lotou o array, para de ler
                        break leitura; // interrompe o while
                    }
                }
            }
        } catch (IOException e) {
            // mostrar alguma mensagem de erro, etc
        }
    }
}

I used a block Try-with-Resources (available from Java 7), which ensures that the file is closed at the end (even in case of error), so you do not need to call close (and the way you did, with no guarantee that you’ll be called, in case there’s an error in the middle of the reading).

In the while, used a label (leitura:), which is something little used, but serves to give a "name" to the loop, so I can use the break leitura to indicate that I want to stop reading as soon as the number of numbers read is equal to the array size.

For every line read, I do the split using space as a separator. Thus, it "breaks" the line into several parts (separating by space), and for each part I convert to number and add in the array. This code assumes that they will always be numbers (because if they are not, parseInt throws an exception - you can add a try/catch and decide what to do if it goes wrong, for example).

This way, no matter how many numbers they have on each line. In fact, you may even have everyone on the same line that won’t make a difference, since I take each line, I separate by space and I see everything there, until I complete the amount of numbers.


Anyway, the "right" form depends on what you want to do exactly (the questions I put at the beginning). If you always want 10 numbers, it’s one thing. If you want validate that the lines always have one (or always two) numbers, the solution is another (would have to see if (partes.length == 2), for example, and would still have to validate whether they are even numbers, making the try/catch in the parseInt, etc.).

  • Thank you @hkotsubo. To make it clearer what I want to do is read values that can be int or String and that can be in pairs or alone on each line. They don’t necessarily need to be 10 but that’s the maximum amount. Your answer will already help me a lot.

  • One thing I didn’t understand was the for (String part : parts), which means this : ?

  • 1

    @kiss_cpp This is the Enhanced for, is just another way to go through an array. You could do for (int i = 0; i < partes.length; i++) { String parte = partes[i]; etc...}, which would be just the same (but when I just want to go through the array elements, no matter what the index, I usually use the Enhanced for, I find it more succinct and direct).

1

The String.split method takes a separator as a parameter. So you could do something like:

String[] campos = linha.split(" ");
for(String campo: campos) {
   // processa cada campo na linha
}

Another better option is to use the java.util.Scanner class like this:

Scanner sc = new Scanner(linha);
while(sc.hasNext()) {
   String campo = sc.next();
}

Scanner has other interesting methods that make it even easier, like Scanner.nextInt or Scanner.nextLong. It’s worth a look at the documentation: https://docs.oracle.com/javase/8/docs/api/java/util/Scanner.html

  • In the second example, . hasNext() returns true if you have another token. So if it is "10 20" in the input the result will be true?

  • sc.next() will not take the entire string?

  • 1

    @kiss_cpp Scanner breaks the orginal string into tokens ("10 20" creates two tokens: "10" and "20") Each Scanner.next() returns one token. The first time calling next() returns "10", the second returns "20".

Browser other questions tagged

You are not signed in. Login or sign up in order to post.