无法解析文本,找到未解析的文本
Text could not be parsed, unparsed text found
我无法弄清楚为什么当我传递的文本符合格式时我会收到 DateTimeParseException 错误。以下是导致问题的代码:
LocalTime lt = LocalTime.parse(songTime,
DateTimeFormatter.ofPattern("k:m:s"));
奇怪的是。每当我查询用户一次(让我们以 00:02:30 为例)时,它就会完全按照我的意愿运行。但是当我使用我的方法(从文本文件中提取时间)时,它给出了错误:
Exception in thread "main" java.time.format.DateTimeParseException:
Text '00:02:30' could not be parsed, unparsed text found at index 8
我首先想到的是,它可能会引入额外的空格或类似的东西。所以为了检查这一点,我在变量的每一侧打印了 3 行,并打印了这个:
---00:02:30---
正如您在上面看到的,没有空格。如果我硬编码 00:02:30 那么它也能完美运行。然后我 运行 陷入了另一件困扰我的事情。我的文本文件如下所示:
00:00:00 First
00:02:30 Second
第一次完美通过,但之后的任何人都会导致错误。它们都具有完全相同的格式,两边都没有空格,所以我看不出问题所在。我检查了关于这个问题的每个论坛 post,其中大多数人使用了错误的格式、错误的字符串等。我不确定这里的情况是否如此,因为当我对其进行硬编码或查询用户时它可以完美运行用于输入。
下面是我在格式化程序中选择的每个选项的含义(来自documentation):
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;
}
歌曲Class:
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
先谢谢大家的帮助!
使用 java 的 strip() 方法 9.
假设 songTime 是您从文本文件中读取的字符串,然后使用 songTime.strip().
strip() 方法删除所有 Unicode 空格和普通空格
您使用的类型有误
00:02:30
是指 Duration
,而不是 LocalTime
。
您可以将您的字符串转换为 ISO 8601 format for a 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
您不需要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
了解有关现代日期时间 API 的更多信息
您的文件中有一个非打印字符
你的字符串中有一个非打印字符(所以不是 white-space 因为 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(十进制)的字符。它是一个零宽度 space,这解释了为什么我们在打印字符串时看不到它。 LocalTime.parse()
可以看到它,这解释了您收到的错误消息。
有趣(也许令人失望)零宽度 space 对于 anish sharma 在他的回答中建议的 strip
方法来说不算是白色 space,这就是为什么回答没有解决问题。
好的解决办法是从文件中删除该字符。
另一个改进建议:java.time.Duration
我完全同意 Arvind Kumar Avinash 的回答:你应该使用 Duration
class 一段时间(而且 LocalTime
将不再工作,如果你有一天遇到持续时间超过 24 小时)。你应该进一步使用 Duration
,在你的模型中 class 将持续时间保持为 Duration
,而不是字符串。就像你将数字保存在 int
变量中而不是字符串中(我非常希望)。
public class Song {
private Duration duration;
private String name;
// …
因为你的实例变量总是从构造函数中初始化,所以不要在声明中给它们默认值,那样只会造成混淆。您可以编写一个方便的构造函数,将字符串解析为 Duration
,例如:
/** @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})$", "PTHMS");
duration = Duration.parse(iso);
您的 if
测试 name
是否为空的语句既错误又多余,所以我将其删除。您不能使用 ==
比较字符串。要测试一个字符串是否为空,请使用 name.isEmpty()
(要求该字符串为非空,即当您从文件中读取它时)。由于您无论如何都将空字符串分配给 name
,我发现省略检查更简单。
我将持续时间字符串转换为 Duration.parse()
要求的 ISO 8601 格式的方法与 Arvind Kumar Avinash 的回答不同。如果他的方法比较好理解,一定要用,也可以。
好处:如果您希望转换为 ISO 8601 以在秒后遗漏任何字符,包括零宽度 space,请使用此变体:
String iso = durationString.replaceFirst(
"^(\d{2}):(\d{2}):(\d{2}).*$", "PTHMS");
我在表示字符串结尾的 $
之前插入了 .*
。这会匹配可能存在的任何字符,并导致它们不会进入 ISO 8601 字符串。所以现在当文件中有零宽度 spaces 时解析也可以工作。
此外,如果你使用 Duration
,Arvind 也是正确的,如果你想解析成 LocalTime
,你不需要 DateTimeFormatter
,因为 [=38] =] 在一天中的某个时间采用 ISO 8601 格式,并且 LocalTime
在不指定格式化程序的情况下解析此格式。最后,Joachim Isaksson 在评论中是正确的,模式字母 k
对于可以为 0 的一天中的小时是不正确的。 k
用于 一天中的时钟小时(1- 24)。对于一天中的小时 (00–23),您需要 HH
.
链接
- Unicode Character 'ZERO WIDTH SPACE' (U+200B) 在 FileFormat.Info 上(重复你自己的 link)
- Documentation of the
Duration
class
- Wikipedia article: ISO 8601
我无法弄清楚为什么当我传递的文本符合格式时我会收到 DateTimeParseException 错误。以下是导致问题的代码:
LocalTime lt = LocalTime.parse(songTime,
DateTimeFormatter.ofPattern("k:m:s"));
奇怪的是。每当我查询用户一次(让我们以 00:02:30 为例)时,它就会完全按照我的意愿运行。但是当我使用我的方法(从文本文件中提取时间)时,它给出了错误:
Exception in thread "main" java.time.format.DateTimeParseException: Text '00:02:30' could not be parsed, unparsed text found at index 8
我首先想到的是,它可能会引入额外的空格或类似的东西。所以为了检查这一点,我在变量的每一侧打印了 3 行,并打印了这个:
---00:02:30---
正如您在上面看到的,没有空格。如果我硬编码 00:02:30 那么它也能完美运行。然后我 运行 陷入了另一件困扰我的事情。我的文本文件如下所示:
00:00:00 First
00:02:30 Second
第一次完美通过,但之后的任何人都会导致错误。它们都具有完全相同的格式,两边都没有空格,所以我看不出问题所在。我检查了关于这个问题的每个论坛 post,其中大多数人使用了错误的格式、错误的字符串等。我不确定这里的情况是否如此,因为当我对其进行硬编码或查询用户时它可以完美运行用于输入。
下面是我在格式化程序中选择的每个选项的含义(来自documentation):
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;
}
歌曲Class:
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
先谢谢大家的帮助!
使用 java 的 strip() 方法 9. 假设 songTime 是您从文本文件中读取的字符串,然后使用 songTime.strip().
strip() 方法删除所有 Unicode 空格和普通空格
您使用的类型有误
00:02:30
是指 Duration
,而不是 LocalTime
。
您可以将您的字符串转换为 ISO 8601 format for a 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
您不需要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
了解有关现代日期时间 API 的更多信息
您的文件中有一个非打印字符
你的字符串中有一个非打印字符(所以不是 white-space 因为 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(十进制)的字符。它是一个零宽度 space,这解释了为什么我们在打印字符串时看不到它。 LocalTime.parse()
可以看到它,这解释了您收到的错误消息。
有趣(也许令人失望)零宽度 space 对于 anish sharma 在他的回答中建议的 strip
方法来说不算是白色 space,这就是为什么回答没有解决问题。
好的解决办法是从文件中删除该字符。
另一个改进建议:java.time.Duration
我完全同意 Arvind Kumar Avinash 的回答:你应该使用 Duration
class 一段时间(而且 LocalTime
将不再工作,如果你有一天遇到持续时间超过 24 小时)。你应该进一步使用 Duration
,在你的模型中 class 将持续时间保持为 Duration
,而不是字符串。就像你将数字保存在 int
变量中而不是字符串中(我非常希望)。
public class Song {
private Duration duration;
private String name;
// …
因为你的实例变量总是从构造函数中初始化,所以不要在声明中给它们默认值,那样只会造成混淆。您可以编写一个方便的构造函数,将字符串解析为 Duration
,例如:
/** @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})$", "PTHMS");
duration = Duration.parse(iso);
您的 if
测试 name
是否为空的语句既错误又多余,所以我将其删除。您不能使用 ==
比较字符串。要测试一个字符串是否为空,请使用 name.isEmpty()
(要求该字符串为非空,即当您从文件中读取它时)。由于您无论如何都将空字符串分配给 name
,我发现省略检查更简单。
我将持续时间字符串转换为 Duration.parse()
要求的 ISO 8601 格式的方法与 Arvind Kumar Avinash 的回答不同。如果他的方法比较好理解,一定要用,也可以。
好处:如果您希望转换为 ISO 8601 以在秒后遗漏任何字符,包括零宽度 space,请使用此变体:
String iso = durationString.replaceFirst(
"^(\d{2}):(\d{2}):(\d{2}).*$", "PTHMS");
我在表示字符串结尾的 $
之前插入了 .*
。这会匹配可能存在的任何字符,并导致它们不会进入 ISO 8601 字符串。所以现在当文件中有零宽度 spaces 时解析也可以工作。
此外,如果你使用 Duration
,Arvind 也是正确的,如果你想解析成 LocalTime
,你不需要 DateTimeFormatter
,因为 [=38] =] 在一天中的某个时间采用 ISO 8601 格式,并且 LocalTime
在不指定格式化程序的情况下解析此格式。最后,Joachim Isaksson 在评论中是正确的,模式字母 k
对于可以为 0 的一天中的小时是不正确的。 k
用于 一天中的时钟小时(1- 24)。对于一天中的小时 (00–23),您需要 HH
.
链接
- Unicode Character 'ZERO WIDTH SPACE' (U+200B) 在 FileFormat.Info 上(重复你自己的 link)
- Documentation of the
Duration
class - Wikipedia article: ISO 8601