Текст не может быть проанализирован, найден неанализируемый текст

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

      LocalTime lt = LocalTime.parse(songTime, 
DateTimeFormatter.ofPattern("k:m:s"));

Вот что странно. Всякий раз, когда я запрашиваю у пользователя какое-то время (давайте возьмем для примера 00:02:30), он работает именно так, как я хочу. Но когда я использую свой метод (который извлекает время из текстового файла), он выдает ошибку:

Исключение в потоке «main» java.time.format.DateTimeParseException: текст '00: 02: 30 'не может быть проанализирован, не проанализированный текст найден с индексом 8

Первое, что я предположил, это то, что он мог вносить лишние пробелы или что-то в этом роде. Чтобы проверить это, я напечатал по 3 строки с каждой стороны переменной, и они напечатали это:

--- 00:02:30 ---

Как видно выше, пробелов не было. Если я жестко запрограммировал 00:02:30, он также отлично работает. Затем я столкнулся с другой вещью, которая меня беспокоила. Мой текстовый файл выглядит так:


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

Ниже приведены значения каждой опции, которую я выбрал в Formatter (из документации ):

      k       clock-hour-of-am-pm (1-24)
m       minute-of-hour 
s       second-of-minute

Вот метод, который читает файл:

      public static ArrayList<Song> scanInSongs () {

ArrayList<Song> songArray = new ArrayList<Song>();

try { 

    BufferedReader reader = new BufferedReader(new FileReader("Description.txt"));
    String line;

    while ((line = reader.readLine()) != null) {
       String key = line.substring(0, line.indexOf(' '));
       System.out.println("Fetched timestamp: "+ key);
       String value = line.substring(line.indexOf(' ') + 1);
       System.out.println("Fetched name: "+ value);

       Song song = new Song(value, "", key);
       songArray.add(song);
    }
} catch (IOException e) {
    System.out.println("File not found, exception: "+ e);
} 

return songArray;

}

Класс песни:

      public class Song {
    private String duration = "";
    private String name = "";
    private String timestampFromVideo = "";

    public Song(String name, String timestampFromVideo, String duration) {
        if (name == "") {
            this.name = "";   
        } else {
            this.name = name;
        }
        this.duration = duration;

        this.timestampFromVideo = timestampFromVideo;
    }

    public String getName() {
        return this.name;
    }

    public String getDuration() {
        return this.duration;
    }

    public String getTimestampFromVideo() {
        return this.timestampFromVideo;
    }

    public void setDuration(String duration) {
        this.duration = duration;
    }

}

Главный:

      public static void main(String[] args) {

    ArrayList<Song> songArray = scanInSongs();

    String songTime = songArray.get(0).getDuration();

    LocalTime lt = LocalTime.parse(songTime, 
    DateTimeFormatter.ofPattern("k:m:s"));       
}

Наконец, как указано ранее, это файл:

      00:00:00 First
00:02:30 Second

Заранее всем спасибо за помощь!

3 ответа

Вы используете неправильный тип

От 00:02:30, ты имеешь в виду , нет LocalTime.

Вы можете преобразовать свою строку в формат ISO 8601 для Duration, а затем проанализировать полученную строку в Duration.

Демо:

      import java.time.Duration;

public class Main {
    public static void main(String[] args) {
        System.out.println(parse("00:02:30"));
        System.out.println(parse("00:00:00"));
    }

    static Duration parse(String strDuration) {
        String[] arr = strDuration.split(":");
        Duration duration = Duration.ZERO;
        if (arr.length == 3) {
            strDuration = "PT" + arr[0] + "H" + arr[1] + "M" + arr[2] + "S";
            duration = Duration.parse(strDuration);
        }
        return duration;
    }
}

Выход:

      PT2M30S
PT0S

ONLINE DEMO

Вам не нужно DateTimeFormattter для анализа времени в формате ISO 8601

Современный API даты и времени основан на ISO 8601 и не требует использования DateTimeFormatter объект явно, если строка даты и времени соответствует стандартам ISO 8601.

Демо:

      import java.time.LocalTime;

public class Main {
    public static void main(String[] args) {
        System.out.println(LocalTime.parse("00:02:30"));
        System.out.println(LocalTime.parse("00:00:00"));
    }
}

Выход:

      00:02:30
00:00

ONLINE DEMO

Узнайте больше о современном API даты и времени из Trail: Date Time.

Непечатаемый символ в вашем файле

В вашей строке есть непечатаемый символ (а не пробел, так как strip()не помогло). Поскольку строка была прочитана из файла, этот символ должен быть в файле.

Как проверить:

          key.chars().forEach(System.out::println);

Если key просто "00:02:30", это напечатает

       48
48
58
48
50
58
51
48

Бьюсь об заклад, что у вас больше результатов, чем это. Если, например, у вас есть:

       48
48
58
48
50
58
51
48
8203

Здесь мы видим, что в конце строки находится символ со значением Unicode 8203 (десятичный). Это пространство нулевой ширины, что объясняет, почему мы не могли видеть его, когда вы печатали строку. LocalTime.parse() могли видеть это, что объясняет появившееся сообщение об ошибке.

Интересно (и, возможно, разочаровывает), что пространство нулевой ширины не считается пробелом для strip Метод, предложенный Анишем Шармой в его ответе, поэтому этот ответ не решил проблему.

Хорошее решение - удалить символ из файла.

Еще одно предложение по улучшению: java.time.Duration

Я полностью согласен с ответом Арвинда Кумара Авинаша: вы должны использовать класс в течение некоторого времени (также больше не будет работать, если вы однажды столкнетесь с продолжительностью более 24 часов). И вам следует пойти дальше и в своем классе модели сохранить продолжительность как a, а не как строку. Так же, как вы храните числа в int переменные, а не в строках (очень надеюсь).

      public class Song {
    private Duration duration;
    private String name;
    // …

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

      /** @throws DateTimeParseException if durationString is not in format hh:mm:ss */
public Song(String name, String timestampFromVideo, String durationString) {
    this.name = "";   
    String iso = durationString.replaceFirst(
            "^(\\d{2}):(\\d{2}):(\\d{2})$", "PT$1H$2M$3S");
    duration = Duration.parse(iso);

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

Мой способ преобразования строки продолжительности в формат ISO 8601, требуемый Duration.parse()отличается от ответа Арвинда Кумара Авинаша. Если его путь легче понять, во что бы то ни стало используйте его, это нормально.

Кроме того, это не актуально, если вы используете, Arvind также прав, что если вы хотите выполнить синтаксический анализ в a, вам не понадобится DateTimeFormatter поскольку 00:02:30 в формате ISO 8601 для времени суток и LocalTimeанализирует этот формат без указания средства форматирования. Наконец, Йоахим Исакссон прав в своем комментарии, что шаблонная буква неверна для часа дня, когда она может быть 0. kдля часового дня (1-24). Для часа дня (00–23) вам понадобится HH.

Ссылки

используйте метод strip() java 9. Предполагая, что songTime - это строка, которую вы читаете из текстового файла, используйте songTime.strip().

Метод strip() удаляет все пробелы Unicode вместе с нормальными пробелами

Другие вопросы по тегам