从文本文件中读取字符同时忽略新行中的额外空格的最佳方法是什么?

What is the best way to read in chars from a text file while ignoring extra spaces from new lines?

我正在阅读格式为 16x16 数独游戏的文本文件。

例如:

F7B-E-A-1--6---D  
-91AF-0-85D7E4-C  
05-69C---B-EA-3-  
-C-E-2-B--A-7860  
E05---2F-7---1C-  
-4-8-DC--E-593--  
-29---1-D--A-04-  
D67-A-98----B-F-  
9B-D-130C8--F5A-  
8F4569EA7D--CB--  
6A---745BFE-12D9  
7--1DBFC-A-04--E  
5-F9C-61240D-7E-  
A--7-F-DE-580-2-  
--0-5E7-F63C--14  
CE640-----7B5D9F

我试图将这些值放入一个二维字符数组中,但是当遇到一行的末尾时,似乎包含了 3 个空格。 我试过使用 BufferedReader 和 FileInputStream 等各种方式都无济于事。文本文件必须采用该格式,因为我的教授将使用该格式使用他自己的值进行测试。

我将文件放入 ArrayList 的代码:

private static ArrayList readFile(File filename)
{
    ArrayList records = new ArrayList();
    try
    {
        FileInputStream stream = new FileInputStream(filename);

        char current;
        while(stream.available() > 0)
        {
            current = (char)stream.read();
            records.add(current);
        }
        stream.close();
        return records;
    }
    catch (Exception e)
    {
        System.err.format("Exception occurred trying to read '%s'.", filename);
        return null;
    }
}

然后我使用迭代器开始为二维数组赋值。当打印出网格时它看起来很好,但是当检查单个值时,比如 grid[1][1],它是不正确的因为它抛出的间距。

有没有一种方法可以一个字符一个字符地读入,但要避免它放入的 3 个空格来表示新行?

好吧,因为您只对十六进制字符和 - 真正感兴趣,所以您可以过滤掉所有其他内容。最简单的方法可能是替换:

current = (char)stream.read();

与:

current = (char)stream.read();
while ("0123456789ABCDEF-".indexOf(current) < 0)
    current = (char)stream.read();

但您可能需要 fiddle 错误条件以确保它是防弹的。

例如,检查输入循环完成后有多少元素被添加到 records。如果 records.size() 没有给你 256,则文件有问题。

这将从您的文件中消除 所有 格式问题,只有内容才是重要的(例如,如果您愿意,您可以只在一行中提供所有 256 个字符)。

这遵循 "be liberal in what you accept, specific in what you produce" 的稳健性原则。


您可能还想重新考虑从文件输入创建数组列表然后从中构造二维数组的方法。在我看来你可以直接用类似(伪代码)的东西创建二维数组:

def readPuzzle(file) -> (array, error)
    set puzzle to new char[16][16]
    set row to 0, col to 0

    get next character from file to current
    while read okay:
        if current in "0123456789ABCDEF-":
            if row is 16:
                return (puzzle, "too many entries in file")
            puzzle[row][col] = current
            increment col
            if col is 16:
                increment row
                set col to 0
    if row is not 16:
        return (puzzle, "not enough entries in file")
    return (puzzle, "okay")

这基本上只是从文件中读取所有 个字符,如果它们有效则将它们直接添加到数组中。添加之前,它会检查以确保您尚未填满拼图,并且在处理完所有字符后,它会检查以确保 整个 拼图已填满。

你提到你想放入一个二维字符数组,所以你可能想忽略位置 > 15 :

char[][] sudoku = new char[16][16];
Scanner sc = new Scanner(filename);
String[] temporary = new String[16];
int counter = 0;

while(sc.hasNext){
    temporary[counter] = sc.nextLine();
    counter ++;
}

for(int i = 0; i < 16; i++){
    for(int j = 0; j < 16; j++){
        sudoku[i][j] = temporary[i].charAt(j);
    }
}

现在你的二维数组会自动忽略末尾的空白,因为你逐行读取文件,然后手动将值添加到二维数组中。

String.trim() 是从字符串的开头或结尾删除不必要的空格的最简单方法,因此您始终可以在读取文件后进行清理:

private static void trimAllStrings(List<String> list) {
  for (int i = 0; i < list.size(); i++) {
    list.put(i, list.get(i).trim());
  }
}

或者您可以在阅读内容的同时进行修剪 - Java 8 的 Files.lines() 流使这种转换非常容易:

List<String> trimmedLines = Files.lines(myfile, StandardCharsets.UTF_8)
    .map(String::trim).collect(Collectors.toList());

如果你还没有掌握这个 Java 8 语法,你可以在 Java 7 风格中做基本相同的事情:

ArrayList<String> list = new ArrayList<>();
for (String line : Files.readAllLines(myfile, StandardCharsets.UTF_8)) {
  list.add(line.trim());
}