Преобразование .txt-файла с удвоениями в ArrayList

#java #arraylist

#java #arraylist

Вопрос:

У меня есть .txt файл с таким содержимым: "17.23;12.1;20.34;88.23523;" . Я хочу прочитать этот файл как удвоенный в ArrayList . И в конечном итоге распечатайте ArrayList (и в конечном итоге распечатайте min. и макс., но я не думаю, что это будет проблемой после решения этого).

Но я получаю только вывод «[ ]».

Что я делаю не так? Я боролся с этим более 15 часов, просматривал здесь, youtube, учебные пособия…

Мой код:

 public static void main(String[] args) throws IOException {
      File myFile = new File("text.txt");
      Scanner scan = new Scanner(myFile);

      ArrayList<Double> aList = new ArrayList<>();
      
      while (scan.hasNextDouble()) {  
          double nextInput = scan.nextDouble();
          if (nextInput != 0) {
              break;  
          }  
        
          aList.add(nextInput);
      }

      System.out.println(alist);
}
  

Комментарии:

1. if (nextInput != 0) break; зачем вам нужна эта строка? Из-за них ваш код никогда не должен добавлять что-либо в ArrayList с учетом вашего ввода

2. Поскольку в вашем файле есть числа, разделенные точкой с запятой, вы не сможете прочитать их с помощью scan.hasNextDouble() по умолчанию. Однако существует так много способов сделать это, например, прочитать строку как строку и обработать каждое число из нее после разделения его на точки с запятой. Другой способ — переопределить разделитель по умолчанию и т. Д.

Ответ №1:

Вы должны настроить свой сканер так, чтобы он принимал:

  1. ; в качестве разделителя
  2. , в качестве десятичного разделителя

Рабочий код:

 File myFile = new File("input.txt");

// Swedish locale uses ',' as a decimal separator
Scanner scan = new Scanner(myFile).useDelimiter(";").useLocale(Locale.forLanguageTag("sv-SE"));

ArrayList<Double> aList = new ArrayList<>();

while (scan.hasNextDouble()) {
    double nextInput = scan.nextDouble();
    aList.add(nextInput);
}

System.out.println(aList);
  

С выводом [17.23, 12.1, 20.34, 88.23523]

Комментарии:

1. Отличный ответ, 1 от меня, хотя я считаю, что слово «Uppgift» в имени файла — шведское, и Швеция , также используется, поэтому изменение Locale.FRENCH на Locale.forLanguageTag("sv-SE") , вероятно, будет более точным для вопроса. Тот же результат, конечно.

2. Да, конечно, французский — это просто пример (язык «ru-RU» тоже работает)

Ответ №2:

Scanner работает путем разделения входных данных на токены, где токены разделены пробелами (по умолчанию). Поскольку в тексте нет пробелов, первым / единственным маркером является весь текст, и поскольку этот текст не является допустимым double значением, hasNextDouble() возвращает false .

Два способа исправить это:

  • Измените разделитель токенов на ; :

     scan.useDelimiter(";");
      
  • Прочитайте файл с BufferedReader помощью и используйте split() :

     String filename = "text.txt";
    try (BufferedReader in = Files.newBufferedReader(Paths.get(filename))) {
        for (String line; (line = in.readLine()) != null; ) {
            String[] tokens = line.split(";");
            // code here
        }
    }
      

Теперь это приведет к следующим токенам: 17,23 , 12,1 , 20,34 , 88,23523 .

К сожалению, ни одно из этих double значений не является допустимым, поскольку они используют форматирование, зависящее от локали, то есть десятичная точка — это a , , а не a . .

Это означает, что если вы продолжали использовать Scanner , вы не можете использовать hasNextDouble() и nextDouble() , и если вы изменили на use split() , вы не можете использовать Double.parseDouble() .

Вам нужно использовать a NumberFormat для анализа форматов чисел, зависящих от локали. Поскольку «Uppgift» выглядит по-шведски, мы можем использовать NumberFormat.getInstance(Locale.forLanguageTag("sv-SE")) , или просто NumberFormat.getInstance() , если ваш язык по умолчанию — Швеция.

 String filename = "text.txt";
try (BufferedReader in = Files.newBufferedReader(Paths.get(filename))) {
    NumberFormat format = NumberFormat.getInstance(Locale.forLanguageTag("sv-SE"));
    
    for (String line; (line = in.readLine()) != null; ) {
        List<Double> aList = new ArrayList<>();
        
        for (String token : line.split(";")) {
            double value = format.parse(token).doubleValue();
            aList.add(value);
        }
        
        System.out.println(aList); // Prints: [17.23, 12.1, 20.34, 88.23523]
    }
}
  

Ответ №3:

Вы можете сделать это, просто изменив разделитель. Это работает путем чтения из строки, но вы также можете сделать это из файла. Вам решать поместить значения в некоторую структуру данных. Это предполагает, что ваш язык по умолчанию использует ‘,’ в качестве десятичной точки.

 String str = "17,23;12,1;20,34;88,23523;";

Scanner scan = new Scanner(str);
scan.useDelimiter("[;] ");
while(scan.hasNextDouble()) {
    System.out.println(scan.nextDouble());
}
  

С принтами

 17.23
12.1
20.34
88.23523
  

Комментарии:

1. Запятая — это десятичный разделитель в вопросе OP, а не разделитель чисел

2. Маловероятно, что оба , и ; являются разделителями значений. Гораздо более вероятно, что ; это разделитель значений, и это , десятичная точка, зависящая от локали, тем более, что слово «Uppgift» в имени файла — шведское, а Швеция использует , в качестве десятичной точки.

3. Ну, OP не указал это в вопросе (но это имеет смысл), поэтому я уточнил это в своем ответе. Спасибо вам обоим!

4. Привет, Андреас прав. Теперь я изменил это на более международный стандарт! Большое спасибо за ответы!

Ответ №4:

Поскольку в вашем файле есть числа, разделенные точкой с запятой, вы не сможете прочитать их с помощью scan.hasNextDouble() по умолчанию. Однако существует так много способов сделать это, например

  1. Переопределите разделитель по умолчанию.
  2. Чтение строки как строки и обработка каждого числа из нее после разделения на точки с запятой.

Вариант-1:

 scan.useDelimiter(";")
  

Обратите внимание, что, поскольку в вашем файле вместо точки в качестве десятичного символа используется запятая, вы можете использовать a Locale , в котором он используется по умолчанию.

 scan.useLocale(Locale.FRANCE);
  

Кроме того, следующий блок кода в вашем коде приведет к завершению цикла после считывания самого первого числа как первого числа в вашем файле, не равного нулю. Просто удалите эти строки, чтобы получить желаемый результат:

 if (nextInput != 0) {
    break;  
}
  

Вариант-2:

Прочитайте строку, разделите ее точкой с запятой, замените запятую точкой, проанализируйте каждый элемент из результирующего массива в Double и сохраните его в aList .

ДЕМОНСТРАЦИЯ:

 import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) throws FileNotFoundException {
        File myFile = new File("file.txt");
        Scanner scan = new Scanner(myFile);

        List<Double> aList = new ArrayList<>();
        while (scan.hasNextLine()) {
            String nextInput = scan.nextLine();
            String[] arr = nextInput.split(";");
            for (String s : arr) {
                aList.add(Double.valueOf(s.replace(",", ".")));
            }
        }
        System.out.println(aList);
    }
}
  

Вывод:

 [17.23, 12.1, 20.34, 88.23523]
  

Альтернативой замене запятой точкой является использование NumberFormat , как показано ниже:

 import java.io.File;
import java.io.FileNotFoundException;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) throws FileNotFoundException, ParseException {
        File myFile = new File("file.txt");
        Scanner scan = new Scanner(myFile);
        NumberFormat format = NumberFormat.getInstance(Locale.FRANCE);
        List<Double> aList = new ArrayList<>();
        while (scan.hasNextLine()) {
            String nextInput = scan.nextLine();
            String[] arr = nextInput.split(";");
            for (String s : arr) {
                aList.add(format.parse(s).doubleValue());
            }
        }
        System.out.println(aList);
    }
}