读取以制表符分隔的文件,并将单词放入ArrayList中。

12

我是一名自学者,正在进行有关Java的练习,但我卡在了这个问题上。我有以下txt文件:

Name  Hobby 
Susy  eat fish 
Anna  gardening
Billy bowling with friends

注意:名字和爱好之间用制表符分隔 最佳方法是读取所有行并将其放入arraylist(name,hobby)中。棘手的部分是:
eat fish or bowling with friends

有空格的字符串必须放在一个数组中,但我无法硬编码。以下是我的当前代码:

 public void openFile(){
            try{
                FileInputStream fstream = new    FileInputStream("textfile.txt");
          // use DataInputStream to read binary NOT text
          BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
          ArrayList<String> names = new ArrayList<String>();
          ArrayList<String> hobbies = new ArrayList<String>();
          String lineJustFetched;
          while ((lineJustFetched = br.readLine()) != null)   {
          String[] tokens = lineJustFetched.split(" \t");

我遇到了一个错误:

java.lang.StringIndexOutOfBoundsException: 字符串索引超出范围:-1

我怀疑在制表符上计算索引并不是很有用。有什么想法吗?


确保文件末尾没有新的/空的行。 - srkavin
5个回答

14

好的,您需要执行下面显示的配方:

  1. 创建一个BufferedReader
  2. 创建一个ArrayList<String>
  3. 开始将数据读入名为lineJustFetchedString变量中。
  4. 通过调用lineJustFetched.split("\t");拆分String
  5. 迭代生成的String[]。检查要输入到ArrayList中的标记是否不是""
  6. 如果不是,则将单词添加到ArrayList

您指定需要基于\t值进行拆分,因此空格不会成为问题。

SSCCE

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;

public class WordsInArray {
    public static void main(String[] args) {
        try{
            BufferedReader buf = new BufferedReader(new FileReader("/home/little/Downloads/test"));
            ArrayList<String> words = new ArrayList<>();
            String lineJustFetched = null;
            String[] wordsArray;

            while(true){
                lineJustFetched = buf.readLine();
                if(lineJustFetched == null){  
                    break; 
                }else{
                    wordsArray = lineJustFetched.split("\t");
                    for(String each : wordsArray){
                        if(!"".equals(each)){
                            words.add(each);
                        }
                    }
                }
            }

            for(String each : words){
                System.out.println(each);
            }

            buf.close();

        }catch(Exception e){
            e.printStackTrace();
        }
    }
}    

输出

John
likes to play tennis
Sherlock
likes to solve crime

嗨,我已经按照你的指示编辑了我的源代码。这样正确吗? - user2891092
@user2891092,我为您发布了一个SSCCE。 - An SO User
但它将所有内容都放入一个ArrayList中。是否可能将它们分成两个ArrayList(例如,将John放入名称列表中,将喜欢打网球放入爱好列表中)? - user2891092
是的。在这种情况下,每个奇数单词都将成为名字,每个偶数单词都将成为爱好。你明白我的意思吗?=) - An SO User
难道没有一个Java库可以完成这个常见的任务吗?例如,Python有csv - Arthur

4
如果您使用制表符 \t 分隔姓名和爱好列,则应该像这样操作(不要忘记在结尾处关闭扫描器):
public void readFile() throws FileNotFoundException{
    Scanner scan = new Scanner(new File("D://a.txt"));
    ArrayList<String> names = new ArrayList<String>();
    ArrayList<String> hobbies = new ArrayList<String>();

    while(scan.hasNext()){
        String curLine = scan.nextLine();
        String[] splitted = curLine.split("\t");
        String name = splitted[0].trim();
        String hobby = splitted[1].trim();
        if(!"Name".equals(name)){
            names.add(name);
        }
        if(!"Hobby".equals(hobby)){
            hobbies.add(hobby);
        }
    }
    System.out.println(names);
    System.out.println(hobbies);
    scan.close();
}

1
对于仍在探索中的人,使用Java 8的Stream API可以完成这个操作。
这显示了:
  • 过滤方法用于从列表中过滤出第一个标题元素
  • 映射方法将流中的每个元素映射到另一个元素以创建新流。
package com.bhavya.stackoverflow.examples.q19575308;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.function.Predicate;

/**
 * Java 8 Stream API to handle file reading.
 *
 * @author bhavya.work
 */
public class StreamTests {
  public static void main(String[] args) {
    try {
      InputStream fileInputStream;
      BufferedReader bufferedReader;
      final String filepathInSamePackage = "textfile.txt";
      //filter predicate
      Predicate<String> filterFirstLine =
          line -> !(
              "Name".equals(line.split("\t", -1)[0])
                  && "Hobby".equals(line.split("\t", -1)[1])
          );

      //Implementation 1 returns Arrays as asked.

      System.out.println("==ArrayList==");
      fileInputStream = StreamTests.class.getResourceAsStream(filepathInSamePackage);
      bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));

      bufferedReader
          .lines()
          .filter(filterFirstLine)
          .map(s -> {
            String[] splitStrings = s.split("\t", -1);
            return Arrays.asList(splitStrings);
          }).forEach(System.out::println);

      //Implementation 2 returns HashMap as another example

      fileInputStream = StreamTests.class.getResourceAsStream(filepathInSamePackage);    
      bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));
      System.out.println("\n==HashMap==");

      bufferedReader
          .lines()
          .filter(filterFirstLine)
          .map(s -> {
            String[] splitStrings = s.split("\t", -1);
            HashMap<String, String> stringStringMap = new HashMap<>();
            stringStringMap.put(splitStrings[0], splitStrings[1]);
            return stringStringMap;
          }).forEach(System.out::println);
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
}

和输出

==ArrayList==
[Susy, eat fish]
[Anna, gardening]
[Billy, bowling with friends]

==HashMap==
{Susy=eat fish}
{Anna=gardening}
{Billy=bowling with friends} 

0
你应该尝试使用commons-lang库。除了其他有用的功能外,你可以使用分隔符拆分字符串:
String x="Billy bowling with friends";

String y[]=StringUtils.split(x, '\t');

假设在 Billybowling 之间有一个制表符,
  • y[0] 包含 "Billy"
  • y1 包含 "和朋友一起打保龄球"

0

将来如果你要解析制表符,请使用类似 "\t" 的分隔符,而不是 .split(" ")。

此外,当抛出错误时,表示找不到任何字符,因此会出现 -1。因此在尝试将其存储到数组中时,-1 是无效的。(需要检查一下)

你可以使用 F10 或 F11 等键,在 IDE 中逐步执行程序。

这只是一些提示。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接