提问人:4K4K1N 提问时间:8/28/2023 最后编辑:4K4K1N 更新时间:8/28/2023 访问量:106
如何在 Java 中拆分行尾?
How do you split at the end of the line in Java?
问:
我有一个 .txt 文件,如下所示:
Event=ThermostatNight,time=0
Event=LightOn,time=2000
Event=WaterOff,time=10000
Event=ThermostatDay,time=12000
Event=Bell,time=9000,rings=5
Event=WaterOn,time=6000
Event=LightOff,time=4000
Event=Terminate,time=20000
Event=FansOn,time=7000
Event=FansOff,time=8000
我正在尝试将上述内容存储到一个数组中,例如数组应该是:
[0] = Event
[1] = ThermostatNight
[2] = time
[3] = 0
[4] = Event
[5] = LightOn
[6] = time
[7] = 2000
//.... etc
基本上,我试图将事件名称存储为变量,将时间存储为另一个变量,并使用 = 和 作为拆分点。但是,索引 [3] 显示“0Event”,索引 [6] 显示“2000Event”,依此类推。
我不确定我是否应该使用新行作为拆分点或空白,或者我可能只是以错误的方式看待这个问题。这是我的代码:
public static void main(String[] 参数) {
try {
Scanner content = new Scanner(new File("file.txt")).useDelimiter(",");
StringBuilder sb = new StringBuilder();
while(content.hasNext()) {
sb.append(content.nextLine());
}
String[] wordsArray = sb.toString().split("[=,]");
//Test what is at each index
System.out.println(wordsArray[3]);
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
}
我一直在玩 String[] wordsArray = sb.toString().split(“[=,]”);并尝试将代码修改为:
.split("\[=,\\n\]")
.split("\[=,\\s\]")
.split("\[=,\\n\]")
...etc
以及 .split 中的许多其他不同参数。
但我仍然不断将索引 [3] 和 [6] 作为 0Event 和 2000Event。
再次不确定我是否只是以错误的方式看待这个问题或采取错误的方法。任何帮助将不胜感激。
答:
TL的;博士
我发现多次拆分而不是正则表达式更简单、更清晰、更自我记录。
input
.lines ( )
.flatMap ( line -> Arrays.stream ( line.split ( "," ) ) )
.flatMap ( pair -> Arrays.stream ( pair.split ( "=" ) ) )
.toArray ( String[] :: new );
拆分 3 次,嵌套
为什么不使用三重嵌套调用来拆分?
在外循环中,按线拆分。在逗号上的拆分中。第三,在 EQUALS SIGN 上拆分。
String input = """
Event=ThermostatNight,time=0
Event=LightOn,time=2000
Event=WaterOff,time=10000
Event=ThermostatDay,time=12000
Event=Bell,time=9000,rings=5
Event=WaterOn,time=6000
Event=LightOff,time=4000
Event=Terminate,time=20000
Event=FansOn,time=7000
Event=FansOff,time=8000
""";
List < String > list = new ArrayList <> ( );
for ( String line : input.lines ( ).toList ( ) )
{
for ( String pair : line.split ( "," ) )
{
for ( String keyOrValue : pair.split ( "=" ) )
{
list.add ( keyOrValue );
}
}
}
String[] array = list.toArray ( String[] :: new );
array = [Event, ThermostatNight, time, 0, Event, LightOn, time, 2000, Event, WaterOff, time, 10000, Event, ThermostatDay, time, 12000, Event, Bell, time, 9000, rings, 5, Event, WaterOn, time, 6000, Event, LightOff, time, 4000, Event, Terminate, time, 20000, Event, FansOn, time, 7000, Event, FansOff, time, 8000]
您的 IDE 可能会建议将该内部循环替换为 调用 。addAll
for ( String line : input.lines ( ).toList ( ) )
{
for ( String pair : line.split ( "," ) )
{
list.addAll ( Arrays.asList ( pair.split ( "=" ) ) );
}
}
对于更紧凑的代码,我们可以使用流并生成单行代码。flatMap
String[] array =
input
.lines ( )
.flatMap ( line -> Arrays.stream ( line.split ( "," ) ) )
.flatMap ( pair -> Arrays.stream ( pair.split ( "=" ) ) )
.toArray ( String[] :: new );
评论
String[] array = input.split("\\R|[,=]");
Scanner
String[] array = new Scanner(input) .useDelimiter("\\R|[,=]").tokens().toArray(String[]::new);
您应该一次分隔一个步骤的数据,并一次解析一行,而不是一次全部解析。
因此,在您的情况下,每行 (content.nextLine) 都应该用逗号分隔:
String attributes = line.split(',');
然后,获取属性并单独拆分它们,以获取密钥和值:
for(String attribute : attributes) {
String pairs = attribute.split('=');
String key = attribute[0]; // Event, or time
String value = attribute[1]; // LightsOn, or 2000
// Do stuff with key and value, like add in your array
}
作为旁注:
除非您需要将其添加到原始数组中,否则我建议创建一个对象来表示您正在解析的数据。这样,您就可以将该数据的新对象(即 Event(String name, long time))添加到事件的 ArrayList 中。
"...我正在尝试将上述内容存储到一个数组中......”
"...我不确定我是否应该使用新行作为分割点或空白,或者我可能只是以错误的方式看待这个问题......”
有几种方法可以完成此任务。
可以向 Scanner#useDelimiter 调用添加更多值,然后使用 next 而不是 nextLine。
\r\n?|\n|[,=]
这将允许您摆脱 StringBuilder。
对于 wordsArray,最初使用 List,并在需要时转换为数组。
try {
Scanner content = new Scanner(new File("file.txt")).useDelimiter("\r\n?|\n|[,=]");
List<String> list = new ArrayList<>();
while(content.hasNext()) {
list.add(content.next());
}
String[] wordsArray = list.toArray(new String[0]);
//Test what is at each index
System.out.println(wordsArray[3]);
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
或者,按原样使用扫描程序,不使用修改的分隔符,并使用 String#split 方法。
while(content.hasNextLine())
wordsArray.addAll(List.of(content.nextLine().split("[,=]")));
try {
Scanner content = new Scanner(new File("file.txt"));
List<String> list = new ArrayList<>();
while(content.hasNext()) {
list.addAll(List.of(content.nextLine().split("[,=]")));
}
String[] wordsArray = list.toArray(new String[0]);
//Test what is at each index
System.out.println(wordsArray[3]);
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
输出
0
"...再次不确定我是否只是以错误的方式看待这个问题或采取错误的方法。任何帮助都非常感谢。
可以使用提供 lines 方法的 BufferedReader 类代替 Scanner。
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
List<String> list = reader.lines()
.flatMap(x -> Stream.of(x.split("[,=]")))
.toList();
}
评论
\R
\r\n?|\n
Scanner
String[] array; try(Scanner s = new Scanner(new File("file.txt")) .useDelimiter("\\R|[,=]")) { array = s.tokens().toArray(String[]::new); }
Scanner
Reader
\R
\r\n
\R\R
\r\n
\R
"\r\n".matches("\\R\\R")
true
matches
"\r\n".matches("(\r\n?|\n){2}")
true
split
"X\r\nY".split("\\R")
"X\r\nY".split("\r\n?|\n")
"X"
"Y"
上面提到的人,你最好采用面向对象的方法来建模你的活动。请注意具有“rings”属性的异常记录。这将是描述重复的另一种方式。这里是铃铛,但可能是蜂鸣器或其他东西。
完成此操作后,可以将文件解析为对象:Event
public class Event {
private String name;
private int duration;
private int numRepetitions;
public Event() {
}
public Event(String name, int duration, int numRepetitions) {
this.name = name;
this.duration = duration;
this.numRepetitions = numRepetitions;
}
public String getName() {
return this.name;
}
public int getDuration() {
return this.duration;
}
public int getNumRepetitions() {
return this.numRepetitions;
}
public void setName(String name) {
this.name = name;
}
public void setDuration(int duration) {
this.duration = duration;
}
public void setNumRepetitions(int numRepetitions) {
this.numRepetitions = numRepetitions;
}
public static Event fromCsv(String[] tokens) {
if (tokens.length == 4) {
return new Event(tokens[1], Integer.parseInt(tokens[3]), 0);
} else {
return new Event(tokens[1], Integer.parseInt(tokens[3]), Integer.parseInt(tokens[5]));
}
}
public String toString() {
return String.format("%s=%s,%s=%d,%s=%d", "name", name, "duration", duration, "numRepetitions", numRepetitions);
}
}
解析文件:
import java.nio.file.Path;
import java.nio.file.Files;
import java.util.List;
import java.io.IOException;
public class EventParser {
public static void main(String[] args) throws Exception {
List<Event> events = EventParser.parseEvents(Path.of(args[0]));
events.forEach(System.out::println);
}
public static List<Event> parseEvents(Path p) throws IOException {
return Files.lines(p)
.map(line ->line.split("[,=]"))
.map(Event::fromCsv)
.toList();
}
}
给出输出:
name=ThermostatNight,duration=0,numRepetitions=0
name=LightOn,duration=2000,numRepetitions=0
name=WaterOff,duration=10000,numRepetitions=0
name=ThermostatDay,duration=12000,numRepetitions=0
name=Bell,duration=9000,numRepetitions=5
name=WaterOn,duration=6000,numRepetitions=0
name=LightOff,duration=4000,numRepetitions=0
name=Terminate,duration=20000,numRepetitions=0
name=FansOn,duration=7000,numRepetitions=0
name=FansOff,duration=8000,numRepetitions=0
评论
content.nextLine()
String.split
\\R
split
.split("\[=,\\R]")
)