3

我为学校编写了这个程序,它几乎可以工作,但是有一个问题。该程序的目标是获取输入的字符串,并从输入中以元音开头的每个单词创建一个新字符串。

例子:

输入:It is a hot and humid day.
输出:Itisaand.

这是驱动程序:

public class Driver {

public static void main(String[] args) {

    Scanner console = new Scanner(System.in);
    System.out.print("Input: ");
    String input = console.nextLine();
    Class strings = new Class(input);
    int beg=0;
    for(int j=0;j<input.length();j++)
    {
        if(strings.isVowel(j)&&(j==0||input.charAt(j-1)==' '))
            beg=j;
        else if(strings.endWord(j)&&(beg==0||input.charAt(beg-1)==' '))
        {
            strings.findWord(beg, j);       
        }
    }
    System.out.print("Output: ");
    strings.printAnswer();
}

}

这是课程:

public class Class {

    String input="",answer="";
    public Class(String input1)
    {
        input = input1;
    }


    public boolean isVowel(int loc)
    {
        return (input.charAt(loc)=='U'||input.charAt(loc)=='O'||input.charAt(loc)=='I'||input.charAt(loc)=='E'||input.charAt(loc)=='A'||input.charAt(loc)=='a'||input.charAt(loc)=='e'||input.charAt(loc)=='i'||input.charAt(loc)=='o'||input.charAt(loc)=='u');
    }
    public boolean endWord(int loc)
    {
        return (input.charAt(loc)==' '||input.charAt(loc)=='.'||input.charAt(loc)=='?'||input.charAt(loc)=='!');
    }
    public void findWord(int beg,int end)
    {
        answer = answer+(input.substring(beg,end));
    }
    public void printAnswer()
    {
        System.out.println(answer+".");
    }
}

使用此代码,我得到输出:
Itisaa hotandand humidand humid summerand humid summer day.

通过删除这段代码:

&& (j == 0 || input.charAt(j-1) == ' ')

我得到了正确的输出,但如果输入的单词中有多个元音,它就不起作用。

例如:

输入:Apples and bananas.
输出:and.

有人可以解释一下:
a)为什么代码会打印出以辅音开头的单词,
b)我该如何解决它。

另外,我编写的类中的方法不能更改。

4

7 回答 7

4

这是一个更好的算法:

  1. 将输入拆分为单词数组
  2. 遍历每个单词
  3. 如果单词以元音开头,则将其附加到输出

拆分输入的最简单方法是使用String.split().

这是一个简单的实现:

public static void main(String[] args) {
    Scanner console = new Scanner(System.in);
    String input = console.nextLine();
    String[] words = input.split(" ");
    StringBuilder output = new StringBuilder();
    for (String s : words) {
        if (startsWithVowel(s)) {
            output.append(s);
        }
        else {
            output.append(getPunc(s));
        }
    }
    System.out.println(output.toString());
}

public static boolean startsWithVowel(String s) {
     char[] vowels = { 'a', 'e', 'i', 'o', 'u' };
     char firstChar = s.toLowerCase().charAt(0);
     for (char v : vowels) {
         if (v == firstChar) {
             return true;
         }
     }
     return false;
 }

public static String getPunc(String s) {
    if (s.matches(".*[.,:;!?]$")) {
        int len = s.length();
        return s.substring(len - 1, len);
    }
    return "";
}
于 2013-10-19T16:24:23.190 回答
2

您的代码的问题是:它多次计算同一个单词,因为它会找到元音并重新开始单词搜索过程。

下面是我解决问题的方法,同时仍然保持你的代码看起来相对相同:我改变的只是你的循环

for(int i=0;i<input.length();i++)
    {
        if(strings.isVowel(i) &&(i==0 || strings.endWord(i-1))){ 
            beg = i;
            for(int j = i; j < input.length();j++) //look for end of word
            {
                if(strings.endWord(j)) //word has ended
                {
                    i = j; //start from end of last word
                    strings.findWord(beg, j);         
                    break; //word done, end word search
                }
            }
        }
    }

如上所述,有更好的方法来解决这个问题,并且设置中有一些非常明显的缺陷,但你想要一个答案,所以你去

于 2013-10-19T16:32:20.343 回答
1

通常我会建议你在哪里修复你的代码,但这里似乎有很多不好的代码实践。

  • 批量连接应适用于 StringBuilder。
  • 永远不要叫班级Class
  • 条件太长,可以通过静态元音字符串缩短并应用 .contains(Your-Char)
  • 出于可读性目的所需的空格、缩进。
  • 解决此问题的不同方法可能会提高您的效率。

另一种方法将是Split空格代码并循环遍历结果数组以开始元音字母,然后将它们附加到结果字符串。

于 2013-10-19T16:24:08.563 回答
1

我认为最好的方法是拆分输入,然后检查每个单词是否以元音开头。

public static void main(String[] args)
{

  Scanner console = new Scanner(System.in);
  System.out.print("Input: ");
  String str = console.next();

  String[] input = str.split(" ");

  StringBuilder s = new StringBuilder();

  String test;

  for (int i = 0; i < input.length; i++)
  {
      test = input[i];

      if (test.charAt(0) == 'U' || test.charAt(0) == 'O'
          || test.charAt(0) == 'I' || test.charAt(0) == 'E'
          || test.charAt(0) == 'A' || test.charAt(0) == 'a'
          || test.charAt(0) == 'e' || test.charAt(0) == 'i'
          || test.charAt(0) == 'o' || test.charAt(0) == 'u')
     {
           s.append(input[i]);

     }

   }
   System.out.println(s);

}
于 2013-10-19T16:38:32.427 回答
1

一个更好的可读性和更易维护的版本做你想要的:

public static String buildWeirdSentence(String input) {
    Pattern vowels = Pattern.compile("A|E|I|O|U|a|e|i|o|u");
    Pattern signs = Pattern.compile("!|\\.|,|:|;|\\?");
    StringBuilder builder = new StringBuilder();

    for (String word : input.split(" ")) {
        String firstCharacter = word.substring(0, 1);
        Matcher vowelMatcher = vowels.matcher(firstCharacter);
        if (vowelMatcher.matches()) {
            builder.append(word);
        } else {
            // we still might want the last character because it might be a sign
            int wordLength = word.length();
            String lastCharacter = word.substring(wordLength - 1, wordLength);
            Matcher signMatcher = signs.matcher(lastCharacter);
            if (signMatcher.matches()) {
                builder.append(lastCharacter);
            }
        }
    }

    return builder.toString();
}

正在使用:

public static void main(String[] args) {
    System.out.println(buildWeirdSentence("It is a hot and humid day.")); // Itisaand.
}
于 2013-10-19T16:48:21.757 回答
1

beg您的代码的问题在于,当单词具有更多元音时,您会覆盖第一个。例如,使用Applesbeg go to0并且在您可以调用findWord捕获它之前,它会被覆盖,4它是 . 的索引e。这就是搞砸你的算法的原因。

您需要注意,在您调用之前,您已经找到了一个元音finWord,因为您可以添加一个布尔变量haveFirstVowel并在第一次找到一个时将其设置为 true 并且只有在没有时才进入将该变量设置为 true 的分支'还没有设置它。调用后将findWord其设置回 false。

接下来,您需要检测单词的开头,否则例如oofhot可能会错误地表示第一个元音。

Class strings = new Class(input);
int beg = 0;
boolean haveFirstVowel = false;
for (int j = 0; j < input.length(); j++) {
    boolean startOfWord = (beg == 0 || input.charAt(j - 1) == ' ');
    if (startOfWord && ! haveFirstVowel && strings.isVowel(j)) {
        beg = j;
        haveFirstVowel = true;
    }
    else if (strings.endWord(j) && haveFirstVowel) {
        strings.findWord(beg, j);
        haveFirstVowel = false;
    }
}
System.out.print("Output: ");
strings.printAnswer();
于 2013-10-19T17:21:35.487 回答
0

我认为总体而言该算法还不错。只是实现肯定可以更好。

关于这个问题,你只需要在以下情况下调用findWord ():

  1. 你找到了一个元音,并且
  2. 你已经到了一个单词的结尾。

您的代码忘记了规则 (1),因此 main() 可以修改如下:

Scanner console = new Scanner(System.in);
System.out.print("Input: ");
String input = console.nextLine();
Class strings = new Class(input);
int beg = 0;
boolean foundVowel = false; // added a flag indicating whether a vowel has been found or not
for (int j = 0; j < input.length(); j++) {
    if (strings.isVowel(j) && (j == 0 || input.charAt(j - 1) == ' ')) {
        beg = j;
        foundVowel = true;
    } else if (strings.endWord(j) && (beg == 0 || input.charAt(beg - 1) == ' ')) {
        if (foundVowel) { // only call findWord() when you have found a vowel and reached the end of a word
            strings.findWord(beg, j);
            foundVowel = false; // remember to reset the flag
        }
    }
}
System.out.print("Output: ");
strings.printAnswer();
于 2013-10-19T16:52:04.213 回答