首页 > 解决方案 > 使用正则表达式选择最长和最短单词时出现循环问题

问题描述

我需要选择所有最大长度的单词和所有最小长度的单词。

例如:

When I was younger, so much younger than today 
I never needed anybody's help in any way 
But now these days are gone, I'm not so self-assured 
Now I find I've changed my mind 
I've opened up the doors

输出示例:

Min: I, s, m
Max: younger, anybody, assured, changed

我已经弄清楚了算法,但它只是在排序循环之后终止(使用 int k),我不知道为什么,因为由于我的单元测试,调试器什么也没说。它只是停止。你能帮我弄清楚为什么它不起作用吗?PS我不能使用容器类

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Part2 {

    public static void main(String[] args) {
        String input = Util.getInput("part2.txt");
        System.out.print(convert(input));
    }

    public static String convert(String input) {
        Pattern p = Pattern.compile("[A-zА-я]+");
        Matcher m = p.matcher(input);
        int i = 0;
        String[] arr = new String[100];
        while (m.find()){
            arr[i] = m.group(0);
            i++;
        }
        StringBuilder longestResult = new StringBuilder();
        longestResult.append("Max: ");
        StringBuilder shortestResult = new StringBuilder();
        shortestResult.append("Min: ");
        int longest = 0;
        int shortest = arr[0].length();
        for (int k = 0; k < arr.length; k++){
            if (arr[k].length() > longest){
                longest = arr[k].length();
            }
            if (arr[k].length() < shortest){
                shortest = arr[k].length();
            }
        }
        for ( String word : arr) {
            if (word.length() == longest) {
                longestResult.append(word + ", ");
            }
            if (word.length() == shortest) {
                shortestResult.append(word + ", ");
            }
        }
        return shortestResult.substring(1, shortestResult.length() - 2) +
                longestResult.substring(1, longestResult.length() - 2);
    }
}

标签: javaregexloopssorting

解决方案


即使没有调试器,您面临的问题也非常简单且易于调试。您的代码有一个主方法,可以由您选择的 IDE 运行以进行调试。我建议你看看如何调试你的代码,以帮助你以后解决更复杂的问题。


仅通过查看代码,我就发现了一个概念性问题。您正在创建一个在 while 循环中部分填充的字符串数组。null除非您为它们分配值,否则所有这些元素都是。所以第一个i元素将有一个 String 集,所有其他元素都是null. 之后,您将遍历整个数组 ( k < arr.length)。问题出现在这个 for 循环中,因为您尝试调用length()-elements null。将从第 -th 元素开始arr[k].length()抛出NullPointerException 。i同样的问题稍后再次发生word.length()。运行您的代码确认上述内容:

线程“主”java.lang.NullPointerException 中的异常

if (arr[k].length() > longest){. 解决此问题的一种方法(在许多方法中)是仅遍历数组中实际包含值 ( ) 的元素,如下所示0 .. (i-1)for (int k = 0; k < (i - 1); k++){这同样适用于第二个 for 循环。


更好的解决方案是使用String#split()which 接受一个正则表达式,定义在哪里拆分输入并直接返回一个数组。这个数组没有空元素,只包含足够的元素来保存结果。您可以用它替换您的 while 循环,并拥有一个适用于 100 多个单词且没有硬编码限制的解决方案。如果你使用它,你不需要修改你的循环。

String[] arr = input.split("[\\p{Punct}\\s]+");

补充说明:

  • 使用 aStringJoiner而不是 aStringBuilder有一种干净的方式来获取逗号分隔的值:StringJoiner longestWords = new StringJoiner(", ")然后使用longestWords.add(word)并最终构造结果"Max: " + longestWords
  • 您需要找到一种在结果中不包含重复值的方法。

推荐阅读