基于在Java中搜索文本文件来吐出随机行

时间:2015-06-08 18:03:21

标签: java

我正在制作一个IRC机器人,我有一个文本文件,其中包含每个用户在新的单独行上的引用。

例如: 我喜欢豌豆 - user1 我喜欢西红柿 - user2 我喜欢西红柿里面的豌豆 - user1

我希望有一种方法可以做到这一点,如果有人输入"!引用用户"它将从该用户随机引用并将其发送到该频道。这是我到目前为止的代码:

if (messageIC.startsWith("!quote")) {
    String user = message.substring(7);
    java.io.FileInputStream fs = null;
    try {
        fs = new java.io.FileInputStream("C:/Users/Quibbles/Documents/ampersand/quotes.txt");
    } catch (FileNotFoundException ex) {
        Logger.getLogger(Ampersand.class.getName()).log(Level.SEVERE, null, ex);
    }
    BufferedReader br = new BufferedReader(new InputStreamReader(fs));
    ArrayList<String> array = new ArrayList<>();
    String line;
    try {
        while((line = br.readLine()) != null)
            array.add(br.readLine());
    } catch (IOException ex) {
        Logger.getLogger(Ampersand.class.getName()).log(Level.SEVERE, null, ex);
    }
    // variable so that it is not re-seeded every call.
    Random rand = new Random();

    // nextInt is exclusive. Should be good with output for array.
    int randomIndex = rand.nextInt(array.size());

    if ((array.get(randomIndex).contains(user))) {
       sendMessage(channel, array.get(randomIndex)); 
    }

}

然而,这不起作用。机器人没有吐出任何东西。我做错了什么?

2 个答案:

答案 0 :(得分:1)

有些事情看起来可能会导致问题乍一看:

(我假设&#34; C:/Users/Quibbles/Documents/ampersand/quotes.txt"包含所有用户的引用。)< /子>

首先,如果您只是在寻找一个用户,请不要将所有用户的所有引号都放入ArrayList<String> array。这样,当您从列表中选择一个随机值时,您可以确定它将从指定用户返回一些内容(或为空)。

其次,正如您在评论中看到的那样,构建Random的实例是一项相当昂贵的操作,但将其置于一个变量中,使得每次调用都不会停止它被重新播种,因为它实际上正在被重新实例化。你应该把它放在方法之外,所以它不是一个不断创建和销毁的局部变量。

第三,你在每次迭代中都会调用br.readLine()两次,这会跳过行。由于您已经调用过一次并将其分配给line,因此只需使用line

请改为尝试:

// ... somewhere in the actual class, *not* inside a method ...
private static Random rand = new Random();
// ...

// ... the rest here will be where it was, *inside* the method
if (messageIC.startsWith("!quote")) {
    String user = message.substring(7);
    java.io.FileInputStream fs = null;
    try {
        fs = new java.io.FileInputStream("C:/Users/Quibbles/Documents/ampersand/quotes.txt");
    } catch (FileNotFoundException ex) {
        Logger.getLogger(Ampersand.class.getName()).log(Level.SEVERE, null, ex);
    }
    BufferedReader br = new BufferedReader(new InputStreamReader(fs));
    ArrayList<String> array = new ArrayList<String>();
    String line;
    try {
        while ((line = br.readLine()) != null) {
            if (line.contains(user)) {
                array.add(br.readLine());
            }
        }
    } catch (IOException ex) {
        Logger.getLogger(Ampersand.class.getName()).log(Level.SEVERE, null, ex);
    }
    // `rand` will now refer to the class variable, located outside of the method

    if (!array.isEmpty()) {
        // nextInt is exclusive. Should be good with output for array.
        sendMessage(channel, array.get(rand.nextInt(array.size()))); 
    }
}

此外,如果您说原始代码“无法正常工作”,那么确切地知道出了什么问题会很有帮助。您是否尝试过调试或查看是否找到了用户的引用? 这样,我们将能够帮助您确切地解决出错的问题。

如果找到用户是问题,如果我们使用&#34; quotes.txt&#34;的常规格式,也可能会有所帮助。

无论如何,我希望这有帮助。 :)

答案 1 :(得分:0)

您可以使用以下代码替换代码的前半部分:

List<String> array = Files.readAllLines(
    Paths.get(System.getProperty("user.home"),
        "Documents", "ampersand", "quotes.txt"),
    Charset.defaultCharset());

您的异常处理需要改进。如果你无法读取文件,继续使用该方法是没有意义的,对吧?因此,要么将throws IOException添加到包含方法的签名中,要么执行以下操作:

try {
    List<String> array = Files.readAllLines(
        Paths.get(System.getProperty("user.home"),
            "Documents", "ampersand", "quotes.txt"),
        Charset.defaultCharset());

    // Choose quote here
} catch (IOException e) {
    // Can't continue if we can't read the quotes file.
    throw new RuntimeException(e);
}

您想要来自特定用户的随机引用,而不仅仅是文件中的随机行。因此,您应该将随机值仅应用于所需用户的行:

try {
    List<String> array = Files.readAllLines(
        Paths.get(System.getProperty("user.home"),
            "Documents", "ampersand", "quotes.txt"),
        Charset.defaultCharset());

    // Discard lines from other users
    Iterator<String> i = array.iterator();
    while (i.hasNext()) {
        if (!i.next().endsWith(" - " + user)) {
            i.remove();
        }
    }

    // Important:  Do not keep creating a new Random instance.  Instead,
    // create one instance and keep it in a field of your class.
    int randomIndex = random.nextInt(array.size());
    sendMessage(channel, array.get(randomIndex));
} catch (IOException e) {
    // Can't continue if we can't read the quotes file.
    throw new RuntimeException(e);
}

在Java 8中,您可以使用Stream缩短时间:

Path quotesFile = Paths.get(System.getProperty("user.home"),
    "Documents", "ampersand", quotes.txt");

try (Stream<String> lines =
        Files.lines(quotesFile, Charset.defaultCharset())) {

    String[] array = lines.filter(line -> line.endsWith(" - " + user))
        .toArray(String[]::new);

    int randomIndex = random.nextInt(array.length);
    sendMessage(channel, array[randomIndex]);
} catch (IOException e) {
    // Can't continue if we can't read the quotes file.
    throw new RuntimeException(e);
}

Stream是一个try-with-resources语句,因为它是一个支持I / O的Stream,这意味着它从I / O操作(特别是读取文件)中提供其值。