【问题标题】:Parse a text file, split it into lines, return a list and map into objects解析文本文件,将其拆分为行,返回一个列表并映射到对象
【发布时间】:2020-10-09 08:20:03
【问题描述】:

所以我有两种类型的文件,一种用于级别定义,另一种用于块结构定义。

我需要将它们都解析为包含行的字符串列表,然后遍历列表和每一行,拆分和解析并将它们映射到 java 对象中。

我不知道该怎么做,我已经阅读了有关 java io 阅读器的信息,但在这里我对在哪里以及如何使用它感到困惑。

了解单个关卡的关卡规范的内容:这将遍历字符串,拆分和解析它们,并将它们映射到java对象,从而产生一个LevelInformation对象。

P.S 我已经编写并构建了 LevelInformation 接口(如果我手动编写一个实现此接口的关卡,它就可以工作),它包含文本文件中的所有内容(关卡名称、速度、背景等) 所以基本上我只需要解析这些文本文件并将它们映射到这个界面中。

    public interface LevelInformation {
       int numberOfBalls();
       // The initial velocity of each ball
       // Note that initialBallVelocities().size() == numberOfBalls()
// velocities created by (a,s) format. a = angle, s = speed.
       List<Velocity> initialBallVelocities();
       int paddleSpeed();
       int paddleWidth();
       // the level name will be displayed at the top of the screen.
       String levelName();
       // Returns a sprite with the background of the level
       Sprite getBackground();
       // The Blocks that make up this level, each block contains
       // its size, color and location.
       List<Block> blocks();
       // Number of blocks that should be removed
       // before the level is considered to be "cleared".
       // This number should be <= blocks.size();
       int numberOfBlocksToRemove();
    }

文件示例:

level_definition.txt

START_LEVEL
level_name:Square Moon
ball_velocities:45,500
background:image(background_images/night.jpg)
paddle_speed:650
paddle_width:160
block_definitions:definitions/moon_block_definitions.txt
blocks_start_x:25
blocks_start_y:80
row_height:100
num_blocks:4
START_BLOCKS
--ll--
--ll--
END_BLOCKS
END_LEVEL

block_definitions.txt

    #block definitions
bdef symbol:l width:100 height:100 fill:color(RGB(154,157,84))

#spacers definitions
sdef symbol:- width:30

所以我需要创建一个列表并获取一个阅读器并以某种方式对其进行解析。 我很高兴获得一些提示、想法和帮助。 谢谢。

public class LevelSpecificationReader {

   public List<LevelInformation> fromReader(java.io.Reader reader) {
      // ...
   }
}

我想我需要:

  • 将文件分成几行并从中列出字符串。 这意味着每一行都将作为字符串进入列表。

  • 获取每一行,也拆分成我不知道是什么,但是按顺序 获取信息并映射到所需的对象。例如:
    level_name:某事 我必须在我的界面中将“某事”添加到“关卡名称”中。

这是我失败的尝试:

public List<LevelInformation> fromReader(java.io.Reader reader) throws IOException {
    ArrayList<String> listOfLines = new ArrayList<>();
    BufferedReader bufReader = new BufferedReader(new FileReader("file.txt"));
    String line = bufReader.readLine();
    while (line != null) {
        listOfLines.add(line);
        line = bufReader.readLine();
    }
    return listOfLines;
}

此代码会导致错误,因为我返回了一个字符串列表,但我需要一个 LevelInformation 列表。

【问题讨论】:

  • 您需要展示您迄今为止尝试过的代码尝试,以便我们提供建议
  • @DeveshKumarSingh 我不知道如何编写它,因此我没有代码尝试。我的意思是我确实尝试过做某事,但它超级失败。我会附上它
  • 感觉这是一道作业题,请看meta.stackoverflow.com/questions/334822/…
  • @DeveshKumarSingh 我确实尝试理解阅读器和解析的逻辑。我要求指导和提示。感谢您的帮助。
  • 您在问题中写道:我需要 LevelInformation 列表您有LevelInformation 的代码吗?如果你这样做了,那么edit 你的问题并发布该代码,即LevelInformation 的定义。是一堂课吗?是接口吗?一旦您发布了LevelInformation 的定义,我或许可以向您展示如何从两个文本文件(即level_definition.txt)中创建LevelInformation 对象的List block_definitions.txt

标签: java parsing filereader streamreader text-parsing


【解决方案1】:

也许你想要的是先把它分解成碎片,这样你就不需要一次担心所有的事情,而是专注于解析字符串。您需要做的就是创建一个接受字符串的构造函数,然后在构造函数中解析它

public List<LevelInformation> fromReader(java.io.Reader reader) throws IOException {
ArrayList<LevelInformation> listOfLines = new ArrayList<>();
BufferedReader bufReader = new BufferedReader(new FileReader("file.txt"));
String line = bufReader.readLine();
while (line != null) {
    listOfLines.add(new LevelInformation(line));
    line = bufReader.readLine();
}
return listOfLines;

}

public class LevelInformation {

       LevelInformation (String text) {
           parseText(text);
       }

       private void parseText(String text) {

           //do something here
       }
}

【讨论】:

  • 嘿,谢谢!我已经发布了 LevelIformation 界面。有没有办法像你在这里所做的那样“植入”每一行“new LevelInformation(line)”作为每个对象?例如:包含“level_name:level1”的行会将“level1”插入到LevelInformation接口中包含的“levelName”对象?
【解决方案2】:

这不是一个完整的解决方案,因为您问题中的代码不是reproducible example,因为它不完整。 BlockSpriteVelocity 类的定义在哪里?好吧,我猜到了这些,并为它们做了最小的定义。

我希望以下代码足以帮助您完成项目。它基于您发布的详细信息,包括示例文件:level_definition.txt

班级Sprite

import java.awt.Image;

public class Sprite {
    private Image  image;

    public Sprite(Image image) {
        this.image = image;
    }
}

班级Velocity

public class Velocity {
    private int  speed;

    public Velocity(int speed) {
        this.speed = speed;
    }
}

LevelDtl 实现您的接口:LevelInformation
就个人而言,我认为不需要接口。我觉得应该是一堂课。

public class LevelDtl implements LevelInformation {
    private String  levelName;
    private List<Velocity>  ballVelocities;
    private Sprite  background;
    private int  paddleSpeed;
    private int  paddleWidth;
    private List<Block>  blocks;
    private int  numBlocks;

    @Override
    public int numberOfBalls() {
        return ballVelocities == null ? 0 : ballVelocities.size();
    }

    @Override
    public List<Velocity> initialBallVelocities() {
        return ballVelocities;
    }

    @Override
    public int paddleSpeed() {
        return paddleSpeed;
    }

    @Override
    public int paddleWidth() {
        return paddleWidth;
    }

    @Override
    public String levelName() {
        return levelName;
    }

    @Override
    public Sprite getBackground() {
        return background;
    }

    @Override
    public List<Block> blocks() {
        return blocks;
    }

    @Override
    public int numberOfBlocksToRemove() {
        return numBlocks;
    }

    public void setBackground(Sprite bg) {
        background = bg;
    }

    public void setBallVelocities(List<Velocity> velocities) {
        ballVelocities = velocities;
    }

    public void setLevelName(String name) {
        levelName = name;
    }

    public void setPaddleSpeed(int speed) {
        paddleSpeed = speed;
    }

    public void setPaddleWidth(int width) {
        paddleWidth = width;
    }

    public String toString() {
        return String.format("Level: %s , Paddle: [speed = %d , width = %d]",
                             levelName,
                             paddleSpeed,
                             paddleWidth);
    }
}

所有带有@Override注解的方法都是LevelInformation接口中方法的实现。另外,请注意方法toString() 仅用于调试目的,因为我在您命名的最终类中使用它:LevelSpecificationReader。它逐行读取文件level_definition.txt,假设您的问题中显示的格式,并构建和配置类LevelDtl 的实例,然后将其添加到List。最后,下面的代码打印出List 的内容。当然,使用您在问题中提供的示例数据,List 仅包含一个元素。

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.imageio.ImageIO;

public class LevelSpecificationReader {
    private static final String  BACKGROUND = "background:";
    private static final String  BALL_VELOCITIES = "ball_velocities:";
    private static final String  END_BLOCKS = "END_BLOCKS";
    private static final String  END_LEVEL = "END_LEVEL";
    private static final String  IMAGE = "image(";
    private static final String  LEVEL_NAME = "level_name:";
    private static final String  PADDLE_SPEED = "paddle_speed:";
    private static final String  PADDLE_WIDTH = "paddle_width:";
    private static final String  START_BLOCKS = "START_BLOCKS";
    private static final String  START_LEVEL = "START_LEVEL";

    private static void setBackground(LevelDtl level, String data) throws IOException {
        Objects.requireNonNull(level, "Null level.");
        if (data != null  &&  !data.isEmpty()) {
            // image(background_images/night.jpg)
            if (data.startsWith(IMAGE)) {
                String path = data.substring(IMAGE.length(), data.length() - 1);
                BufferedImage image = ImageIO.read(new File(path));
                level.setBackground(new Sprite(image));
            }
        }
    }

    private static void setInitialBallVelocities(LevelDtl level, String data) {
        Objects.requireNonNull(level, "Null level.");
        if (data != null  &&  !data.isEmpty()) {
            String[] numbers = data.split(",");
            if (numbers.length > 0) {
                List<Velocity> velocities = new ArrayList<>();
                for (String number : numbers) {
                    try {
                        int speed = Integer.parseInt(number);
                        Velocity velocity = new Velocity(speed);
                        velocities.add(velocity);
                    }
                    catch (NumberFormatException xNUmberFormat) {
                        // Ignore.
                    }
                }
                level.setBallVelocities(velocities);
            }
        }
    }

    private static void setPaddleSpeed(LevelDtl level, String data) {
        Objects.requireNonNull(level, "Null level.");
        if (data != null  &&  !data.isEmpty()) {
            int speed;
            try {
                speed = Integer.parseInt(data);
            }
            catch (NumberFormatException xNumberFormat) {
                speed = 0;
            }
            level.setPaddleSpeed(speed);
        }
    }

    private static void setPaddleWidth(LevelDtl level, String data) {
        Objects.requireNonNull(level, "Null level.");
        if (data != null  &&  !data.isEmpty()) {
            int width;
            try {
                width = Integer.parseInt(data);
            }
            catch (NumberFormatException xNumberFormat) {
                width = 0;
            }
            level.setPaddleWidth(width);
        }
    }

    /**
     * Start here.
     */
    public static void main(String[] args) {
        try (FileReader fr = new FileReader("level_definition.txt");
             BufferedReader br = new BufferedReader(fr)) {
               List<LevelInformation> levels = new ArrayList<>();
               LevelDtl level = null;
               String line = br.readLine();
               while (line != null) {
                   if (START_LEVEL.equals(line)) {
                       // End current level.
                       if (level != null) {
                           levels.add(level);
                       }
                       // Start next level.
                       level = new LevelDtl();
                   }
                   else if (line.startsWith(LEVEL_NAME)) {
                       level.setLevelName(line.substring(LEVEL_NAME.length()));
                   }
                   else if (line.startsWith(BALL_VELOCITIES)) {
                       setInitialBallVelocities(level, line.substring(BALL_VELOCITIES.length()));
                   }
                   else if (line.startsWith(BACKGROUND)) {
                       setBackground(level, line.substring(BACKGROUND.length()));
                   }
                   else if (line.startsWith(PADDLE_SPEED)) {
                       setPaddleSpeed(level, line.substring(PADDLE_SPEED.length()));
                   }
                   else if (line.startsWith(PADDLE_WIDTH)) {
                       setPaddleWidth(level, line.substring(PADDLE_WIDTH.length()));
                   }
                   line = br.readLine();
               }
               if (level != null) {
                   levels.add(level);
               }
               System.out.println(levels);
        }
        catch (IOException xIo) {
            xIo.printStackTrace();
        }
    }
}

上面的代码只处理文件 level_definition.txt 中的行,直到并包括这一行:

paddle_width:160

祝你好运,添加代码来处理文件的其余内容。

【讨论】:

  • 哇!看起来很神奇!太感谢了!虽然我面临的问题仍然很少,但我会尝试自己解决它们。例如,Sprite 不是一个类,它是一个接口。为什么你不认为 LevelInformation 应该是一个接口?我想我把它用作界面,因为一开始我通过手动插入球速度的值和球的数量等来创建关卡。所以更容易实现接口,然后只需填写每个关卡的统计数据.所以现在我需要考虑如何将 img 构造函数添加到 Sprite 接口中。
  • @DimaCiun 接口是当您知道您可能需要不同的实现时。例如,接口java.util.List 有几个不同的实现,包括ArrayListLinkedListVector。根据您问题中的信息,我认为您需要的接口LevelInformation 的实现不会超过一个。
  • 我在这段代码中的目标是获取文本文件,将它们植入 LevelInformation 并制作一个包含多个 LevelInformation 的列表,每个 LevelInformation 都描述一个级别。然后我想将该列表发送到我的 RunGame 函数。但首先我需要创建 LevelInformation 列表
  • 嗨,Abra,如果你有时间可以看看stackoverflow.com/questions/62499353 吗?你在这里的回答很棒,所以我也可以在那里使用你的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-17
  • 1970-01-01
  • 2019-09-13
  • 1970-01-01
  • 1970-01-01
  • 2018-11-23
  • 1970-01-01
相关资源
最近更新 更多